#include "esp_misc.h" #include "esp_sta.h" #include "esp_system.h" #include "esp_wifi.h" #include "esp_spiffs.h" #include "spiffs.h" #include "spiffs.h" #include "sdkconfig.h" #include "MQTTClient.h" #include /* #include #include #include #include #include */ // Allow overriding configuration from Kconfig. #ifndef WIFI_SSID #define WIFI_SSID CONFIG_MAIN_DEFAULT_WIFI_SSID #endif #ifndef WIFI_PASSWORD #define WIFI_PASSWORD CONFIG_MAIN_DEFAULT_WIFI_PASSWORD #endif #ifndef MQTT_HOST #define MQTT_HOST CONFIG_MAIN_DEFAULT_MQTT_HOST #endif #ifndef MQTT_PORT #define MQTT_PORT CONFIG_MAIN_DEFAULT_MQTT_PORT #endif extern "C" uint32_t user_rf_cal_sector_set(); extern "C" void user_init(); enum events { EVENTS_GOT_IP = (1 << 0), EVENTS_LOST_IP = (1 << 1), }; struct config { int loaded; int ok_count; char wifi_ssid[20]; char wifi_password[20]; char mqtt_host[20]; int mqtt_port; // Generated field char mqtt_client_id[20]; }; struct config main_config; struct _reent fs_reent; #define open(...) _spiffs_open_r(&fs_reent, __VA_ARGS__) #define close(...) _spiffs_close_r(&fs_reent, __VA_ARGS__) #define read(...) _spiffs_read_r(&fs_reent, __VA_ARGS__) #define write(...) _spiffs_write_r(&fs_reent, __VA_ARGS__) #define lseek(...) _spiffs_lseek_r(&fs_reent, __VA_ARGS__) xTaskHandle main_task_handle = 0; /****************************************************************************** * FunctionName : user_rf_cal_sector_set * Description : SDK just reversed 4 sectors, used for rf init data and paramters. * We add this function to force users to set rf cal sector, since * we don't know which sector is free in user's application. * sector map for last several sectors : ABCCC * A : rf cal * B : rf init data * C : sdk parameters * Parameters : none * Returns : rf cal sector *******************************************************************************/ uint32_t user_rf_cal_sector_set() { flash_size_map size_map = system_get_flash_size_map(); uint32_t rf_cal_sec = 0; switch (size_map) { case FLASH_SIZE_4M_MAP_256_256: rf_cal_sec = 128 - 5; break; case FLASH_SIZE_8M_MAP_512_512: rf_cal_sec = 256 - 5; break; case FLASH_SIZE_16M_MAP_512_512: case FLASH_SIZE_16M_MAP_1024_1024: rf_cal_sec = 512 - 5; break; case FLASH_SIZE_32M_MAP_512_512: case FLASH_SIZE_32M_MAP_1024_1024: rf_cal_sec = 1024 - 5; break; case FLASH_SIZE_64M_MAP_1024_1024: rf_cal_sec = 2048 - 5; break; case FLASH_SIZE_128M_MAP_1024_1024: rf_cal_sec = 4096 - 5; break; default: rf_cal_sec = 0; break; } return rf_cal_sec; } static int on_config_item(void *ctx, const char* key, const char* value) { struct config *config = (struct config *)ctx; if (strcmp(key, "wifi-ssid") == 0) { strncpy(config->wifi_ssid, value, sizeof(config->wifi_ssid)); } else if (strcmp(key, "wifi-password") == 0) { strncpy(config->wifi_password, value, sizeof(config->wifi_password)); } else if (strcmp(key, "mqtt-host") == 0) { strncpy(config->mqtt_host, value, sizeof(config->mqtt_host)); } else if (strcmp(key, "mqtt-port") == 0) { config->mqtt_port = atoi(value); } else { printf("Unknown key: %s\n", key); return -1; } config->ok_count++; return 0; } typedef int (kv_event_handler)(void *ctx, const char *key, const char *value); static int config_read_on_line(kv_event_handler *event_handler, void *ctx, const char* line, size_t sz) { // printf("Handling line: #%d, %s\n", sz, line); char *ptr = strchr(line, '='); if (ptr == NULL) { printf("Could not find '='\n"); return -1; } *ptr = '\0'; const char *key = line, *value = ++ptr; return event_handler(ctx, key, value); } static int config_read(kv_event_handler *event_handler, void *ctx) { int ret = 0; int pos = 0; int fd = open("config", O_RDONLY, 0); // printf("fd=%d\n", fd); if (fd < 0) { ret = -1; goto fail; } while (1) { char buf[100]; ret = lseek(fd, pos, SEEK_SET); if (ret == -1) { printf("lseek failed: pos=%d, res=%d\n", pos, ret); break; } if (pos > 200) { break; // fail safe for now } ret = read(fd, buf, sizeof(buf)); // printf("read: pos=%d, ret=%d\n", (int) pos, ret); if (ret > 0) { char *end = (char *)memchr(buf, 0, ret); if (end == NULL) { printf("could not find newline\n"); ret = -1; goto fail; } else { *end = '\0'; size_t line_sz = end - buf; // printf("line_sz=%d\n", line_sz); pos += line_sz + 1; ret = config_read_on_line(event_handler, ctx, buf, line_sz); if (ret) { goto fail; } } } else { break; } } fail: if (fd != -1) { close(fd); } // printf("%s: ret=%d\n", __FUNCTION__, ret); return ret; } static int config_write_kv(int fd, const char *key, const char *value) { int ret; char c; // printf("Writing %s=%s\n", key, value); size_t sz = strlen(key); ret = write(fd, (char *)key, sz); if (ret != sz) { return ret; } c = '='; ret = write(fd, &c, 1); if (ret != 1) { return ret; } sz = strlen(value); ret = write(fd, (char *)value, sz); if (ret != sz) { return ret; } c = 0; return write(fd, &c, 1) != 1; } static int config_write_kv(int fd, const char *key, int value) { char buf[100]; itoa(value, buf, 10); return config_write_kv(fd, key, buf); } static int config_write(struct config &config) { int ret = 0; int fd = open("config", O_WRONLY | O_CREAT, 0); if (fd == -1) { ret = -1; goto fail; } ret = config_write_kv(fd, "mqtt-host", config.mqtt_host); if (ret) { goto fail; } ret = config_write_kv(fd, "mqtt-port", config.mqtt_port); if (ret) { goto fail; } fail: if (fd != -1) { close(fd); } // printf("%s: ret=%d\n", __FUNCTION__, ret); return ret; } void wifi_event_handler_cb(System_Event_t *event) { if (event == NULL) { os_printf("NULL event\n"); return; } if (event->event_id == EVENT_STAMODE_GOT_IP) { // printf("STA GOT IP\n"); if (main_task_handle) { xTaskNotify(main_task_handle, EVENTS_GOT_IP, eSetBits); } } else if (event->event_id == EVENT_STAMODE_CONNECTED) { os_printf("STA CONNECTED\n"); } else if (event->event_id == EVENT_STAMODE_DISCONNECTED) { if (main_task_handle) { xTaskNotify(main_task_handle, EVENTS_LOST_IP, eSetBits); } wifi_station_connect(); } else { os_printf("unhandled event=%d\n", event->event_id); } } static int fs_init() { struct esp_spiffs_config config; uint32_t log_page_size = CONFIG_MAIN_FLASH_LOG_PAGE_SIZE; config.phys_size = CONFIG_MAIN_FLASH_SIZE_KB * 1024; config.phys_addr = CONFIG_MAIN_FLASH_FLASH_ADDR_KB * 1024; config.phys_erase_block = CONFIG_MAIN_FLASH_SECTOR_SIZE_KB * 1024; config.log_block_size = CONFIG_MAIN_FLASH_LOG_BLOCK_SIZE_KB * 1024; config.log_page_size = log_page_size; config.fd_buf_size = CONFIG_MAIN_FLASH_FD_BUF_SIZE * 2; config.cache_buf_size = (log_page_size + 32) * 8; return esp_spiffs_init(&config); } static MQTTClient mqtt_client; static Network mqtt_network; unsigned char mqtt_tx_buf[80], mqtt_rx_buf[80]; static int mqtt_connect() { int ret; MQTTPacket_connectData cd = MQTTPacket_connectData_initializer; cd.keepAliveInterval = 15; cd.willFlag = 1; cd.will.retained = 1; cd.will.topicName = MQTTString_initializer; cd.will.topicName.cstring = (char *)"esp/esp-245398/online"; cd.will.message = MQTTString_initializer; cd.will.message.cstring = (char *)"0"; NetworkInit(&mqtt_network); unsigned int command_timeout_ms = 30000; MQTTClientInit(&mqtt_client, &mqtt_network, command_timeout_ms, mqtt_tx_buf, sizeof(mqtt_tx_buf), mqtt_rx_buf, sizeof(mqtt_rx_buf)); if ((ret = NetworkConnect(&mqtt_network, main_config.mqtt_host, main_config.mqtt_port)) != 0) { printf("%s: NetworkConnect:%d\n", __FUNCTION__, ret); goto fail; } // printf("%s: network connected\n", __FUNCTION__); #if defined(MQTT_TASK) if ((ret = MQTTStartTask(&mqtt_client)) != pdPASS) { printf("%s: MQTTStartTask:%d\n", __FUNCTION__, ret); goto fail; } #endif cd.MQTTVersion = 4; cd.clientID.cstring = main_config.mqtt_client_id; if ((ret = MQTTConnect(&mqtt_client, &cd)) != 0) { printf("%s: MQTTConnect:%d\n", __FUNCTION__, ret); goto fail; } // printf("%s: mqtt connected\n", __FUNCTION__); return 0; fail: return ret; } static int mqtt_disconnect() { printf("%s\n", __FUNCTION__); // TODO: start timer to reconnect to mqtt return 0; } static int mqtt_publish(const char *topic, const char *value) { uint32_t chip_id = system_get_chip_id(); char buf[100]; snprintf(buf, sizeof(buf), "esp/esp-%02x%02x%02x/%s", (chip_id >> 16) & 0xff, (chip_id >> 8) & 0xff, chip_id & 0xff, topic); printf("=> %s: %s\n", buf, value); MQTTMessage m; bzero(&m, sizeof(m)); m.qos = QOS1; m.payloadlen = strlen(value); m.payload = (void *)value; m.retained = 1; return MQTTPublish(&mqtt_client, buf, &m); } static void set_station_mode(struct config &config) { // printf("STATION_MODE\n"); if (wifi_get_opmode_default() != NULL_MODE) { printf("Setting default station mode"); wifi_set_opmode(NULL_MODE); } wifi_set_opmode_current(STATION_MODE); struct station_config sc; bzero(&sc, sizeof(struct station_config)); sprintf((char *)sc.ssid, config.wifi_ssid); sprintf((char *)sc.password, config.wifi_password); wifi_station_set_config(&sc); wifi_set_event_handler_cb(wifi_event_handler_cb); wifi_station_connect(); } void main_task(void* ctx) { (void) ctx; int count = 0; uint32_t notification_value; while (1) { int timeout = xTaskNotifyWait(0, UINT32_MAX, ¬ification_value, pdMS_TO_TICKS(1000)) == pdFALSE; if (notification_value & EVENTS_GOT_IP) { struct ip_info info; wifi_get_ip_info(STATION_IF, &info); printf("ip=" IPSTR ", nm=" IPSTR ", gw=" IPSTR "\n", IP2STR(&info.ip), IP2STR(&info.netmask), IP2STR(&info.gw)); if (mqtt_connect()) { printf("mqtt_connect failed\n"); mqtt_disconnect(); } else { int ret = mqtt_publish("online", "1"); printf("%s: mqtt_publish:%d\n", __FUNCTION__, ret); } } if (notification_value & EVENTS_LOST_IP) { mqtt_disconnect(); } if (timeout) { /* printf("Hello World! %d\n", count); if (count == 2) { // pvShowMalloc(); } if (count == 5) { // set_station_mode(); } */ count++; } // vTaskDelay(pdMS_TO_TICKS(500)); } } #define THREAD_NAME "main" #define THREAD_STACK_WORDS 2048 #define THREAD_PRIO 8 void user_init() { int ret; os_printf("SDK version: %s, free: %d\n", system_get_sdk_version(), system_get_free_heap_size()); os_printf("App: instace: " CONFIG_ESPTOOLPY_APP_NUM ", build: %s\n", __TIMESTAMP__); os_printf("Upgrade: boot mode: %d, version: %d, user addr=%08x, flash map: %d\n", system_get_boot_mode(), system_get_boot_version(), system_get_userbin_addr(), system_get_flash_size_map()); fs_init(); bzero(&main_config, sizeof(struct config)); ret = config_read(on_config_item, &main_config); if (ret) { printf("Loading file failed, errno=%d\n", fs_reent._errno); } if (main_config.ok_count != 4) { printf("Loading file failed, loaded bad number of items=%d\n", main_config.ok_count); } else { main_config.loaded = 1; } if (!main_config.loaded) { printf("No config loaded, writing new\n"); strncpy(main_config.wifi_ssid, WIFI_SSID, sizeof(((struct config*)0)->wifi_ssid)); strncpy(main_config.wifi_password, WIFI_PASSWORD, sizeof(((struct config*)0)->wifi_password)); strncpy(main_config.mqtt_host, MQTT_HOST, sizeof(((struct config*)0)->mqtt_host)); main_config.mqtt_port = MQTT_PORT; ret = config_write(main_config); if (ret) { printf("Writing file failed, errno=%d\n", fs_reent._errno); } } uint32_t chip_id = system_get_chip_id(); snprintf(main_config.mqtt_client_id, sizeof(main_config.mqtt_client_id), "esp-%02x%02x%02x", (chip_id >> 16) & 0xff, (chip_id >> 8) & 0xff, chip_id & 0xff); printf("Configuration:\n"); printf(" wifi-ssid=%s\n wifi-password=%s\n\n", main_config.wifi_ssid, main_config.wifi_password); printf(" mqtt-host=%s\n mqtt-port=%d\n mqtt-client-id=%s\n\n", main_config.mqtt_host, main_config.mqtt_port, main_config.mqtt_client_id); set_station_mode(main_config); ret = xTaskCreate(main_task, THREAD_NAME, THREAD_STACK_WORDS, NULL, THREAD_PRIO, &main_task_handle); assert(ret == pdPASS); }