void ICACHE_FLASH_ATTR dhterminal_commands_config(const char *args) {
	dhuart_send_str("Wi-Fi SSID: ");
	dhuart_send_line(dhsettings_get_wifi_ssid());
	dhuart_send_str("DeviceHive Server: ");
	dhuart_send_line(dhsettings_get_devicehive_server());
	dhuart_send_str("DeviceHive DeviceId: ");
	dhuart_send_line(dhsettings_get_devicehive_deviceid());
}
void ICACHE_FLASH_ATTR dhterminal_commands_uname(const char *args) {
	char digitBuff[32];
	dhuart_send_line("DeviceHive ESP8266 firmware v"FIRMWARE_VERSION" [Built: "__TIME__" "__DATE__"]");
	dhuart_send_line("Created by Nikolay Khabarov.");
	dhuart_send_str("ChipID: 0x");
	snprintf(digitBuff, sizeof(digitBuff), "%X", system_get_chip_id());
	dhuart_send_str(digitBuff);
	dhuart_send_str(", SDK version: ");
	dhuart_send_str(system_get_sdk_version());
	dhuart_send_line("");
}
LOCAL void ICACHE_FLASH_ATTR nslookup_res(const char *name, ip_addr_t *ip, void *arg) {
	char ipstr[16];
	if (ip == NULL) {
		dhuart_send_line("FAILED");
	} else {
		sprintIp(ipstr, ip);
		dhuart_send_str("Host ");
		dhuart_send_str(name);
		dhuart_send_str(" IP is ");
		dhuart_send_line(ipstr);
	}
}
LOCAL void ICACHE_FLASH_ATTR ping_cb(void* arg, void *pdata) {
	char digitbuf[16];
	struct ping_option *pingopt = (struct ping_option *)arg;
	struct ping_resp *pingresp = (struct ping_resp *)pdata;
	if(dhterminal_get_mode() == SM_OUTPUT_MODE) {
		mSent++;
		if(pingresp->ping_err == 0) {
			mRecieved++;
			mTotalDelay += pingresp->resp_time;
			snprintf(digitbuf, sizeof(digitbuf), "%d", pingresp->bytes);
			dhuart_send_str(digitbuf);
			dhuart_send_str(" bytes received from ");
			sprintIp(digitbuf, (const struct ip_addr *)&pingopt->ip);
			dhuart_send_str(digitbuf);
			dhuart_send_str(" in ");
			snprintf(digitbuf, sizeof(digitbuf), "%d", pingresp->resp_time);
			dhuart_send_str(digitbuf);
			dhuart_send_str(" ms, icmp_seq = ");
			snprintf(digitbuf, sizeof(digitbuf), "%d", mSent);
			dhuart_send_line(digitbuf);
		} else {
			mLost++;
			dhuart_send_str("Request timed out, icmp_seq = ");
			snprintf(digitbuf, sizeof(digitbuf), "%d", mSent);
			dhuart_send_line(digitbuf);
		}
	}
}
LOCAL void ICACHE_FLASH_ATTR get_devicekey_cb(const char *key) {
	if(*key)
		dhsettings_set_devicehive_devicekey(key);
	dhuart_send_str("Configuring complete, store settings...");
	if(dhsettings_commit()) {
		dhuart_send_line("OK");
		dhuart_send_line("Rebooting...");
		system_restart();
	} else {
		dhuart_send_line("ERROR. Not saved. Check debug output.");
	}
	dhterminal_set_mode(SM_NORMAL_MODE, 0, 0, 0, 0);
}
LOCAL void ICACHE_FLASH_ATTR ping_done_cb(void* arg, void *pdata) {
	char digitbuf[16];
	if(dhterminal_get_mode() == SM_OUTPUT_MODE) {
		dhuart_send_str("Total sent: ");
		snprintf(digitbuf, sizeof(digitbuf), "%d", mSent);
		dhuart_send_str(digitbuf);
		dhuart_send_str(", received: ");
		snprintf(digitbuf, sizeof(digitbuf), "%d", mRecieved);
		dhuart_send_str(digitbuf);
		dhuart_send_str(", lost: ");
		snprintf(digitbuf, sizeof(digitbuf), "%d", mLost);
		dhuart_send_str(digitbuf);
		if(mRecieved) {
			dhuart_send_str(", average time: ");
			snprintf(digitbuf, sizeof(digitbuf), "%d", mTotalDelay/mRecieved);
			dhuart_send_str(digitbuf);
			dhuart_send_line(" ms");
		} else {
			dhuart_send_line("");
		}
		dhterminal_set_mode(SM_NORMAL_MODE, 0, 0, 0, 0);
	}
	mIsCommandWorking = 0;
}
void ICACHE_FLASH_ATTR dhterminal_commands_status(const char *args) {
	uint8 mac[6];
	char digitBuff[32];
	struct station_config stationConfig;

	dhuart_send_str("Network adapter ");
	if(!wifi_get_macaddr(STATION_IF, mac)) {
		dhuart_send_str("[Failed to get mac address]");
	} else {
		sprintMac(digitBuff, mac);
		dhuart_send_str(digitBuff);
	}

	if(!wifi_station_get_config(&stationConfig)) {
		os_memset(&stationConfig, 0, sizeof(stationConfig));
		os_strcpy(stationConfig.ssid, "[Can not get SSID]");
	}
	switch(wifi_station_get_connect_status()) {
	case STATION_IDLE:
		dhuart_send_line(" is in idle");
		break;
	case STATION_CONNECTING:
		dhuart_send_str(" is connecting to ");
		dhuart_send_line(stationConfig.ssid);
		break;
	case STATION_WRONG_PASSWORD:
		dhuart_send_str(" has wrong password for ");
		dhuart_send_line(stationConfig.ssid);
		break;
	case STATION_NO_AP_FOUND:
		dhuart_send_str(" can not find AP with SSID ");
		dhuart_send_line(stationConfig.ssid);
		break;
	case STATION_CONNECT_FAIL:
		dhuart_send_str(" has fail while connecting to ");
		dhuart_send_line(stationConfig.ssid);
		break;
	case STATION_GOT_IP:
	{
		dhuart_send_str(" is connected to ");
		dhuart_send_line(stationConfig.ssid);
		struct ip_info info;
		if(!wifi_get_ip_info(STATION_IF, &info)) {
			dhuart_send_line("Failed to get ip info");
		} else {
			dhuart_send_str("IP: ");
			sprintIp(digitBuff, &info.ip);
			dhuart_send_str(digitBuff);
			dhuart_send_str(", netmask: ");
			sprintIp(digitBuff, &info.netmask);
			dhuart_send_str(digitBuff);
			dhuart_send_str(", gateway: ");
			sprintIp(digitBuff, &info.gw);
			dhuart_send_line(digitBuff);
		}
		break;
	}
	default:
		dhuart_send_line("is in unknown state");
		break;
	}
	const DHSTATISTIC *stat = dhstatistic_get_statistic();
	dhuart_send_str("Wi-Fi disconnect count: ");
	snprintf(digitBuff, sizeof(digitBuff), "%u", stat->wifiLosts);
	dhuart_send_line(digitBuff);

	dhuart_send_str("Bytes received: ");
	printBytes(digitBuff, stat->bytesReceived);
	dhuart_send_str(digitBuff);
	dhuart_send_str(", sent: ");
	printBytes(digitBuff, stat->bytesSent);
	dhuart_send_str(digitBuff);
	dhuart_send_str(", errors: ");
	snprintf(digitBuff, sizeof(digitBuff), "%u", stat->networkErrors);
	dhuart_send_line(digitBuff);

	dhuart_send_str("Httpd requests received: ");
	snprintf(digitBuff, sizeof(digitBuff), "%u", stat->httpdRequestsCount);
	dhuart_send_str(digitBuff);
	dhuart_send_str(", errors: ");
	snprintf(digitBuff, sizeof(digitBuff), "%u", stat->httpdErrorsCount);
	dhuart_send_line(digitBuff);

	dhuart_send_str("DeviceHive: ");
	switch(dhconnector_get_state()) {
	case CS_DISCONNECT:
		dhuart_send_str("connection is not established");
		break;
	case CS_GETINFO:
		dhuart_send_str("getting info from server");
		break;
	case CS_REGISTER:
		dhuart_send_str("registering device");
		break;
	case CS_POLL:
	case CS_CUSTOM:
		dhuart_send_str("successfully connected to server");
		break;
	default:
		dhuart_send_str("unknown state");
		break;
	}
	dhuart_send_str(", errors count: ");
	snprintf(digitBuff, sizeof(digitBuff), "%u", stat->serverErrors);
	dhuart_send_line(digitBuff);

	dhuart_send_str("Responses created/dropped: ");
	snprintf(digitBuff, sizeof(digitBuff), "%u/%u", stat->responcesTotal, stat->responcesDroppedCount);
	dhuart_send_str(digitBuff);
	dhuart_send_str(", notification created/dropped: ");
	snprintf(digitBuff, sizeof(digitBuff), "%u/%u", stat->notificationsTotal, stat->notificationsDroppedCount);
	dhuart_send_line(digitBuff);


	dhuart_send_str("Free heap size: ");
	snprintf(digitBuff, sizeof(digitBuff), "%d", system_get_free_heap_size());
	dhuart_send_str(digitBuff);
	dhuart_send_str(" bytes");

	dhuart_send_str(", request queue size: ");
	snprintf(digitBuff, sizeof(digitBuff), "%d", dhsender_queue_length());
	dhuart_send_line(digitBuff);

}
void ICACHE_FLASH_ATTR dhterminal_commands_debug(const char *args) {
	dhuart_send_line("Debug output enabled. Press 'q' for exit.");
	dhterminal_set_mode(SM_DEBUG_MODE, 0, 0, 0, 0);
	dhuart_send_str(dhterminal_get_debug_ouput());
}