// #define DEBUG #define BAUD_RATE 115200 #include "common.h" #include "pins.h" #include "fpga.h" #include "wifi.h" #include "config.h" #include "led.h" #include "tty.h" #include "boardinfo_esp.h" #include #include #include #include #include #include #include volatile bool do_log_config_status; uint8_t efuse_default_mac[6]; char serial_number[16]; // Canonical board serial number void setup_usb_ids() { uint8_t * const mac = efuse_default_mac; esp_efuse_mac_get_default(mac); snprintf(serial_number, sizeof serial_number, "%02X%02X%02X-%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); USB.VID(0x4680); USB.PID(0x0882); USB.firmwareVersion(1); // Do something smarter here USB.productName("MAX80 Network Controller"); USB.manufacturerName("Peter & Per"); USB.serialNumber(serial_number); } bool _spiram_broken; void heap_info() { size_t il = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL); size_t ia = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); size_t it = heap_caps_get_total_size(MALLOC_CAP_INTERNAL); size_t sl = heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM); size_t sa = heap_caps_get_free_size(MALLOC_CAP_SPIRAM); size_t st = heap_caps_get_total_size(MALLOC_CAP_SPIRAM); char msg_buffer[128]; snprintf(msg_buffer, sizeof msg_buffer, "Heap: sram %zu/%zu/%zu, spiram %zu/%zu/%zu\r\n", il, ia, it, sl, sa, st); fputs(msg_buffer, stdout); Serial.print(msg_buffer); setvar_uint(status_heap_sram_max, il); setvar_uint(status_heap_sram_free, ia); setvar_uint(status_heap_sram_size, it); setvar_uint(status_heap_spiram_max, sl); setvar_uint(status_heap_spiram_free, sa); setvar_uint(status_heap_spiram_size, st); _spiram_broken = st == 0; } #if 0 static void dump_config() { printf("--- Configuration:\n"); write_sysvars(stdout, false); printf("--- Status:\n"); write_sysvars(stdout, true); printf("--- End configuration and status\n"); } #endif static void init_hw() { // Start out with disabled shared I/O pins for (int i = 1; i <= 18; i++) pinMode(i, INPUT); // Query board info board_info_init(); // Make sure FPGA nCE input (board 2.1+) is not accidentally pulled high fpga_enable_nce(); // Configure USB power control. Try to detect 36k pulldown // resistor on USB_PWR_EN first, to determine board version 2 // (on board v1, this pin in N/C.) // // This detection algorithm is sketchy at best. In the end the // better option probably would be to use the ADC mode of the input // pin... pinMode(PIN_USB_PWR_SINK, OUTPUT); // IO8: USB_PWR_SINK digitalWrite(PIN_USB_PWR_SINK, 0); // This is a power sink pinMode(PIN_USB_PWR_EN, OUTPUT); digitalWrite(PIN_USB_PWR_EN, 0); delayMicroseconds(50); // Configure LEDs led_init(); led_set(LED_BLUE, LED_FLASH); // ESP32 software initializing } #define _tostring(x) #x #define tostring(x) _tostring(x) static const char fwdate[] = __DATE__ " " __TIME__; static const char arduino_esp32_ver[] = tostring(ARDUINO_ESP32_GIT_DESC); static void set_build_status_info() { setvar_str(status_max80_fw_date, fwdate); setvar_str(status_max80_fw_esp32_arduino, arduino_esp32_ver); setvar_str(status_max80_fw_esp32_idf, IDF_VER); } void setup() { init_hw(); // Enable external PSRAM for heap heap_caps_malloc_extmem_enable(3000); // >= 3K allocations in PSRAM TTY::init(); Serial.print("\r\n*** Hello, World! ***\r\n"); sysvar_init(); heap_info(); printf("[FW] MAX80 firmware compiled on %s\n", fwdate); printf("[PCB] MAX80 board version: %s\n", board_info.version_str); setvar_str(status_max80_hw_ver, board_info.version_str); printf("[PCB] MAX80 serial number: %s\n", serial_number); setvar_str(status_max80_hw_serial, serial_number); Serial.println("MAX80 start"); init_config(); set_build_status_info(); fpga_service_init(); fpga_service_enable(true); if (spiram_broken()) { const char spiram_broken_msg[] = "WARNING: SPIRAM broken, not starting network\r\n"; fputs(spiram_broken_msg, stdout); Serial.print(spiram_broken_msg); } else { SetupWiFi(); } Serial.println("[RDY]"); sysvar_print_updates = true; do_log_config_status = true; // Print configuration from main loop led_set(LED_BLUE, LED_ON); // Software ready } static inline char task_state(eTaskState state) { switch (state) { case eInvalid: return 'X'; case eReady: case eRunning: return 'R'; case eBlocked: return 'D'; case eSuspended: return 'S'; case eDeleted: return 'Z'; default: return '?'; } } static void dump_tasks(void) { TaskHandle_t task = NULL; while (1) { task = pxTaskGetNext(task); if (!task) break; printf("%-16s %c %2u\n", pcTaskGetName(task), task_state(eTaskGetState(task)), uxTaskPriorityGet(task)); } } void loop() { if (0) { printf("loop task: %s\n", pcTaskGetName(xTaskGetCurrentTaskHandle())); printf("idle task: %s\n", pcTaskGetName(xTaskGetIdleTaskHandle())); dump_tasks(); heap_info(); putchar('\n'); } if (do_log_config_status) { do_log_config_status = false; heap_info(); log_config_status(); } fflush(stdout); TTY::ping(); vTaskDelay(5 * configTICK_RATE_HZ); }