LOCAL void network_connect_cb(void *arg) {
	HTTP_REQUEST *request;
	switch(mConnectionState) {
	case CS_GETINFO:
		request = &mInfoRequest;
		dhdebug("Send info request...");
		break;
	case CS_REGISTER:
		request = &mRegisterRequest;
		dhdebug("Send register request...");
		break;
	case CS_POLL:
		request = &mPollRequest;
		dhdebug("Send poll request...");
		break;
	default:
		dhdebug("ASSERT: networkConnectCb wrong state %d", mConnectionState);
	}
	int res;
	if( (res = espconn_send(&mDHConnector, request->data, request->len)) != ESPCONN_OK) {
		mConnectionState = CS_DISCONNECT;
		dhesperrors_espconn_result("network_connect_cb failed:", res);
		espconn_disconnect(&mDHConnector);
	} else {
		dhstatistic_add_bytes_sent(request->len);
	}
}
void ICACHE_FLASH_ATTR dhdebug_dump(const char *data, unsigned int len) {
	if(len == 0)
		return;
	const unsigned char byte_per_line = 16;
	char textbuf[byte_per_line + 1];
	char hexbuf[byte_per_line * 3 + 1];
	char address[9] = "00000000";
	int pos = 0;
	dhdebug("Dump at 0x%X, length %u", (unsigned int)data, len);
	do {
		byteToHex((pos / 0x1000000) & 0xFF, &address[0]);
		byteToHex((pos / 0x10000) & 0xFF, &address[2]);
		byteToHex((pos / 0x100) & 0xFF, &address[4]);
		byteToHex(pos & 0xFF, &address[6]);
		unsigned int i;
		for(i = 0; i < byte_per_line; i++) {
			if(pos < len) {
				char c = data[pos++];
				byteToHex(c, &hexbuf[i * 3]);
				hexbuf[i * 3 + 2] = ' ';
				if(c < 0x20 || c >= 0x7F)
					textbuf[i] = '.';
				else
					textbuf[i] = c;
				textbuf[i + 1] = 0;
			} else {
				hexbuf[i * 3] = ' ';
				hexbuf[i * 3 + 1] = ' ';
				hexbuf[i * 3 + 2] = ' ';
			}
			hexbuf[i * 3 + 3] = 0;
		}
		dhdebug("%s:  %s  %s", address, hexbuf, textbuf);
	} while (pos < len);
}
UP_STATUS ICACHE_FLASH_ATTR uploadable_page_finish() {
    if(mBuffer == NULL)
        return UP_STATUS_WRONG_CALL;
    os_timer_disarm(&mFlashingTimer);
    ETS_INTR_LOCK();
    // Mark data with null terminated char. If data takes whole available space,
    // there is no need in null terminated char.
    // At this point buffer should have at lest 1 free byte, since buffer
    // reaches maximum size before, it had to be written to flash.
    // If nothing was written, just report ok.
    SpiFlashOpResult res = SPI_FLASH_RESULT_OK;
    if(mBufferPos) {
        mBuffer[mBufferPos] = 0;
        mBufferPos++;
        res = flash_data();
    } else if(mFlashingSector > UPLOADABLE_PAGE_START_SECTOR &&
              mFlashingSector <= UPLOADABLE_PAGE_END_SECTOR) {
        res = write_zero_byte(mFlashingSector);
    }
    mBufferPos = 0;
    os_free(mBuffer);
    mBuffer = NULL;
    // force to recalc page size
    mPageLength = 0;
    ETS_INTR_UNLOCK();
    if(res != SPI_FLASH_RESULT_OK) {
        dhdebug("Error while finishing flash page");
        return UP_STATUS_INTERNAL_ERROR;
    }
    dhdebug("Flashing page has finished successfully");
    return UP_STATUS_OK;
}
void ICACHE_FLASH_ATTR dhesperrors_wifi_state(const char *descrption, uint8 reason) {
	char *errdescr = 0;
	switch(reason) {
	case EVENT_STAMODE_CONNECTED:
		errdescr = "STAMODE_CONNECTED";
		break;
	case EVENT_STAMODE_DISCONNECTED:
		errdescr = "STAMODE_DISCONNECTED";
		break;
	case EVENT_STAMODE_AUTHMODE_CHANGE:
		errdescr = "STAMODE_AUTHMODE_CHANGE";
		break;
	case EVENT_STAMODE_GOT_IP:
		errdescr = "STAMODE_GOT_IP";
		break;
	case EVENT_SOFTAPMODE_STACONNECTED:
		errdescr = "SOFTAPMODE_STACONNECTED";
		break;
	case EVENT_SOFTAPMODE_STADISCONNECTED:
		errdescr = "SOFTAPMODE_STADISCONNECTED";
		break;
	case EVENT_MAX:
		errdescr = "EVENT_MAX";
		break;
	}
	if(errdescr)
		dhdebug("%s %s", descrption, errdescr);
	else
		dhdebug("%s %d", descrption, reason);
}
int ICACHE_FLASH_ATTR dhsender_queue_take(HTTP_REQUEST *out, unsigned int *is_notification) {
	if(mQueueTakePos < 0)
		return 0;
	ETS_INTR_LOCK();
	DHSENDER_QUEUE item;
	os_memcpy(&item, &mQueue[mQueueTakePos], sizeof(DHSENDER_QUEUE));
	if(mQueueTakePos >= mQueueMaxSize - 1)
		mQueueTakePos = 0;
	else
		mQueueTakePos++;
	if(mQueueAddPos == mQueueTakePos)
		mQueueTakePos = -1;
	mQueueSize--;
	ETS_INTR_UNLOCK();

	if(mQueueSize < MEM_RECOVER_THRESHOLD && dhmem_isblock())
		dhmem_unblock();

	char buf[HTTP_REQUEST_MIN_ALLOWED_PAYLOAD];
	if(dhsender_data_to_json(buf, sizeof(buf),
			item.notification_type == RNT_NOTIFICATION_GPIO, item.data_type,
			&item.data, item.data_len, item.pin) < 0) {
		snprintf(buf, sizeof(buf), "Failed to convert data to json");
		item.type = RT_RESPONCE_ERROR;
	}

	*is_notification = 0;
	switch(item.type) {
		case RT_RESPONCE_OK:
		case RT_RESPONCE_ERROR:
			dhrequest_create_update(out, item.id, (item.type == RT_RESPONCE_OK) ? STATUS_OK : STATUS_ERROR, buf);
			break;
		case RT_NOTIFICATION:
			*is_notification = 1;
			switch(item.notification_type) {
			case RNT_NOTIFICATION_GPIO:
				dhrequest_create_notification(out, "gpio/int", buf);
				break;
			case RNT_NOTIFICATION_ADC:
				dhrequest_create_notification(out, "adc/int", buf);
				break;
			case RNT_NOTIFICATION_UART:
				dhrequest_create_notification(out, "uart/int", buf);
				break;
			case RNT_NOTIFICATION_ONEWIRE:
				dhrequest_create_notification(out, "onewire/master/int", buf);
				break;
			default:
				dhdebug("ERROR: Unknown notification type of request %d", item.notification_type);
				return 0;
			}
			break;
		default:
			dhdebug("ERROR: Unknown type of request %d", item.type);
			return 0;
	}
	return 1;
}
LOCAL void ICACHE_FLASH_ATTR start_resolve_dh_server() {
	static ip_addr_t ip;
	const char *server = dhrequest_current_server();
	char host[os_strlen(server) + 1];
	const char *fr = server;
	while(*fr != ':') {
		fr++;
		if(*fr == 0) {
			fr = 0;
			break;
		}
	}
	if(fr) {
		fr++;
		if(*fr != '/')
			fr = 0;
	}
	if (fr) {
		while (*fr == '/')
			fr++;
		int i = 0;
		while (*fr != '/' && *fr != ':' && *fr != 0)
			host[i++] = *fr++;
		// read port if present
		int port = 0;
		if(*fr == ':') {
			unsigned char d;
			fr++;
			while ( (d = *fr - 0x30) < 10) {
				fr++;
				port = port*10 + d;
				if(port > 0xFFFF)
					break;
			}
		}
		if(port && port < 0xFFFF)
			mDHConnector.proto.tcp->remote_port = port;
		else if (os_strncmp(dhrequest_current_server(), "https", 5) == 0)
			mDHConnector.proto.tcp->remote_port = 443; // HTTPS default port
		else
			mDHConnector.proto.tcp->remote_port = 80; //HTTP default port
		host[i] = 0;
		dhdebug("Resolving %s", host);
		err_t r = espconn_gethostbyname(&mDHConnector, host, &ip, resolve_cb);
		if(r == ESPCONN_OK) {
			resolve_cb(host, &ip, NULL);
		} else if(r != ESPCONN_INPROGRESS) {
			dhesperrors_espconn_result("Resolving failed:", r);
			arm_repeat_timer(RETRY_CONNECTION_INTERVAL_MS);
		}
	} else {
		dhdebug("Can not find scheme in server url");
	}
}
LOCAL void parse_json(struct jsonparse_state *jparser) {
	int type;
	unsigned int id;
	char command[128] = "";
	const char *params;
	int paramslen = 0;
	char timestamp[128] = "";
	while ((type = jsonparse_next(jparser)) != JSON_TYPE_ERROR) {
		if (type == JSON_TYPE_PAIR_NAME) {
			if (jsonparse_strcmp_value(jparser, "serverTimestamp") == 0) {
				jsonparse_next(jparser);
				if (jsonparse_next(jparser) != JSON_TYPE_ERROR) {
					jsonparse_copy_value(jparser, timestamp, sizeof(timestamp));
					dhdebug("Timestamp received %s", timestamp);
					dhrequest_update_poll(&mPollRequest, timestamp);
				}
				break;
			} else if (jsonparse_strcmp_value(jparser, "command") == 0) {
				jsonparse_next(jparser);
				if(jsonparse_next(jparser) != JSON_TYPE_ERROR)
					jsonparse_copy_value(jparser, command, sizeof(command));
			} else if (jsonparse_strcmp_value(jparser, "id") == 0) {
				jsonparse_next(jparser);
				if(jsonparse_next(jparser) != JSON_TYPE_ERROR)
					id = jsonparse_get_value_as_ulong(jparser);
			} else if (jsonparse_strcmp_value(jparser, "parameters") == 0) {
				jsonparse_next(jparser);
				if(jsonparse_next(jparser) != JSON_TYPE_ERROR) {
					// there is an issue with extracting subjson with jparser->vstart or jparser_copy_value
					params = &jparser->json[jparser->pos - 1];
					if(*params == '{') {
						int end = jparser->pos;
						while(end < jparser->len && jparser->json[end] != '}') {
							end++;
						}
						paramslen = end - jparser->pos + 2;
					}
				}
			} else if (jsonparse_strcmp_value(jparser, "timestamp") == 0) {
				jsonparse_next(jparser);
				if(jsonparse_next(jparser) != JSON_TYPE_ERROR)
					jsonparse_copy_value(jparser, timestamp, sizeof(timestamp));
			}
		}
	}
	if (mConnectionState == CS_POLL) {
		if(timestamp[0]) {
			dhdebug("Timestamp received %s", timestamp);
			dhrequest_update_poll(&mPollRequest, timestamp);
		}
		mCommandCallback(id, command, params, paramslen);
	}
}
LOCAL void ICACHE_FLASH_ATTR dhap_httpd_connect_cb(void *arg) {
	struct espconn *conn = arg;
	mConnected++;
	if(mConnected > MAX_CONNECTIONS) {
		espconn_disconnect(conn);
		dhdebug("Refuse connection, already %u connections", mConnected);
		return;
	}
	espconn_regist_recvcb(conn, dhap_httpd_recv_cb);
	espconn_regist_disconcb(conn, dhap_httpd_disconnect_cb);
	espconn_regist_sentcb(conn, dhap_httpd_sent_cb);
	dhdebug("Client connected");
}
void ICACHE_FLASH_ATTR dhsender_queue_init() {
	mQueueMaxSize = (system_get_free_heap_size() - MEMORY_RESERVER) / sizeof(DHSENDER_QUEUE);
	if(mQueueMaxSize > MAX_QUEUE_LENGTH)
		mQueueMaxSize = MAX_QUEUE_LENGTH;
	mQueue = (DHSENDER_QUEUE *)os_malloc(mQueueMaxSize * sizeof(DHSENDER_QUEUE));
	if(mQueue == 0) {
		dhdebug("ERROR: can not allocate memory for queue");
	} else {
		if(mQueueMaxSize < 10)
			dhdebug("Warning: queue is very shot - %u", mQueueMaxSize);
		else
			dhdebug("Queue created, size %u", mQueueMaxSize);
	}
}
void ICACHE_FLASH_ATTR dhesperrors_espconn_result(const char *descrption, int reason) {
	char *errdescr = 0;
	switch(reason) {
	case ESPCONN_OK:
		errdescr = "No error";
		break;
	case ESPCONN_MEM:
		errdescr = "Out of memory error";
		break;
	case ESPCONN_TIMEOUT:
		errdescr = "Timeout";
		break;
	case ESPCONN_RTE:
		errdescr = "Routing problem";
		break;
	case ESPCONN_INPROGRESS:
		errdescr = "Operation in progress";
		break;
	case ESPCONN_ABRT:
		errdescr = "Connection aborted";
		break;
	case ESPCONN_RST:
		errdescr = "Connection reset";
		break;
	case ESPCONN_CLSD:
		errdescr = "Connection closed";
		break;
	case ESPCONN_CONN:
		errdescr = "Not connected";
		break;
	case ESPCONN_ARG:
		errdescr = "Illegal argument";
		break;
	case ESPCONN_ISCONN:
		errdescr = "Already connected";
		break;
	case ESPCONN_HANDSHAKE:
		errdescr = "SSL handshake failed";
		break;
	case ESPCONN_PROTO_MSG:
		errdescr = "SSL application invalid";
		break;
	}
	if(errdescr)
		dhdebug("%s %s", descrption, errdescr);
	else
		dhdebug("%s %d", descrption, reason);
}
LOCAL void set_state(CONNECTION_STATE state) {
	mConnectionState = state;
	if(state != CS_DISCONNECT) {
		if(dhmem_isblock()) {
			mNeedRecover = 1;
			return;
		}
	}
	switch(state) {
	case CS_DISCONNECT:
		start_resolve_dh_server();
		break;
	case CS_GETINFO:
	case CS_REGISTER:
	case CS_POLL:
	{
		const sint8 cr = espconn_connect(&mDHConnector);
		if(cr == ESPCONN_ISCONN)
			return;
		if(cr != ESPCONN_OK) {
			dhesperrors_espconn_result("Connector espconn_connect failed:", cr);
			arm_repeat_timer(RETRY_CONNECTION_INTERVAL_MS);
		}
		break;
	}
	default:
		dhdebug("ASSERT: set_state wrong state %d", mConnectionState);
	}
}
UP_STATUS ICACHE_FLASH_ATTR uploadable_page_begin() {
    ETS_INTR_LOCK();
    if(mBuffer == NULL) {
        mBuffer = (char *)os_malloc(SPI_FLASH_SEC_SIZE);
    }
    mBufferPos = 0;
    mFlashingSector = UPLOADABLE_PAGE_START_SECTOR;
    ETS_INTR_UNLOCK();
    if(mBuffer == NULL) {
        dhdebug("No memory to initialize page flashing");
        return UP_STATUS_INTERNAL_ERROR;
    }
    reset_timer();
    dhdebug("Page flashing is initialized");
    return UP_STATUS_OK;
}
int ICACHE_FLASH_ATTR dhsender_queue_add(REQUEST_TYPE type, REQUEST_NOTIFICATION_TYPE notification_type, REQUEST_DATA_TYPE data_type, unsigned int id, va_list ap) {
	ETS_INTR_LOCK();
	if(mQueueAddPos == mQueueTakePos) {
		ETS_INTR_UNLOCK();
		dhdebug("ERROR: no space for request");
		return 0;
	}
	mQueue[mQueueAddPos].id = id;
	mQueue[mQueueAddPos].type = type;
	mQueue[mQueueAddPos].data_type = data_type;
	mQueue[mQueueAddPos].notification_type = notification_type;
	dhsender_data_parse_va(ap, &data_type, &mQueue[mQueueAddPos].data,
			&mQueue[mQueueAddPos].data_len, &mQueue[mQueueAddPos].pin);
	if(mQueueTakePos < 0)
		mQueueTakePos = mQueueAddPos;
	if(mQueueAddPos >= mQueueMaxSize - 1)
		mQueueAddPos = 0;
	else
		mQueueAddPos++;
	mQueueSize++;
	if(mQueueSize > RESERVE_FOR_RESPONCE)
		dhmem_block();
	ETS_INTR_UNLOCK();
	return 1;
}
LOCAL UP_STATUS ICACHE_FLASH_ATTR flash_data() {
    if(mFlashingSector > UPLOADABLE_PAGE_END_SECTOR) {
        return UP_STATUS_OVERFLOW;
    }

    if((SPI_FLASH_SEC_SIZE - mBufferPos) > 0) {
        irom_read(&mBuffer[mBufferPos], (const char *)
                  (mFlashingSector * SPI_FLASH_SEC_SIZE + mBufferPos + IROM_FLASH_BASE_ADDRESS),
                  SPI_FLASH_SEC_SIZE - mBufferPos);
        mBufferPos = SPI_FLASH_SEC_SIZE;
    }

    if(irom_cmp(mBuffer, (const char *)
                (mFlashingSector * SPI_FLASH_SEC_SIZE + IROM_FLASH_BASE_ADDRESS),
                SPI_FLASH_SEC_SIZE) == 0) {
        mFlashingSector++;
        return UP_STATUS_OK;
    }

    SpiFlashOpResult res;
    res = spi_flash_erase_sector(mFlashingSector);
    if(res == SPI_FLASH_RESULT_OK) {
        dhdebug("Flashing page at address 0x%X", mFlashingSector * SPI_FLASH_SEC_SIZE);
        res = spi_flash_write(mFlashingSector * SPI_FLASH_SEC_SIZE,
                              (uint32 *)mBuffer, SPI_FLASH_SEC_SIZE);
    }

    system_soft_wdt_feed();
    if(res == SPI_FLASH_RESULT_OK) {
        mFlashingSector++;
        return UP_STATUS_OK;
    }
    return UP_STATUS_INTERNAL_ERROR;
}
UP_STATUS ICACHE_FLASH_ATTR uploadable_page_put(const char *data, unsigned int data_len) {
    if(mBuffer == NULL)
        return UP_STATUS_WRONG_CALL;
    if(mFlashingSector > UPLOADABLE_PAGE_END_SECTOR)
        return UP_STATUS_OVERFLOW;
    reset_timer();

    ETS_INTR_LOCK();
    while(data_len) {
        uint32_t tocopy = (data_len > (SPI_FLASH_SEC_SIZE - mBufferPos)) ?
                          (SPI_FLASH_SEC_SIZE - mBufferPos): data_len;
        os_memcpy(&mBuffer[mBufferPos], data, tocopy);
        mBufferPos += tocopy;
        data_len -= tocopy;
        data += tocopy;
        if(mBufferPos == SPI_FLASH_SEC_SIZE) {
            SpiFlashOpResult res = flash_data();
            mBufferPos = 0;
            if(res != SPI_FLASH_RESULT_OK) {
                ETS_INTR_UNLOCK();
                dhdebug("Error while writing page at 0x%X",
                        mFlashingSector * SPI_FLASH_SEC_SIZE);
                return UP_STATUS_INTERNAL_ERROR;
            }
        }
    }
    ETS_INTR_UNLOCK();
    return UP_STATUS_OK;
}
LOCAL void network_recv_cb(void *arg, char *data, unsigned short len) {
	dhstatistic_add_bytes_received(len);
	const char *rc = find_http_responce_code(data, len);
	if (rc) { // HTTP
		if (*rc == '2') { // HTTP responce code 2xx - Success
			if (mConnectionState == CS_REGISTER) {
				dhdebug("Successfully register");
			} else {
				char *content = (char *) os_strstr(data, (char *) "\r\n\r\n");
				if (content) {
					int deep = 0;
					unsigned int pos = 0;
					unsigned int jsonstart = 0;
					while (pos < len) {
						if (data[pos] == '{') {
							if (deep == 0)
								jsonstart = pos;
							deep++;
						} else if (data[pos] == '}') {
							deep--;
							if (deep == 0) {
								struct jsonparse_state jparser;
								jsonparse_setup(&jparser, &data[jsonstart],
										pos - jsonstart);
								parse_json(&jparser);
							}
						}
						pos++;
					}
				}
			}
		} else {
			mConnectionState = CS_DISCONNECT;
			dhdebug("Connector HTTP response bad status %c%c%c", rc[0],rc[1],rc[2]);
			dhdebug(data);
			dhdebug("--------------------------------------");
			dhstatistic_server_errors_count();
		}
	} else {
		mConnectionState = CS_DISCONNECT;
		dhdebug("Connector HTTP magic number is wrong");
		dhstatistic_server_errors_count();
	}
	espconn_disconnect(&mDHConnector);
}
LOCAL void ICACHE_FLASH_ATTR resolve_cb(const char *name, ip_addr_t *ip, void *arg) {
	if (ip == NULL) {
		dhdebug("Resolve %s failed. Trying again...", name);
		mConnectionState = CS_DISCONNECT;
		arm_repeat_timer(RETRY_CONNECTION_INTERVAL_MS);
		dhstatistic_inc_network_errors_count();
		return;
	}
	unsigned char *bip = (unsigned char *) ip;
	dhdebug("Host %s ip: %d.%d.%d.%d, using port %d", name, bip[0], bip[1], bip[2], bip[3], mDHConnector.proto.tcp->remote_port);

	dhsender_init(ip, mDHConnector.proto.tcp->remote_port);
	dhconnector_init_connection(ip);
	if(mPollRequest.len)
		set_state(CS_POLL);
	else
		set_state(CS_GETINFO);
}
LOCAL void ICACHE_FLASH_ATTR senderRecvCb(void *arg, char *data, unsigned short len) {
	dhstatistic_add_bytes_received(len);
	const char *rc = find_http_responce_code(data, len);
	if (rc) { // HTTP
		if (*rc == '2') { // HTTP responce code 2xx - Success
			mSenderTook = 0;
			dhdebug("Sender received OK");
		} else {
			dhdebug("Sender HTTP response bad status %c%c%c", rc[0],rc[1],rc[2]);
			dhdebug_ram(data);
			dhdebug("--------------------------------------");
			dhstatistic_server_errors_count();
		}
	} else {
		dhdebug("Sender received wrong HTTP magic");
		dhstatistic_server_errors_count();
	}
	espconn_disconnect(&mDHSender);
}
LOCAL void ICACHE_FLASH_ATTR wifi_state_cb(System_Event_t *event) {
	if(event->event == EVENT_STAMODE_GOT_IP) {
		if(event->event_info.got_ip.ip.addr != 0) {
			const unsigned char * const bip = (unsigned char *)&event->event_info.got_ip.ip;
			dhdebug("WiFi connected, ip: %d.%d.%d.%d", bip[0], bip[1], bip[2], bip[3]);
			mConnectionState = CS_DISCONNECT;
			arm_repeat_timer(DHREQUEST_PAUSE_MS);
		} else {
			dhdebug("ERROR: WiFi reports STAMODE_GOT_IP, but no actual ip found");
		}
	} else if(event->event == EVENT_STAMODE_DISCONNECTED) {
		os_timer_disarm(&mRetryTimer);
		dhsender_stop_repeat();
		dhesperrors_disconnect_reason("WiFi disconnected", event->event_info.disconnected.reason);
		dhstatistic_inc_wifi_lost_count();
	} else {
		dhesperrors_wifi_state("WiFi event", event->event);
	}
}
int ICACHE_FLASH_ATTR dhgpio_write(unsigned int set_mask, unsigned int unset_mask) {
	const unsigned int pins = set_mask | unset_mask;
	if((pins | DHGPIO_SUITABLE_PINS) != DHGPIO_SUITABLE_PINS)
		return 0;
	dhdebug("GPIO set high at 0x%X, set low at 0x%X", set_mask, unset_mask);
	dhgpio_prepare_pins(pins, 1);
	dhgpio_open_drain(0, pins);
	dhgpio_pull(0, pins);
	gpio_output_set(set_mask, unset_mask, pins, 0);
	return 1;
}
Exemple #21
0
void user_init(void) {
    int ever_saved;
    if(mSpecialMode) {
        system_set_os_print(0);
        dhsettings_init(&ever_saved);
        dhap_init();
    } else {
        dhdebug("*****************************");
        dhsettings_init(&ever_saved);
        if(ever_saved == 0) { // if first run on this chip
            uploadable_page_delete();
        }
        dhsender_queue_init();
        dhconnector_init(dhcommands_do);
        dhgpio_init();
        webserver_init();
        dhdebug("Initialization completed");
        dhterminal_init();
    }
}
LOCAL void ICACHE_FLASH_ATTR decrementSenderTook() {
	if(mSenderTook) {
		if(mSenderTook == 1) {
			dhdebug("WARNING: Request is not delivered after %u attempts", DHSENDER_RETRY_COUNT);
			if(isCurrentNotification)
				dhstatistic_inc_notifications_dropped_count();
			else
				dhstatistic_inc_responces_dropped_count();
		}
		mSenderTook--;
	}
}
void ICACHE_FLASH_ATTR dhsender_notification(REQUEST_NOTIFICATION_TYPE type, REQUEST_DATA_TYPE data_type, ...) {
	va_list ap;
	va_start(ap, data_type);
	dhstatistic_inc_notifications_count();
	if(dhsender_queue_add(RT_NOTIFICATION, type, data_type, 0, ap)) {
		dhsender_next(NULL);
	} else {
		dhstatistic_inc_notifications_dropped_count();
		dhdebug("ERROR: No memory for notification.");
	}
	va_end(ap);
}
void ICACHE_FLASH_ATTR dhsender_response(CommandResultArgument cid, RESPONCE_STATUS status, REQUEST_DATA_TYPE data_type, ...) {
	va_list ap;
	va_start(ap, data_type);
	dhstatistic_inc_responces_count();
	if(dhsender_queue_add(status == DHSTATUS_ERROR ? RT_RESPONCE_ERROR : RT_RESPONCE_OK, RNT_NOTIFICATION_NONE, data_type, cid.id, ap)) {
		dhsender_next(NULL);
	} else {
		dhstatistic_inc_responces_dropped_count();
		dhdebug("ERROR: No memory for response.");
	}
	va_end(ap);
}
void ICACHE_FLASH_ATTR dhap_httpd_init() {
	struct espconn *httpdConn = (struct espconn *)os_zalloc(sizeof(struct espconn ));
	esp_tcp *httpdTcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
	httpdConn->type = ESPCONN_TCP;
	httpdConn->state = ESPCONN_NONE;
	httpdTcp->local_port = HTTPD_PORT;
	httpdConn->proto.tcp = httpdTcp;

	espconn_regist_connectcb(httpdConn, dhap_httpd_connect_cb);
	espconn_regist_reconcb(httpdConn, dhap_httpd_reconnect_cb);
	sint8 res = espconn_accept(httpdConn);
	if(res)
		dhdebug("espconn_accept returned: %d", res);
}
LOCAL void network_disconnect_cb(void *arg) {
	switch(mConnectionState) {
	case CS_DISCONNECT:
		arm_repeat_timer(RETRY_CONNECTION_INTERVAL_MS);
		break;
	case CS_GETINFO:
		set_state(CS_REGISTER);
		break;
	case CS_REGISTER:
		mConnectionState = CS_POLL;
		/* no break */
	case CS_POLL:
		arm_repeat_timer(DHREQUEST_PAUSE_MS);
		break;
	default:
		dhdebug("ASSERT: networkDisconnectCb wrong state %d", mConnectionState);
	}
}
LOCAL void ICACHE_FLASH_ATTR dhsender_next(void *arg) {
	if(mStopped)
		return;
	if(mSenderTook == 0) {
		if(dhsender_queue_take(&mSenderRequest, &isCurrentNotification))
			mSenderTook = DHSENDER_RETRY_COUNT;
		else
			return;
	}
	sint8 cr = espconn_connect(&mDHSender);
	if(cr == ESPCONN_ISCONN) {
		return;
	} else if (cr != ESPCONN_OK) {
		dhesperrors_espconn_result("Sender espconn_connect failed:", cr);
		dhsender_arm_timer(RETRY_CONNECTION_INTERVAL_MS);
	} else {
		dhdebug("Sender start");
	}
}
Exemple #28
0
DHI2C_STATUS ICACHE_FLASH_ATTR mpu6050_read(int sda, int scl,
		MPU6050_XYZ *acceleromter, MPU6050_XYZ *gyroscope, float *temparature)
{
	char buf[16];
	DHI2C_STATUS status;
	if(sda != MPU6050_NO_PIN && scl != MPU6050_NO_PIN) {
		if((status = dhi2c_init(sda, scl)) != DHI2C_OK) {
			dhdebug("mpu6050: failed to set up pins");
			return status;
		}
	}

	buf[0] = 0x6B; // power up
	buf[1] = 0; // no sleep bit
	if((status = dhi2c_write(mAddress, buf, 2, 1)) != DHI2C_OK) {
		dhdebug("mpu6050: failed to power up");
		return status;
	}

	buf[0] = 0x1C; // accelerometer configuration
	buf[1] = (1 << 4); // AFS_SEL = 2, range +-8 g
	if((status = dhi2c_write(mAddress, buf, 2, 1)) != DHI2C_OK) {
		dhdebug("mpu6050: failed to configure accelerometer");
		return status;
	}

	buf[0] = 0x1B; // gyroscope configuration
	buf[1] = (1 << 4); // FS_SEL = 2, range +-1000 dps
	if((status = dhi2c_write(mAddress, buf, 2, 1)) != DHI2C_OK) {
		dhdebug("mpu6050: failed to configure gyroscope");
		return status;
	}

	os_delay_us(50000);

	buf[0] = 0x3B; // get data
	if((status = dhi2c_write(mAddress, buf, 1, 0)) != DHI2C_OK) {
		dhdebug("mpu6050: failed to set read register");
		return status;
	}
	if((status = dhi2c_read(mAddress, buf, 14)) != DHI2C_OK) {
		dhdebug("mpu6050: failed to read");
		return status;
	}

	buf[14] = 0x6B; // power down
	buf[15] = 1 << 6; // sleep bit
	if((status = dhi2c_write(mAddress, &buf[14], 2, 1)) != DHI2C_OK) {
		dhdebug("mpu6050: failed to power up");
		return status;
	}

	if(acceleromter) {
		acceleromter->X = signedInt16(buf, 0) * 8.0f * EARTH_GRAVITY_ACCELERATION / 32768.0f;
		acceleromter->Y = signedInt16(buf, 2) * 8.0f * EARTH_GRAVITY_ACCELERATION / 32768.0f;
		acceleromter->Z = signedInt16(buf, 4) * 8.0f * EARTH_GRAVITY_ACCELERATION / 32768.0f;
	}

	if(gyroscope) {
		gyroscope->X = signedInt16(buf, 8) * 1000.0f / 32768.0f;
		gyroscope->Y = signedInt16(buf, 10) * 1000.0f / 32768.0f;
		gyroscope->Z = signedInt16(buf, 12) * 1000.0f / 32768.0f;
	}

	if(temparature)
		*temparature = signedInt16(buf, 6) / 340.0f + 36.53f;
	return DHI2C_OK;
}
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;
		}
	}
}
LOCAL void ICACHE_FLASH_ATTR dhap_httpd_sent_cb(void *arg) {
	struct espconn *conn = arg;
	espconn_disconnect(conn);
	dhdebug("Data sent");
}