Сравнение строк в switch

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

Я не нашол ничего лучше как crc32 вычислять для каждой строки и сравнивать с подсчитанными заранее...

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

вот сами строки с расчетом их crc32 в питоне

>>> import binascii
>>> hex(binascii.crc32("on") & 0xffffffff)
'0x9b629c8L'
>>> binascii.crc32("on")
162933192
>>> binascii.crc32("On")
-1674441366
>>> hex(binascii.crc32("On") & 0xffffffff)
'0x9c320d6aL'
>>> hex(binascii.crc32("ON") & 0xffffffff)
'0xa75c2da2L'
>>> hex(binascii.crc32("1") & 0xffffffff)
'0x83dcefb7L'
>>> hex(binascii.crc32("true") & 0xffffffff)
'0xfdfc4c8dL'
>>> hex(binascii.crc32("off") & 0xffffffff)
'0x2bbc5d43L'
>>> hex(binascii.crc32("Off") & 0xffffffff)
'0x13f11ba3L'
>>> hex(binascii.crc32("0") & 0xffffffff)
'0xf4dbdf21L'
>>> hex(binascii.crc32("false") & 0xffffffff)
'0x2bcd6830L'
>>> hex(binascii.crc32("OFF") & 0xffffffff)
'0xbd1b1fc9L'
>>> hex(binascii.crc32("r1") & 0xffffffff)
'0xd0e09b1L'
>>> hex(binascii.crc32("R1") & 0xffffffff)
'0x988a2d13L'
>>> hex(binascii.crc32("r2") & 0xffffffff)
'0x9407580bL'
>>> hex(binascii.crc32("R2") & 0xffffffff)
'0x1837ca9L'
>>> hex(binascii.crc32("r3") & 0xffffffff)
'0xe300689dL'
>>> hex(binascii.crc32("R3") & 0xffffffff)
'0x76844c3fL'
>>> hex(binascii.crc32("r4") & 0xffffffff)
'0x7d64fd3eL'
>>> hex(binascii.crc32("R4") & 0xffffffff)
'0xe8e0d99cL'
>>> 

Вот код скетча...

/*
  Web Server
 
 A simple web server that shows the value of the analog input pins.
 using an Arduino Wiznet Ethernet shield. 
 
 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13
 * Analog inputs attached to pins A0 through A5 (optional)
 
 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe
 
 */

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
#include <Wire.h>


// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,10,177);
#define R1 22
#define R2 23
#define R3 24
#define R4 25

/* This creates an instance of the webserver.  By specifying a prefix
 * of "", all pages will be at the root of the server. */
#define WEBDUINO_SERVER_HEADER "Server: Test/"
#define WEBDUINO_AUTH_REALM "Analog data"
#define PREFIX ""
#include <WebServer.h>
WebServer webserver(PREFIX, 80);
P(relay_form) = 
"<form>"
"<label for=\"r1\">Relay 1</label><select name=\"r1\"><option>on</option><option>off</option></select><br>"
"<label for=\"r2\">Relay 2</label><select name=\"r2\"><option>on</option><option>off</option></select><br>"
"<label for=\"r3\">Relay 3</label><select name=\"r3\"><option>on</option><option>off</option></select><br>"
"<label for=\"r4\">Relay 4</label><select name=\"r4\"><option>on</option><option>off</option></select><br>"
"<input type=\"submit\" value=\"Set\">"
"</form>"
;

//Init LCD via I2C PCF8264
#include <LiquidCrystal.h>
LiquidCrystal lcd(0x27);

//CRC
static PROGMEM prog_uint32_t crc_table[16] = {
    0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
    0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
    0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
    0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};

unsigned long crc_update(unsigned long crc, byte data)
{
    byte tbl_idx;
    tbl_idx = crc ^ (data >> (0 * 4));
    crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f)) ^ (crc >> 4);
    tbl_idx = crc ^ (data >> (1 * 4));
    crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f)) ^ (crc >> 4);
    return crc;
}

unsigned long crc32(char *s)
{
  unsigned long crc = ~0L;
  while (*s)
    crc = crc_update(crc, *s++);
  crc = ~crc;
  return crc;
}

