LOCAL char * ICACHE_FLASH_ATTR readUIntField(struct jsonparse_state *jparser, ALLOWED_FIELDS field, uint32_t *out, ALLOWED_FIELDS fields, ALLOWED_FIELDS *readedfields, unsigned int x) {
	if((fields & field) == 0)
		return UNEXPECTED;
	int value;
	jsonparse_next(jparser);
	if(jsonparse_next(jparser) != JSON_TYPE_ERROR) {
		if(x && jparser->vlen == 1 && jparser->json[jparser->vstart] == 'x' && (field & AF_CS)) {
			*out = x;
			*readedfields |= field;
			return 0;
		}
		const int res = strToUInt(&jparser->json[jparser->vstart], &value);
		if(!res)
			return NONINTEGER;
		*out = value;
		*readedfields |= field;
	}
	return 0;
}
char * ICACHE_FLASH_ATTR parse_params_pins_set(const char *params, unsigned int paramslen, gpio_command_params *out, unsigned int all, unsigned int timeout, ALLOWED_FIELDS fields, ALLOWED_FIELDS *readedfields) {
	struct jsonparse_state jparser;
	if(paramslen)
		jsonparse_setup(&jparser, params, paramslen);
	else if(fields)
		return "No parameters specified";
	int type;
	int pinnum;
	unsigned int pins_found = 0;
	unsigned int pinmask;
	*readedfields = 0;
	load_defaults(out, timeout);
	while (jparser.pos < jparser.len) {
		type = jsonparse_next(&jparser);
		if (type == JSON_TYPE_PAIR_NAME) {
			if(strcmp_value(&jparser, "mode") == 0) {
				if((fields & AF_UARTMODE) == 0 && (fields & AF_SPIMODE) == 0)
					return UNEXPECTED;
				jsonparse_next(&jparser);
				if(jsonparse_next(&jparser) != JSON_TYPE_ERROR) {
					int val;
					if(strcmp_value(&jparser, "disable") == 0 && (fields & AF_UARTMODE)) {
						*readedfields |= AF_UARTMODE;
						out->uart_speed = 0;
						continue;
					}
					int res = strToUInt(&jparser.json[jparser.vstart], &val);
					if(!res)
						return "Wrong mode integer value";
					if(fields & AF_UARTMODE) {
						*readedfields |= AF_UARTMODE;
						out->uart_speed = val;
						if(res < jparser.vlen && jparser.json[jparser.vstart + res] == ' ') {
							while(res < jparser.vlen && jparser.json[jparser.vstart + res] == ' ')
								res++;
							if(res + 3 == jparser.vlen) {
								const unsigned char b =  jparser.json[jparser.vstart + res] - '0';
								const unsigned char p =  jparser.json[jparser.vstart + res + 1];
								const unsigned char s =  jparser.json[jparser.vstart + res + 2] - '0';
								if(b < 10 && s < 10) {
									out->uart_bits = b;
									out->uart_partity = p;
									out->uart_stopbits = s;
								} else {
									return "Wrong mode framing";
								}
							}
						}
					}
					if(fields & AF_SPIMODE) {
						*readedfields |= AF_SPIMODE;
						out->spi_mode = val;
					}
				}
				continue;
			} else if(strcmp_value(&jparser, "count") == 0) {
				char * res = readUIntField(&jparser, AF_COUNT, &out->count, fields, readedfields, 0);
				if(res)
					return res;
				continue;
			} else if(strcmp_value(&jparser, "timeout") == 0) {
				char * res = readUIntField(&jparser, AF_TIMEOUT, &out->timeout, fields, readedfields, 0);
				if(res)
					return res;
				continue;
			} else if(strcmp_value(&jparser, "frequency") == 0) {
				if((fields & AF_PERIOD) == 0)
					return UNEXPECTED;
				float frequncy;
				jsonparse_next(&jparser);
				if(jsonparse_next(&jparser) != JSON_TYPE_ERROR) {
					const int res = strToFloat(&jparser.json[jparser.vstart], &frequncy);
					if(!res)
						return "Wrong frequency float value";
					if(frequncy < 0.000499999f)
						out->periodus = 2000004000;
					else
						out->periodus = 1000000.0f / frequncy;
					*readedfields |= AF_PERIOD;
				}
				continue;
			} else if(strcmp_value(&jparser, "address") == 0) {
				if((fields & AF_ADDRESS) == 0)
					return UNEXPECTED;
				jsonparse_next(&jparser);
				if(jsonparse_next(&jparser) != JSON_TYPE_ERROR) {
					char c;
					int p;
					if(jparser.json[jparser.vstart] == '0' && jparser.json[jparser.vstart + 1] == 'x')
						p = 2;
					else
						p = 0;
					const int res = hexToByte(&jparser.json[jparser.vstart + p], &c);
					if(res != (jparser.vlen - p))
						return "Address is wrong";
					out->address = c;
					*readedfields |= AF_ADDRESS;
				}
				continue;
			} else if(strcmp_value(&jparser, "SDA") == 0) {
				char * res = readUIntField(&jparser, AF_SDA, &out->SDA, fields, readedfields, 0);
				if(res)
					return res;
				continue;
			} else if(strcmp_value(&jparser, "SCL") == 0) {
				char * res = readUIntField(&jparser, AF_SCL, &out->SCL, fields, readedfields, 0);
				if(res)
					return res;
				continue;
			} else if(strcmp_value(&jparser, "CS") == 0) {
				char * res = readUIntField(&jparser, AF_CS, &out->CS, fields, readedfields,  ~(uint32_t)0U);
				if(res)
					return res;
				continue;
			} else if(strcmp_value(&jparser, "pin") == 0) {
				char * res = readUIntField(&jparser, AF_PIN, &out->pin, fields, readedfields, 0);
				if(res)
					return res;
				continue;
			} else if(strcmp_value(&jparser, "data") == 0) {
				if((fields & AF_DATA) == 0 || out->data_len)
					return UNEXPECTED;
				jsonparse_next(&jparser);
				if(jsonparse_next(&jparser) != JSON_TYPE_ERROR) {
					out->data_len = dhdata_decode(&jparser.json[jparser.vstart], jparser.vlen, out->data, sizeof(out->data));
					if(out->data_len == 0)
						return "Data is broken";
					*readedfields |= AF_DATA;
				}
				continue;
			}  else if(strcmp_value(&jparser, "text") == 0) {
				if((fields & AF_TEXT_DATA) == 0 || out->data_len)
					return UNEXPECTED;
				jsonparse_next(&jparser);
				if(jsonparse_next(&jparser) != JSON_TYPE_ERROR) {
					if (jparser.vlen > sizeof(out->data) - 1)
						return "Text is too long";
					os_memcpy(out->data, &jparser.json[jparser.vstart], jparser.vlen);
					out->data[jparser.vlen] = 0;
					out->data_len = jparser.vlen;
					*readedfields |= AF_TEXT_DATA;
				}
				continue;
			} else if(strcmp_value(&jparser, "all") == 0) {
				if(pins_found)
					return "Wrong argument";
				pins_found = ~(unsigned int)0;
				pinmask = all;
				pinnum = -1;
			} else {
				const int res = strToUInt(&jparser.json[jparser.vstart], &pinnum);
				if(!res || pinnum < 0 || pinnum > DHGPIO_MAXGPIONUM || (pins_found & (1 << pinnum)))
					return "Wrong argument";
				pins_found |= (1 << pinnum);
				pinmask =  (1 << pinnum);
			}
			jsonparse_next(&jparser);
			if(jsonparse_next(&jparser) != JSON_TYPE_ERROR) {
				if(strcmp_value(&jparser, "x") == 0)
					continue;
				else if(strcmp_value(&jparser, "init") == 0) {
					if((fields & AF_INIT) == 0)
						return UNEXPECTED;
					out->pins_to_init |= pinmask;
					*readedfields |= AF_INIT;
				} else if(strcmp_value(&jparser, "pullup") == 0) {
					if((fields & AF_PULLUP) == 0)
						return UNEXPECTED;
					out->pins_to_pullup |= pinmask;
					*readedfields |= AF_PULLUP;
				} else if(strcmp_value(&jparser, "nopull") == 0) {
					if((fields & AF_NOPULLUP) == 0)
						return UNEXPECTED;
					out->pins_to_nopull |= pinmask;
					*readedfields |= AF_NOPULLUP;
				} else if(strcmp_value(&jparser, "disable") == 0) {
					if((fields & AF_VALUES) == 0 && (fields & AF_DISABLE) == 0) {
						return UNEXPECTED;
					}
					if (fields & AF_VALUES) {
						int i;
						if(pinnum > 0 )
							out->pin_value[pinnum] = 0;
						else for(i = 0; i <= DHGPIO_MAXGPIONUM; i++)
							out->pin_value[i] = 0;
						out->pin_value_readed |= pinmask;
						*readedfields |= AF_VALUES;
					}
					if(fields & AF_DISABLE) {
						out->pins_to_disable |= pinmask;
						*readedfields |= AF_DISABLE;
					}
				} else if(strcmp_value(&jparser, "rising") == 0) {
					if((fields & AF_RISING)== 0)
						return UNEXPECTED;
					out->pins_to_rising |= pinmask;
					*readedfields |= AF_RISING;
				} else if(strcmp_value(&jparser, "falling") == 0) {
					if((fields & AF_FALLING) == 0)
						return UNEXPECTED;
					out->pins_to_falling |= pinmask;
					*readedfields |= AF_FALLING;
				} else if(strcmp_value(&jparser, "both") == 0) {
					if((fields & AF_BOTH) == 0)
						return UNEXPECTED;
					out->pins_to_both |= pinmask;
					*readedfields |= AF_BOTH;
				} else if(strcmp_value(&jparser, "read") == 0) {
					if((fields & AF_READ) == 0)
						return UNEXPECTED;
					out->pins_to_read |= pinmask;
					*readedfields |= AF_READ;
				} else if(strcmp_value(&jparser, "presence") == 0) {
					if((fields & AF_PRESENCE) == 0)
						return UNEXPECTED;
					out->pins_to_presence |= pinmask;
					*readedfields |= AF_PRESENCE;
				} else if((fields & AF_VALUES)) { // BE CAREFULL, all digits values have to be under this if
					int value, i;
					if(!strToUInt(&jparser.json[jparser.vstart], &value))
						return NONINTEGER;
					if(pinnum > 0 )
						out->pin_value[pinnum] = value;
					else for(i = 0; i <= DHGPIO_MAXGPIONUM; i++)
						out->pin_value[i] = value;
					out->pin_value_readed |= pinmask;
					*readedfields |= AF_VALUES;
					if(value == 1 && (fields & AF_SET)) {
						out->pins_to_set |= pinmask;
						*readedfields |= AF_SET;
					} else if(value == 0 && (fields & AF_CLEAR)) {
						out->pins_to_clear |= pinmask;
						*readedfields |= AF_CLEAR;
					}
				} else if(strcmp_value(&jparser, "1") == 0) {
					if((fields & AF_SET) == 0)
						return UNEXPECTED;
					out->pins_to_set |= pinmask;
					*readedfields |= AF_SET;
				} else if(strcmp_value(&jparser, "0") == 0) {
					if((fields & AF_CLEAR) == 0)
						return UNEXPECTED;
					out->pins_to_clear |= pinmask;
					*readedfields |= AF_CLEAR;
				} else {
					return "Unsupported action";
				}
			}
		} else if(type == JSON_TYPE_ERROR) {
			return "Broken json";
		}
	}
	return NULL;
}
LOCAL void ICACHE_FLASH_ATTR receive_post(const char *data, unsigned short len, char * internal, unsigned int internalsize) {
	const unsigned int POST_BUF_SIZE = 2048;
	const char content_length[] = "Content-Length:";
	const char sp[] = "\r\n\r\n";
	if(mPostBuf == 0) {
		mPostBuf = (char*)os_malloc(POST_BUF_SIZE);
		if(mPostBuf == 0) {
			check_send_res(espconn_send(mCurrentPost, internal, internalsize));
			mCurrentPost = 0;
			return;
		}
	}
	if(len > POST_BUF_SIZE - mPostBufPos) {
		check_send_res(espconn_send(mCurrentPost, internal, internalsize));
		mCurrentPost = 0;
		return;
	}
	os_memcpy(&mPostBuf[mPostBufPos], data, len);
	mPostBufPos += len;
	const int to = (int)mPostBufPos - sizeof(content_length) + 1;
	int i;
	unsigned int cont_len;
	for(i = 0; i < to; i++) {
		if(os_strncmp(&mPostBuf[i], content_length, sizeof(content_length) - 1) == 0) {
			i += sizeof(content_length) - 1;
			while(mPostBuf[i] == ' ')
				i++;
			if(strToUInt(&mPostBuf[i], &cont_len)) {
				for(; i < mPostBufPos; i++) {
					if(os_strncmp(&mPostBuf[i], sp, sizeof(sp) - 1) == 0) {
						i += sizeof(sp) - 1;
						if(cont_len <= mPostBufPos - i) {
							dhdebug("POST len %u/%u", cont_len, mPostBufPos - i);
							char *res = dhap_post_parse(&mPostBuf[i], mPostBufPos - i);
							unsigned int rlen;
							if(res) {
								res = dhap_pages_error(res, &rlen);
							} else {
								if(dhsettings_commit() == 0) {
									res = internal;
									rlen = internalsize;
								} else {
									res = dhap_pages_ok(&rlen);
									if(res == 0) {
										dhdebug("Generate OK page fail");
										res = internal;
										rlen = internalsize;
									} else {
										dhdebug("Configuration was written. Will be rebooted in %d ms", RECONFIGURE_DELAY_MS);
										os_timer_disarm(&mReconfigureTimer);
										os_timer_setfn(&mReconfigureTimer, (os_timer_func_t *)system_reconfigure, NULL);
										os_timer_arm(&mReconfigureTimer, RECONFIGURE_DELAY_MS, 0);
										mConfigured = 1;
									}
								}
							}
							dhdebug("Parse post, send result %u bytes", rlen);
							check_send_res(espconn_send(mCurrentPost, res, rlen));
							mCurrentPost = 0;
						}
						return;
					}
				}
			}
			return;
		}
	}
}