// Find a variable by name. // AP_Param * AP_Param::find(const char *name, enum ap_var_type *ptype) { for (uint8_t i=0; i<_num_vars; i++) { uint8_t type = PGM_UINT8(&_var_info[i].type); if (type == AP_PARAM_GROUP) { uint8_t len = strnlen_P(_var_info[i].name, AP_MAX_NAME_SIZE); if (strncmp_P(name, _var_info[i].name, len) != 0) { continue; } const struct GroupInfo *group_info = (const struct GroupInfo *)PGM_POINTER(&_var_info[i].group_info); AP_Param *ap = find_group(name + len, i, group_info, ptype); if (ap != NULL) { return ap; } // we continue looking as we want to allow top level // parameter to have the same prefix name as group // parameters, for example CAM_P_G } else if (strcasecmp_P(name, _var_info[i].name) == 0) { *ptype = (enum ap_var_type)type; return (AP_Param *)PGM_POINTER(&_var_info[i].ptr); } } return NULL; }
// Find a variable by name in a group AP_Param * AP_Param::find_group(const char *name, uint8_t vindex, const struct GroupInfo *group_info, enum ap_var_type *ptype) { uint8_t type; for (uint8_t i=0; (type=PGM_UINT8(&group_info[i].type)) != AP_PARAM_NONE; i++) { #ifdef AP_NESTED_GROUPS_ENABLED if (type == AP_PARAM_GROUP) { const struct GroupInfo *ginfo = (const struct GroupInfo *)PGM_POINTER(&group_info[i].group_info); AP_Param *ap = find_group(name, vindex, ginfo, ptype); if (ap != NULL) { return ap; } } else #endif // AP_NESTED_GROUPS_ENABLED if (strcasecmp_P(name, group_info[i].name) == 0) { uintptr_t p = PGM_POINTER(&_var_info[vindex].ptr); *ptype = (enum ap_var_type)type; return (AP_Param *)(p + PGM_POINTER(&group_info[i].offset)); } else if (type == AP_PARAM_VECTOR3F) { // special case for finding Vector3f elements uint8_t suffix_len = strnlen_P(group_info[i].name, AP_MAX_NAME_SIZE); if (strncmp_P(name, group_info[i].name, suffix_len) == 0 && name[suffix_len] == '_' && (name[suffix_len+1] == 'X' || name[suffix_len+1] == 'Y' || name[suffix_len+1] == 'Z')) { uintptr_t p = PGM_POINTER(&_var_info[vindex].ptr); AP_Float *v = (AP_Float *)(p + PGM_POINTER(&group_info[i].offset)); *ptype = AP_PARAM_FLOAT; switch (name[suffix_len+1]) { case 'X': return (AP_Float *)&v[0]; case 'Y': return (AP_Float *)&v[1]; case 'Z': return (AP_Float *)&v[2]; } } } } return NULL; }
void BetterStream::_vprintf (unsigned char in_progmem, const char *fmt, va_list ap) { unsigned char c; /* holds a char from the format string */ unsigned char flags; unsigned char width; unsigned char prec; unsigned char buf[11]; /* size for -1 in octal, without '\0' */ for (;;) { /* * Process non-format characters */ for (;;) { c = GETBYTE (in_progmem, 1, fmt); if (!c) return; if (c == '%') { c = GETBYTE (in_progmem, 1, fmt); if (c != '%') break; } /* emit cr before lf to make most terminals happy */ if (c == '\n') write('\r'); write(c); } flags = 0; width = 0; prec = 0; /* * Process format adjustment characters, precision, width. */ do { if (flags < FL_WIDTH) { switch (c) { case '0': flags |= FL_ZFILL; continue; case '+': flags |= FL_PLUS; /* FALLTHROUGH */ case ' ': flags |= FL_SPACE; continue; case '-': flags |= FL_LPAD; continue; case '#': flags |= FL_ALT; continue; } } if (flags < FL_LONG) { if (c >= '0' && c <= '9') { c -= '0'; if (flags & FL_PREC) { prec = 10*prec + c; continue; } width = 10*width + c; flags |= FL_WIDTH; continue; } if (c == '.') { if (flags & FL_PREC) return; flags |= FL_PREC; continue; } if (c == 'l') { flags |= FL_LONG; continue; } if (c == 'h') continue; } break; } while ( (c = GETBYTE (in_progmem, 1, fmt)) != 0); /* * Handle floating-point formats E, F, G, e, f, g. */ if (c >= 'E' && c <= 'G') { flags |= FL_FLTUPP; c += 'e' - 'E'; goto flt_oper; } else if (c >= 'e' && c <= 'g') { int exp; /* exponent of master decimal digit */ int n; unsigned char vtype; /* result of float value parse */ unsigned char sign; /* sign character (or 0) */ unsigned char ndigs; flags &= ~FL_FLTUPP; flt_oper: if (!(flags & FL_PREC)) prec = 6; flags &= ~(FL_FLTEXP | FL_FLTFIX); if (c == 'e') flags |= FL_FLTEXP; else if (c == 'f') flags |= FL_FLTFIX; else if (prec > 0) prec -= 1; if (flags & FL_FLTFIX) { vtype = 7; /* 'prec' arg for 'ftoa_engine' */ ndigs = prec < 60 ? prec + 1 : 60; } else { if (prec > 7) prec = 7; vtype = prec; ndigs = 0; } exp = __ftoa_engine (va_arg(ap,double), (char *)buf, vtype, ndigs); vtype = buf[0]; sign = 0; if ((vtype & FTOA_MINUS) && !(vtype & FTOA_NAN)) sign = '-'; else if (flags & FL_PLUS) sign = '+'; else if (flags & FL_SPACE) sign = ' '; if (vtype & (FTOA_NAN | FTOA_INF)) { const char *p; ndigs = sign ? 4 : 3; if (width > ndigs) { width -= ndigs; if (!(flags & FL_LPAD)) { do { write(' '); } while (--width); } } else { width = 0; } if (sign) write(sign); p = PSTR("inf"); if (vtype & FTOA_NAN) p = PSTR("nan"); while ( (ndigs = pgm_read_byte((const prog_char *)p)) != 0) { if (flags & FL_FLTUPP) ndigs += 'I' - 'i'; write(ndigs); p++; } goto tail; } /* Output format adjustment, number of decimal digits in buf[] */ if (flags & FL_FLTFIX) { ndigs += exp; if ((vtype & FTOA_CARRY) && buf[1] == '1') ndigs -= 1; if ((signed char)ndigs < 1) ndigs = 1; else if (ndigs > 8) ndigs = 8; } else if (!(flags & FL_FLTEXP)) { /* 'g(G)' format */ if (exp <= prec && exp >= -4) flags |= FL_FLTFIX; while (prec && buf[1+prec] == '0') prec--; if (flags & FL_FLTFIX) { ndigs = prec + 1; /* number of digits in buf */ prec = prec > exp ? prec - exp : 0; /* fractional part length */ } } /* Conversion result length, width := free space length */ if (flags & FL_FLTFIX) n = (exp>0 ? exp+1 : 1); else n = 5; /* 1e+00 */ if (sign) n += 1; if (prec) n += prec + 1; width = width > n ? width - n : 0; /* Output before first digit */ if (!(flags & (FL_LPAD | FL_ZFILL))) { while (width) { write(' '); width--; } } if (sign) write(sign); if (!(flags & FL_LPAD)) { while (width) { write('0'); width--; } } if (flags & FL_FLTFIX) { /* 'f' format */ n = exp > 0 ? exp : 0; /* exponent of left digit */ do { if (n == -1) write('.'); flags = (n <= exp && n > exp - ndigs) ? buf[exp - n + 1] : '0'; if (--n < -prec) break; write(flags); } while (1); if (n == exp && (buf[1] > '5' || (buf[1] == '5' && !(vtype & FTOA_CARRY))) ) { flags = '1'; } write(flags); } else { /* 'e(E)' format */ /* mantissa */ if (buf[1] != '1') vtype &= ~FTOA_CARRY; write(buf[1]); if (prec) { write('.'); sign = 2; do { write(buf[sign++]); } while (--prec); } /* exponent */ write(flags & FL_FLTUPP ? 'E' : 'e'); ndigs = '+'; if (exp < 0 || (exp == 0 && (vtype & FTOA_CARRY) != 0)) { exp = -exp; ndigs = '-'; } write(ndigs); for (ndigs = '0'; exp >= 10; exp -= 10) ndigs += 1; write(ndigs); write('0' + exp); } goto tail; } /* * Handle string formats c, s, S. */ { const char * pnt; size_t size; switch (c) { case 'c': buf[0] = va_arg (ap, int); pnt = (char *)buf; size = 1; goto no_pgmstring; case 's': pnt = va_arg (ap, char *); size = strnlen (pnt, (flags & FL_PREC) ? prec : ~0); no_pgmstring: flags &= ~FL_PGMSTRING; goto str_lpad; case 'S': // pgmstring: // not yet used pnt = va_arg (ap, char *); size = strnlen_P (pnt, (flags & FL_PREC) ? prec : ~0); flags |= FL_PGMSTRING; str_lpad: if (!(flags & FL_LPAD)) { while (size < width) { write(' '); width--; } } while (size) { write(GETBYTE (flags, FL_PGMSTRING, pnt)); if (width) width -= 1; size -= 1; } goto tail; } } /* * Handle integer formats variations for d/i, u, o, p, x, X. */ if (c == 'd' || c == 'i') { long x = (flags & FL_LONG) ? va_arg(ap,long) : va_arg(ap,int); flags &= ~(FL_NEGATIVE | FL_ALT); if (x < 0) { x = -x; flags |= FL_NEGATIVE; } c = __ultoa_invert (x, (char *)buf, 10) - (char *)buf; } else {
/** @brief Analyse HTTP request and then services WEB. */ void process_HTTP( SOCKET s, /**< http server socket */ uint8_t * buffer, /**< buffer pointer included http request */ uint16_t length /**< length of http request */ ) { uint8_t * name; uint16_t bytes_read; TickType_t wait_send; FIL source_file; /* File object for the source file */ parse_HTTP_request(pHTTPRequest, buffer); // After analysing request, convert into pHTTPRequest /* method Analyse */ switch (pHTTPRequest->METHOD) { case METHOD_HEAD: case METHOD_GET : case METHOD_POST : name = get_HTTP_URI_name(pHTTPRequest->URI); if (!strcmp((const char *)name, "/")) strcpy((char *)name,"index.htm"); // If URI is "/", respond by index.htm #ifdef WEB_DEBUG if(strlen( (const char *)name) < MAX_INT_STR ) xSerialPrintf_P(PSTR("\r\nPAGE : %s "), name); else xSerialPrint_P(PSTR("\r\nFILENAME TOO LONG")); #endif find_HTTP_URI_type(&pHTTPRequest->TYPE, name); //Check file type (HTML, TEXT, ICO, GIF, JPEG, ZIP are included) // OK now we start to respond to the info we've decoded. /* Open the specified file stored in the SD card FAT32 */ if (f_open(&source_file, (const TCHAR *)name, FA_OPEN_EXISTING | FA_READ)) { // if file open failure memcpy_P( (char *)pHTTPResponse, ERROR_HTML_PAGE, strnlen_P(ERROR_HTML_PAGE, FILE_BUFFER_SIZE) ); #ifdef WEB_DEBUG xSerialPrint_P(PSTR("HTTP Unknown file or page.\r\n")); xSerialPrintf_P(PSTR("HTTP Response...\r\n%s\r\nResponse Size: %u \r\n"), pHTTPResponse, strlen_P(ERROR_HTML_PAGE)); #endif send( s, (const uint8_t*)pHTTPResponse, strlen_P(ERROR_HTML_PAGE)); } else { // if file open success make_HTTP_response_header( pHTTPResponse, pHTTPRequest->TYPE, source_file.fsize); #ifdef WEB_DEBUG xSerialPrintf_P(PSTR("HTTP Opened file: %s Source Size: %u \r\n"), name, source_file.fsize); xSerialPrintf_P(PSTR("HTTP Response Header...\r\n%s\r\nResponse Header Size: %u \r\n"), pHTTPResponse, strlen((char*)pHTTPResponse )); #endif send(s, (const uint8_t*)pHTTPResponse, strlen((char*)pHTTPResponse )); wait_send = xTaskGetTickCount(); while(getSn_TX_FSR(s)!= WIZCHIP_getTxMAX(s)) { if( (xTaskGetTickCount() - wait_send) > (WEBSERVER_SOCKET_TIMEOUT / portTICK_PERIOD_MS) ) // wait up to 1.5 Sec { #ifdef WEB_DEBUG xSerialPrint_P(PSTR("HTTP Response head send fail\r\n")); #endif break; } vTaskDelay( 0 ); // yield until next tick. } for (;;) { if ( f_read(&source_file, pHTTPResponse, (sizeof(uint8_t)*(FILE_BUFFER_SIZE) ), &bytes_read) || bytes_read == 0 ) break; // read error or reached end of file if(pHTTPRequest->TYPE == PTYPE_HTML) // if we've got a html document, there might be some system variables to set { *(pHTTPResponse + bytes_read + 1) = 0; // make the buffer a string, null terminated bytes_read = replace_sys_env_value(pHTTPResponse, bytes_read); // Replace html system environment value to real value } if (send(s, (const uint8_t*)pHTTPResponse, bytes_read) != bytes_read) break; // TCP/IP send error wait_send = xTaskGetTickCount(); while(getSn_TX_FSR(s)!= WIZCHIP_getTxMAX(s)) { if( (xTaskGetTickCount() - wait_send) > (WEBSERVER_SOCKET_TIMEOUT / portTICK_PERIOD_MS) ) // wait up to 1.5 Sec { #ifdef WEB_DEBUG xSerialPrint_P(PSTR("HTTP Response body send fail\r\n")); #endif break; } vTaskDelay( 0 ); // yield until next tick. } } f_close(&source_file); eeprom_busy_wait(); eeprom_update_dword( &pagesServed, eeprom_read_dword(&pagesServed) +1 ); } break; case METHOD_ERR : memcpy_P( (char *)pHTTPResponse, ERROR_REQUEST_PAGE, strnlen_P(ERROR_REQUEST_PAGE, FILE_BUFFER_SIZE) ); #ifdef WEB_DEBUG xSerialPrint_P(PSTR("HTTP Method Error.\r\n")); xSerialPrintf_P(PSTR("HTTP Response...\r\n%s\r\nResponse Size: %u \r\n"), pHTTPResponse, strlen_P(ERROR_REQUEST_PAGE)); #endif send( s, (const uint8_t*)pHTTPResponse, strlen_P(ERROR_REQUEST_PAGE)); break; default : break; } }