void defaultCmd(WebServer &server, WebServer::ConnectionType type, char *, bool)
{
  server.httpSuccess();
  if (type != WebServer::HEAD)
  {
    P(helloMsg) = "<h1>Hello, World!</h1><a href=\"private.html\">Private page</a>";
    server.printP(helloMsg);
    server.println("<pre>");
    File dataFile = SD.open("log.txt");
    if (dataFile) {
       while (dataFile.available()) {
           server.print((char)dataFile.read());
       }
       dataFile.close();
    }  
    server.println("</pre>");
  }
}

void privateCmd(WebServer &server, WebServer::ConnectionType type, char *, bool)
{
  /* if the user has requested this page using the following credentials
   * username = user
   * password = user
   * display a page saying "Hello User"
   *
   * the credentials have to be concatenated with a colon like
   * username:password
   * and encoded using Base64 - this should be done outside of your Arduino
   * to be easy on your resources
   *
   * in other words: "dXNlcjp1c2Vy" is the Base64 representation of "user:user"
   *
   * if you need to change the username/password dynamically please search
   * the web for a Base64 library */
  if (server.checkCredentials("dXNlcjp1c2Vy"))
  {
    server.httpSuccess();
    if (type != WebServer::HEAD)
    {
      P(helloMsg) = "<h1>Hello User</h1>";
      server.printP(helloMsg);
      // output the value of each analog input pin
      for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
            int sensorReading = analogRead(analogChannel);
            server.print("analog input ");
            server.print(analogChannel);
            server.print(" is ");
            server.print(sensorReading);
            server.println("<br />");
      }
    }
  }
  /* if the user has requested this page using the following credentials
   * username = admin
   * password = admin
   * display a page saying "Hello Admin"
   *
   * in other words: "YWRtaW46YWRtaW4=" is the Base64 representation of "admin:admin" */
  else if (server.checkCredentials("YWRtaW46YWRtaW4="))
  {
    server.httpSuccess();
    if (type != WebServer::HEAD)
    {
      P(helloMsg) = "<h1>Hello Admin</h1>";
      server.printP(helloMsg);
    }
  }
  else
  {
    /* send a 401 error back causing the web browser to prompt the user for credentials */
    server.httpUnauthorized();
  }
}
void togle(uint8_t pin, char * state){
   switch(crc32(state)){
     case 0x9b629c8:
     case 0x9c320d6a:
     case 0xa75c2da2:
     case 0x83dcefb7:
     case 0xfdfc4c8d:
        digitalWrite(pin, LOW);
        break;
     case 0x2bbc5d43:
     case 0x13f11ba3:
     case 0xbd1b1fc9:
     case 0xf4dbdf21:
     case 0x2bcd6830:
        digitalWrite(pin, HIGH);
        break;
     
   }
}
uint8_t getpin(char * name){
  switch(crc32(name)){
    case 0xd0e09b1:
    case 0x988a2d13:
      return R1;
      break;
    case 0x9407580b:
    case 0x1837ca9:
      return R2;
      break;
    case 0xe300689d:
    case 0x76844c3f:
      return R3;
      break;
    case 0x7d64fd3e:
    case 0xe8e0d99c:
      return R4;
      break;
  }
}
#define NAMELEN 32
#define VALUELEN 32
void relay(WebServer &server, WebServer::ConnectionType type, char * url_tail, bool tail_complete){
  URLPARAM_RESULT rc;
  char name[NAMELEN];
  int  name_len;
  char value[VALUELEN];
  int value_len;
  server.httpSuccess();
  switch(type){
    case WebServer::HEAD:
      return;
      break;
    case WebServer::GET:
      while (strlen(url_tail)){
        rc = server.nextURLparam(&url_tail, name, NAMELEN, value, VALUELEN);
        if (rc != URLPARAM_EOS)
            togle(getpin(name),value);
      }
    default:
      server.printP(relay_form);
  }
}


void setup() {
  pinMode(R1,OUTPUT);
  pinMode(R2,OUTPUT);
  pinMode(R3,OUTPUT);
  pinMode(R4,OUTPUT);
  digitalWrite(R1,HIGH);
  digitalWrite(R2,HIGH);
  digitalWrite(R3,HIGH);
  digitalWrite(R4,HIGH);
  lcd.begin(20,4);
  lcd.begin(20,4);
  lcd.backlight();
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  Serial.print("Initializing SD card...");
  pinMode(4, OUTPUT); 
  if (!SD.begin(4)) {
   Serial.println("failed!");
   lcd.println("SD not found!");
  }else{
   Serial.println("done.");
   sdinfo();
  }

  Serial.println("Initializing Eternet!");
  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // using static ip:
    Ethernet.begin(mac, ip);
  }
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
  lcd.println(Ethernet.localIP());
  webserver.setDefaultCommand(&defaultCmd);
  webserver.addCommand("index.html", &defaultCmd);
  webserver.addCommand("private.html", &privateCmd);
  webserver.addCommand("relay/", &relay);
  webserver.begin();

}

void sdinfo(){
     switch(SD.card.type()) {
      case SD_CARD_TYPE_SD1:
        lcd.print("SD1 ");
      break;
      case SD_CARD_TYPE_SD2:
        lcd.print("SD2 ");
      break;
      case SD_CARD_TYPE_SDHC:
        lcd.print("SHC ");
      break;
      default:
        lcd.print("--- ");
     }
  uint32_t volumesize;
  volumesize = SD.volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= SD.volume.clusterCount();       // we'll have a lot of clusters
  volumesize /= 2; //2k per cluster with 4x512b blocks
  if(volumesize > 1024){
    volumesize /= 1024;
    lcd.print(volumesize);
    lcd.println(" Mb");
  }else{
    lcd.print(volumesize);
    lcd.println(" Kb");
  }
}


void loop() {
  char buff[64];
  int len = 64;

  /* process incoming connections one at a time forever */
  webserver.processConnection(buff, &len);

}

Код работает как и должен, но мне кажется что он кривой и не оптимальный.

Ищу красивое и более оптимальное решение для обработки параметров передаваемых в запросе...

Вообще как проще всего сравнивать строки в switch.

Скетч запускаю на меге, а большой он потому что играюсь с модулями разными )))

P.S. LiquidCrystal использован не стандартный...

MaksMS
Offline
Зарегистрирован: 11.03.2013

Используйте strcasecmp и if

 



if (strcasecmp(строка1,строка2)==0) строки равны !

 

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

Это я знаю... речь идет об конструкциях

switch(string){
	case "Test":
	case "test":
	case "TEST":
		test();
	case "ok":
	case "Ok":
		myFunction();
		break;
	default: 
		otherFunction();
}

Если такое на ифах писать ггг....

можно конечно строки в нижний регистр приводить. Надо какой то более простой CRC использовать для расчета идентификатора...

MaksMS
Offline
Зарегистрирован: 11.03.2013

А зачем switch ?? тем более он вроде больше места занимает чем if.. 

Нормально на if писать,главно оформить отступы кода

NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013

Вобщем вопрос больше теоретический чем практический. Вызывать функцию strcmp я считаю затратнее чем расчитать хэш и сравнивать с хэшами - которые число и памяти меньше жрут.

sva1509
Offline
Зарегистрирован: 07.12.2012

Доброго времени суток !

NeiroN пишет:

Вобщем вопрос больше теоретический чем практический. Вызывать функцию strcmp я считаю затратнее чем расчитать хэш и сравнивать с хэшами - которые число и памяти меньше жрут.

Я думаю Вы ошибаетесь. У Вас 8-ми битный процессор самое быстрое, что он может в данной ситуации делать побайтное сравнение. Обработка хешей - это обработка тех же байтов плюс 32-ух битная математика.

я бы делал так:


char str1[] PROGMEM = "void";
char str1[] PROGMEM = "typedef"; 
char str1[] PROGMEM = "hello";
char *str[] PROGMEM ={str1,str2,str3};

void myFunc(char *a)
{
uint8_t i1;

      i1 = 0;
      while(i1<3) {
          if (!strcmp(a,(char*)pgm_read_word(&(str[i1])))) break;
          i1++;
      }
      switch(i1){
      case 0:
             doVoidFunc();
             break;
      case 1:
             doTypedefFunc();
             break;
      case 2:
             doHelloFunc();
             break;
      case 3:
             doNeNajdenFunc();
             break;
      }
}