diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 8198b40dc..e0656bed6 100755 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -7,6 +7,7 @@ SRCS "display.c" "screen.c" "input.c" + "filesystem.c" "system.c" "work_queue.c" "lv_font_portfolio-6x8.c" diff --git a/main/filesystem.c b/main/filesystem.c new file mode 100644 index 000000000..aa797b0e2 --- /dev/null +++ b/main/filesystem.c @@ -0,0 +1,39 @@ +#include "filesystem.h" +#include "global_state.h" +#include "esp_log.h" +#include "esp_spiffs.h" +#include "esp_vfs.h" + +static const char * TAG = "filesystem"; + +esp_err_t filesystem_init(void * pvParameters) +{ + GlobalState * GLOBAL_STATE = (GlobalState *) pvParameters; + + esp_vfs_spiffs_conf_t conf = {.base_path = "", .partition_label = NULL, .max_files = 5, .format_if_mount_failed = false}; + esp_err_t ret = esp_vfs_spiffs_register(&conf); + + if (ret != ESP_OK) { + if (ret == ESP_FAIL) { + ESP_LOGE(TAG, "Failed to mount or format filesystem"); + } else if (ret == ESP_ERR_NOT_FOUND) { + ESP_LOGE(TAG, "Failed to find SPIFFS partition"); + } else { + ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); + } + return ESP_FAIL; + } + + GLOBAL_STATE->filesystem_is_available = true; + + size_t total = 0, used = 0; + ret = esp_spiffs_info(NULL, &total, &used); + if (ret != ESP_OK) { + // This shouldn't happen + ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret)); + } else { + ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); + } + + return ESP_OK; +} diff --git a/main/filesystem.h b/main/filesystem.h new file mode 100644 index 000000000..d0b95864b --- /dev/null +++ b/main/filesystem.h @@ -0,0 +1,16 @@ +#ifndef FILESYSTEM_H_ +#define FILESYSTEM_H_ + +#include "esp_err.h" + +/** + * @brief Initialize the SPIFFS filesystem + * + * This function mounts the SPIFFS partition and can be used + * independently of the REST server for self-test mode. + * + * @return ESP_OK on success, ESP_FAIL on failure + */ +esp_err_t filesystem_init(void * pvParameters); + +#endif /* FILESYSTEM_H_ */ diff --git a/main/global_state.h b/main/global_state.h index 19c90d25a..b37d58071 100644 --- a/main/global_state.h +++ b/main/global_state.h @@ -145,6 +145,7 @@ typedef struct bool ASIC_initalized; bool psram_is_available; + bool filesystem_is_available; int block_height; char scriptsig[128]; diff --git a/main/http_server/http_server.c b/main/http_server/http_server.c index 6448335d8..a4df1936b 100644 --- a/main/http_server/http_server.c +++ b/main/http_server/http_server.c @@ -302,33 +302,6 @@ esp_err_t is_network_allowed(httpd_req_t * req) return ESP_FAIL; } -esp_err_t init_fs(void) -{ - esp_vfs_spiffs_conf_t conf = {.base_path = "", .partition_label = NULL, .max_files = 5, .format_if_mount_failed = false}; - esp_err_t ret = esp_vfs_spiffs_register(&conf); - - if (ret != ESP_OK) { - if (ret == ESP_FAIL) { - ESP_LOGE(TAG, "Failed to mount or format filesystem"); - } else if (ret == ESP_ERR_NOT_FOUND) { - ESP_LOGE(TAG, "Failed to find SPIFFS partition"); - } else { - ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); - } - return ESP_FAIL; - } - - size_t total = 0, used = 0; - ret = esp_spiffs_info(NULL, &total, &used); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret)); - } else { - ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); - } - - return ESP_OK; -} - /* Function for stopping the webserver */ void stop_webserver(httpd_handle_t server) { @@ -1293,13 +1266,6 @@ esp_err_t start_rest_server(void * pvParameters) asic_api_init(GLOBAL_STATE); const char * base_path = ""; - bool enter_recovery = false; - if (init_fs() != ESP_OK) { - // Unable to initialize the web app filesystem. - // Enter recovery mode - enter_recovery = true; - } - REST_CHECK(base_path, "wrong base path", err); rest_server_context_t * rest_context = calloc(1, sizeof(rest_server_context_t)); REST_CHECK(rest_context, "No memory for rest context", err); @@ -1426,7 +1392,7 @@ esp_err_t start_rest_server(void * pvParameters) }; httpd_register_uri_handler(server, &ws); - if (enter_recovery) { + if (!GLOBAL_STATE->filesystem_is_available) { /* Make default route serve Recovery */ httpd_uri_t recovery_implicit_get_uri = { .uri = "/*", .method = HTTP_GET, diff --git a/main/main.c b/main/main.c index 518388c6e..91c4a1502 100644 --- a/main/main.c +++ b/main/main.c @@ -21,6 +21,8 @@ #include "connect.h" #include "asic_reset.h" #include "asic_init.h" +#include "filesystem.h" +#include "input.h" static GlobalState GLOBAL_STATE; @@ -73,25 +75,30 @@ void app_main(void) return; } - if (self_test(&GLOBAL_STATE)) + if (self_test_init(&GLOBAL_STATE) != ESP_OK) { + ESP_LOGE(TAG, "Failed to init self test"); return; + } SYSTEM_init_system(&GLOBAL_STATE); - // init AP and connect to wifi - wifi_init(&GLOBAL_STATE); + if (!GLOBAL_STATE.SELF_TEST_MODULE.is_active) { + wifi_init(&GLOBAL_STATE); + } SYSTEM_init_peripherals(&GLOBAL_STATE); if (xTaskCreate(POWER_MANAGEMENT_task, "power management", 8192, (void *) &GLOBAL_STATE, 10, NULL) != pdPASS) { ESP_LOGE(TAG, "Error creating power management task"); } - if (xTaskCreate(FAN_CONTROLLER_task, "fan_controller", 8192, (void *) &GLOBAL_STATE, 5, NULL) != pdPASS) { - ESP_LOGE(TAG, "Error creating fan controller task"); - } - // start the API for AxeOS - start_rest_server((void *) &GLOBAL_STATE); + if (!GLOBAL_STATE.SELF_TEST_MODULE.is_active) { + if (xTaskCreate(FAN_CONTROLLER_task, "fan_controller", 8192, (void *) &GLOBAL_STATE, 5, NULL) != pdPASS) { + ESP_LOGE(TAG, "Error creating fan controller task"); + } + // start the API for AxeOS + start_rest_server((void *) &GLOBAL_STATE); + } // After mounting SPIFFS SYSTEM_init_versions(&GLOBAL_STATE); @@ -113,15 +120,23 @@ void app_main(void) return; } - if (xTaskCreate(stratum_task, "stratum admin", 8192, (void *) &GLOBAL_STATE, 5, NULL) != pdPASS) { - ESP_LOGE(TAG, "Error creating stratum admin task"); - } if (xTaskCreate(create_jobs_task, "stratum miner", 8192, (void *) &GLOBAL_STATE, 20, NULL) != pdPASS) { ESP_LOGE(TAG, "Error creating stratum miner task"); } if (xTaskCreate(ASIC_result_task, "asic result", 8192, (void *) &GLOBAL_STATE, 15, NULL) != pdPASS) { ESP_LOGE(TAG, "Error creating asic result task"); } + + if (!GLOBAL_STATE.SELF_TEST_MODULE.is_active) { + if (xTaskCreate(stratum_task, "stratum admin", 8192, (void *) &GLOBAL_STATE, 5, NULL) != pdPASS) { + ESP_LOGE(TAG, "Error creating stratum admin task"); + } + } else { + if (xTaskCreate(self_test_task, "self_test", 8192, (void *) &GLOBAL_STATE, 10, NULL) != pdPASS) { + ESP_LOGE(TAG, "Error creating self test task"); + } + } + if (xTaskCreateWithCaps(hashrate_monitor_task, "hashrate monitor", 8192, (void *) &GLOBAL_STATE, 5, NULL, MALLOC_CAP_SPIRAM) != pdPASS) { ESP_LOGE(TAG, "Error creating hashrate monitor task"); diff --git a/main/self_test/self_test.c b/main/self_test/self_test.c index f360af4bb..c4e82ceec 100644 --- a/main/self_test/self_test.c +++ b/main/self_test/self_test.c @@ -6,30 +6,18 @@ #include "esp_log.h" #include "esp_timer.h" +#include "esp_check.h" +#include "esp_psram.h" #include "DS4432U.h" -#include "TPS546.h" -#include "adc.h" -#include "display.h" -#include "esp_psram.h" -#include "global_state.h" -#include "i2c_bitaxe.h" -#include "input.h" -#include "nvs_config.h" -#include "nvs_flash.h" -#include "power.h" -#include "power_management_task.h" -#include "screen.h" #include "thermal.h" -#include "utils.h" #include "vcore.h" +#include "power.h" +#include "nvs_config.h" +#include "global_state.h" #include "asic.h" #include "asic_reset.h" -#include "bm1366.h" -#include "bm1368.h" -#include "bm1370.h" -#include "bm1397.h" #include "device_config.h" #include "hashrate_monitor_task.h" @@ -60,7 +48,7 @@ static bool isFactoryTest = false; // local function prototypes static void tests_done(GlobalState * GLOBAL_STATE, bool test_result); -static bool should_test() +static bool self_test_should_run() { bool is_factory_flash = nvs_config_get_u64(NVS_CONFIG_BEST_DIFF) < 1; bool is_self_test_flag_set = nvs_config_get_bool(NVS_CONFIG_SELF_TEST); @@ -73,15 +61,54 @@ static bool should_test() return gpio_get_level(CONFIG_GPIO_BUTTON_BOOT) == 0; // LOW when pressed } -static void reset_self_test() +esp_err_t self_test_init(void * pvParameters) { - ESP_LOGI(TAG, "Long press detected..."); - // Give the semaphore back - xSemaphoreGive(longPressSemaphore); + if (self_test_should_run()) { + GlobalState * GLOBAL_STATE = (GlobalState *) pvParameters; + + GLOBAL_STATE->SELF_TEST_MODULE.is_active = true; + GLOBAL_STATE->DEVICE_CONFIG.family.asic.difficulty = DIFFICULTY; + GLOBAL_STATE->SYSTEM_MODULE.is_connected = true; + + // TODO: This might work here instead of the setup json messages + // GLOBAL_STATE->extranonce_str = "12905085617eff8e"; + // GLOBAL_STATE->extranonce_2_len = 8; + // GLOBAL_STATE->pool_difficulty = 0xffffffff; + // GLOBAL_STATE->new_set_mining_difficulty_msg = true; + + // vTaskDelay(1000 / portTICK_PERIOD_MS); + + // No need to set version_mask, it uses default mask which is fine + // GLOBAL_STATE->version_mask = 0xffffffff; + // GLOBAL_STATE->new_stratum_version_rolling_msg = true; + + // Create a binary semaphore + longPressSemaphore = xSemaphoreCreateBinary(); + + if (longPressSemaphore == NULL) { + ESP_LOGE(TAG, "Failed to create semaphore"); + return ESP_FAIL; + } + } + + return ESP_OK; } -static void display_msg(char * msg, GlobalState * GLOBAL_STATE) +void self_test_reset() { + if (longPressSemaphore != NULL) { + ESP_LOGI(TAG, "Long press detected..."); + // Give the semaphore back + xSemaphoreGive(longPressSemaphore); + } +} + +void self_test_show_message(void * pvParameters, char * msg) +{ + GlobalState * GLOBAL_STATE = (GlobalState *) pvParameters; + + if (!GLOBAL_STATE->SELF_TEST_MODULE.is_active) return; + GLOBAL_STATE->SELF_TEST_MODULE.message = msg; vTaskDelay(10 / portTICK_PERIOD_MS); } @@ -110,7 +137,7 @@ static esp_err_t test_fan_sense(GlobalState * GLOBAL_STATE) // fan test failed ESP_LOGE(TAG, "FAN test failed!"); - display_msg("FAN:WARN", GLOBAL_STATE); + self_test_show_message(GLOBAL_STATE, "FAN:WARN"); return ESP_FAIL; } @@ -127,7 +154,7 @@ static esp_err_t test_power_consumption(GlobalState * GLOBAL_STATE) } ESP_LOGE(TAG, "POWER test failed! measured %.2f W, target %.2f W +/- %.2f W", power, target_power, margin); - display_msg("POWER:FAIL", GLOBAL_STATE); + self_test_show_message(GLOBAL_STATE, "POWER:FAIL"); return ESP_FAIL; } @@ -141,65 +168,10 @@ static esp_err_t test_core_voltage(GlobalState * GLOBAL_STATE) } // tests failed ESP_LOGE(TAG, "Core Voltage TEST FAIL, INCORRECT CORE VOLTAGE"); - display_msg("VCORE:FAIL", GLOBAL_STATE); + self_test_show_message(GLOBAL_STATE, "VCORE:FAIL"); return ESP_FAIL; } -esp_err_t test_display(GlobalState * GLOBAL_STATE) -{ - // Display testing - if (display_init(GLOBAL_STATE) != ESP_OK) { - ESP_LOGE(TAG, "DISPLAY test failed!"); - display_msg("DISPLAY:FAIL", GLOBAL_STATE); - return ESP_FAIL; - } - - if (GLOBAL_STATE->SYSTEM_MODULE.is_screen_active) { - ESP_LOGI(TAG, "DISPLAY init success!"); - } else { - ESP_LOGW(TAG, "DISPLAY not found!"); - } - - return ESP_OK; -} - -esp_err_t test_input(GlobalState * GLOBAL_STATE) -{ - // Input testing - if (input_init(NULL, reset_self_test) != ESP_OK) { - ESP_LOGE(TAG, "INPUT test failed!"); - display_msg("INPUT:FAIL", GLOBAL_STATE); - return ESP_FAIL; - } - - ESP_LOGI(TAG, "INPUT init success!"); - - return ESP_OK; -} - -esp_err_t test_screen(GlobalState * GLOBAL_STATE) -{ - // Screen testing - if (screen_start(GLOBAL_STATE) != ESP_OK) { - ESP_LOGE(TAG, "SCREEN test failed!"); - display_msg("SCREEN:FAIL", GLOBAL_STATE); - return ESP_FAIL; - } - - ESP_LOGI(TAG, "SCREEN start success!"); - - return ESP_OK; -} - -esp_err_t init_voltage_regulator(GlobalState * GLOBAL_STATE) -{ - ESP_RETURN_ON_ERROR(VCORE_init(GLOBAL_STATE), TAG, "VCORE init failed!"); - - ESP_RETURN_ON_ERROR(VCORE_set_voltage(GLOBAL_STATE, 1.150), TAG, "VCORE set voltage failed!"); - - return ESP_OK; -} - static esp_err_t test_input_voltage(GlobalState * GLOBAL_STATE) { if (!GLOBAL_STATE->DEVICE_CONFIG.INA260) { @@ -217,7 +189,7 @@ static esp_err_t test_input_voltage(GlobalState * GLOBAL_STATE) } ESP_LOGE(TAG, "Input voltage test failed! %.0f mV, expected %.0f +/- %.0f mV", input_voltage_mv, nominal_mv, margin_mv); - display_msg("VIN:FAIL", GLOBAL_STATE); + self_test_show_message(GLOBAL_STATE, "VIN:FAIL"); return ESP_FAIL; } @@ -232,73 +204,25 @@ esp_err_t test_vreg_faults(GlobalState * GLOBAL_STATE) return ESP_OK; } -esp_err_t test_voltage_regulator(GlobalState * GLOBAL_STATE) -{ - - // enable the voltage regulator GPIO on HW that supports it - if (GLOBAL_STATE->DEVICE_CONFIG.asic_enable) { - gpio_set_direction(GPIO_ASIC_ENABLE, GPIO_MODE_OUTPUT); - gpio_set_level(GPIO_ASIC_ENABLE, 0); - } - - if (init_voltage_regulator(GLOBAL_STATE) != ESP_OK) { - ESP_LOGE(TAG, "VCORE init failed!"); - display_msg("VCORE:FAIL", GLOBAL_STATE); - // tests_done(GLOBAL_STATE, false); - return ESP_FAIL; - } - - // VCore regulator testing - if (GLOBAL_STATE->DEVICE_CONFIG.DS4432U) { - if (DS4432U_test() != ESP_OK) { - ESP_LOGE(TAG, "DS4432 test failed!"); - display_msg("DS4432U:FAIL", GLOBAL_STATE); - // tests_done(GLOBAL_STATE, false); - return ESP_FAIL; - } - } - - ESP_LOGI(TAG, "Voltage Regulator test success!"); - return ESP_OK; -} - -esp_err_t test_init_peripherals(GlobalState * GLOBAL_STATE) -{ - - ESP_RETURN_ON_ERROR(Thermal_init(&GLOBAL_STATE->DEVICE_CONFIG), TAG, "THERMAL init failed"); - - // ESP_RETURN_ON_ERROR(Thermal_set_fan_percent(&GLOBAL_STATE->DEVICE_CONFIG, 1), TAG, "THERMAL set fan percent failed"); - - ESP_LOGI(TAG, "Peripherals init success!"); - return ESP_OK; -} - -esp_err_t test_psram(GlobalState * GLOBAL_STATE) -{ - if (!esp_psram_is_initialized()) { - ESP_LOGE(TAG, "No PSRAM available on ESP32!"); - display_msg("PSRAM:FAIL", GLOBAL_STATE); - return ESP_FAIL; - } - return ESP_OK; -} - /** * @brief Perform a self-test of the system. * - * This function is intended to be run as a task and will execute a series of + * This function is run as a task and will execute a series of * diagnostic tests to ensure the system is functioning correctly. * * @param pvParameters Pointer to the parameters passed to the task (if any). - * @return true if the self-test was run, false if it was skipped. */ -bool self_test(void * pvParameters) +void self_test_task(void * pvParameters) { GlobalState * GLOBAL_STATE = (GlobalState *) pvParameters; - // Should we run the self-test? - if (!should_test()) - return false; + if (!GLOBAL_STATE->SELF_TEST_MODULE.is_active) return; + + // Check if we already have an error message from peripheral initialization + if (GLOBAL_STATE->SELF_TEST_MODULE.message != NULL && strlen(GLOBAL_STATE->SELF_TEST_MODULE.message) > 0) { + ESP_LOGE(TAG, "Aborting self-test due to initialization failure: %s", GLOBAL_STATE->SELF_TEST_MODULE.message); + tests_done(GLOBAL_STATE, false); + } if (isFactoryTest) { ESP_LOGI(TAG, "Running factory self-test"); @@ -308,299 +232,129 @@ bool self_test(void * pvParameters) char logString[300]; - GLOBAL_STATE->SELF_TEST_MODULE.is_active = true; - - // Create a binary semaphore - longPressSemaphore = xSemaphoreCreateBinary(); - - gpio_install_isr_service(0); - - if (longPressSemaphore == NULL) { - ESP_LOGE(TAG, "Failed to create semaphore"); - return true; - } - - // Run PSRAM test - if (test_psram(GLOBAL_STATE) != ESP_OK) { + if (!GLOBAL_STATE->psram_is_available) { ESP_LOGE(TAG, "NO PSRAM on device!"); + self_test_show_message(GLOBAL_STATE, "PSRAM:FAIL"); tests_done(GLOBAL_STATE, false); } - // Run display tests - if (test_display(GLOBAL_STATE) != ESP_OK) { - ESP_LOGE(TAG, "Display test failed!"); - tests_done(GLOBAL_STATE, false); - } - - // Run input tests - if (test_input(GLOBAL_STATE) != ESP_OK) { - ESP_LOGE(TAG, "Input test failed!"); - tests_done(GLOBAL_STATE, false); - } - - // Run screen tests - if (test_screen(GLOBAL_STATE) != ESP_OK) { - ESP_LOGE(TAG, "Screen test failed!"); - tests_done(GLOBAL_STATE, false); - } - - // Init peripherals EMC2101 and INA260 (if present) - if (test_init_peripherals(GLOBAL_STATE) != ESP_OK) { - ESP_LOGE(TAG, "Peripherals init failed!"); - tests_done(GLOBAL_STATE, false); - } - - // Voltage Regulator Testing - if (test_voltage_regulator(GLOBAL_STATE) != ESP_OK) { - ESP_LOGE(TAG, "Voltage Regulator test failed!"); + // Capture extra validation for DS4432U if present + if (GLOBAL_STATE->DEVICE_CONFIG.DS4432U && DS4432U_test() != ESP_OK) { + ESP_LOGE(TAG, "DS4432 test failed!"); + self_test_show_message(GLOBAL_STATE, "DS4432U:FAIL"); tests_done(GLOBAL_STATE, false); } // Input voltage check (INA260 devices only) if (test_input_voltage(GLOBAL_STATE) != ESP_OK) { ESP_LOGE(TAG, "Input voltage test failed!"); - tests_done(GLOBAL_STATE, false); - } - - if (asic_reset() != ESP_OK) { - ESP_LOGE(TAG, "ASIC reset failed!"); - tests_done(GLOBAL_STATE, false); - } - - // test for number of ASICs - if (SERIAL_init() != ESP_OK) { - ESP_LOGE(TAG, "SERIAL init failed!"); - tests_done(GLOBAL_STATE, false); - } - - POWER_MANAGEMENT_init_frequency(GLOBAL_STATE); - - GLOBAL_STATE->DEVICE_CONFIG.family.asic.difficulty = DIFFICULTY; - - uint8_t chips_detected = ASIC_init(GLOBAL_STATE); - uint8_t chips_expected = GLOBAL_STATE->DEVICE_CONFIG.family.asic_count; - ESP_LOGI(TAG, "%u chips detected, %u expected", chips_detected, chips_expected); - - if (chips_detected != chips_expected) { - ESP_LOGE(TAG, "SELF-TEST FAIL, %d of %d CHIPS DETECTED", chips_detected, chips_expected); - char error_buf[20]; - snprintf(error_buf, 20, "ASIC:FAIL %d CHIPS", chips_detected); - display_msg(error_buf, GLOBAL_STATE); + self_test_show_message(GLOBAL_STATE, "VOLTAGE:FAIL"); tests_done(GLOBAL_STATE, false); } // test for voltage regulator faults if (test_vreg_faults(GLOBAL_STATE) != ESP_OK) { ESP_LOGE(TAG, "VCORE check fault failed!"); - char error_buf[20]; - snprintf(error_buf, 20, "VCORE:PWR FAULT"); - display_msg(error_buf, GLOBAL_STATE); + self_test_show_message(GLOBAL_STATE, "VCORE:PWR FAULT"); tests_done(GLOBAL_STATE, false); } - GLOBAL_STATE->ASIC_initalized = true; - // setup and test hashrate - int baud = ASIC_set_max_baud(GLOBAL_STATE); - vTaskDelay(10 / portTICK_PERIOD_MS); + vTaskDelay(1000 / portTICK_PERIOD_MS); - if (SERIAL_set_baud(baud) != ESP_OK) { - ESP_LOGE(TAG, "SERIAL set baud failed!"); + // setup and test hashrate + StratumApiV1Message msg = {0}; + + // 1. Mock set_extranonce + const char *extranonce_json = "{\"id\":null,\"method\":\"mining.set_extranonce\",\"params\":[\"12905085617eff8e\",8]}"; + STRATUM_V1_parse(&msg, extranonce_json); + if (msg.method == MINING_SET_EXTRANONCE) { + if (GLOBAL_STATE->extranonce_str) free(GLOBAL_STATE->extranonce_str); + GLOBAL_STATE->extranonce_str = msg.extranonce_str; + GLOBAL_STATE->extranonce_2_len = msg.extranonce_2_len; + ESP_LOGI(TAG, "Self-test: Applied mock extranonce %s, len %d", GLOBAL_STATE->extranonce_str, GLOBAL_STATE->extranonce_2_len); + } + + // 2. Mock set_difficulty + memset(&msg, 0, sizeof(msg)); + const char *difficulty_json = "{\"id\":null,\"method\":\"mining.set_difficulty\",\"params\":[4294967295]}"; + STRATUM_V1_parse(&msg, difficulty_json); + if (msg.method == MINING_SET_DIFFICULTY) { + GLOBAL_STATE->pool_difficulty = msg.new_difficulty; + GLOBAL_STATE->new_set_mining_difficulty_msg = true; + ESP_LOGI(TAG, "Self-test: Applied mock difficulty %lu", (unsigned long)GLOBAL_STATE->pool_difficulty); + } + + // 3. Mock set_version_mask + memset(&msg, 0, sizeof(msg)); + const char *version_mask_json = "{\"id\":null,\"method\":\"mining.set_version_mask\",\"params\":[\"ffffffff\"]}"; + STRATUM_V1_parse(&msg, version_mask_json); + if (msg.method == MINING_SET_VERSION_MASK) { + GLOBAL_STATE->version_mask = msg.version_mask; + GLOBAL_STATE->new_stratum_version_rolling_msg = true; + ESP_LOGI(TAG, "Self-test: Applied mock version mask %08lx", GLOBAL_STATE->version_mask); + } + + // 4. Mock mining.notify + memset(&msg, 0, sizeof(msg)); + const char *notify_json = "{\"id\":null,\"method\":\"mining.notify\",\"params\":[\"0\",\"0c859545a3498373a57452fac22eb7113df2a465000543520000000000000000\",\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4b0389130cfabe6d6d5cbab26a2599e92916edec5657a94a0708ddb970f5c45b5d\",\"31650707758de07b010000000000001cfd7038212f736c7573682f000000000379ad0c2a000000001976a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac00000000000000002c6a4c2952534b424c4f434b3ae725d3994b811572c1f345deb98b56b465ef8e153ecbbd27fa37bf1b005161380000000000000000266a24aa21a9ed63b06a7946b190a3fda1d76165b25c9b883bcc6621b040773050ee2a1bb18f1800000000\",[\"2b77d9e413e8121cd7a17ff46029591051d0922bd90b2b2a38811af1cb57a2b2\",\"5c8874cef00f3a233939516950e160949ef327891c9090467cead995441d22c5\",\"2d91ff8e19ac5fa69a40081f26c5852d366d608b04d2efe0d5b65d111d0d8074\",\"0ae96f609ad2264112a0b2dfb65624bedbcea3b036a59c0173394bba3a74e887\",\"e62172e63973d69574a82828aeb5711fc5ff97946db10fc7ec32830b24df7bde\",\"adb49456453aab49549a9eb46bb26787fb538e0a5f656992275194c04651ec97\",\"a7bc56d04d2672a8683892d6c8d376c73d250a4871fdf6f57019bcc737d6d2c2\",\"d94eceb8182b4f418cd071e93ec2a8993a0898d4c93bc33d9302f60dbbd0ed10\",\"5ad7788b8c66f8f50d332b88a80077ce10e54281ca472b4ed9bbbbcb6cf99083\",\"9f9d784b33df1b3ed3edb4211afc0dc1909af9758c6f8267e469f5148ed04809\",\"48fd17affa76b23e6fb2257df30374da839d6cb264656a82e34b350722b05123\",\"c4f5ab01913fc186d550c1a28f3f3e9ffaca2016b961a6a751f8cca0089df924\",\"cff737e1d00176dd6bbfa73071adbb370f227cfb5fba186562e4060fcec877e1\"],\"20000004\",\"1705ae3a\",\"647025b5\",true]}"; + STRATUM_V1_parse(&msg, notify_json); + + if (msg.method == MINING_NOTIFY) { + ESP_LOGI(TAG, "Enqueuing mock work into stratum_queue"); + queue_enqueue(&GLOBAL_STATE->stratum_queue, msg.mining_notification); + } else { + ESP_LOGE(TAG, "Failed to parse mock mining notification"); tests_done(GLOBAL_STATE, false); } - GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs = malloc(sizeof(bm_job *) * 128); - GLOBAL_STATE->valid_jobs = malloc(sizeof(uint8_t) * 128); - - for (int i = 0; i < 128; i++) { - GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[i] = NULL; - GLOBAL_STATE->valid_jobs[i] = 0; - } - - vTaskDelay(1000 / portTICK_PERIOD_MS); - - mining_notify notify_message; - notify_message.job_id = 0; - notify_message.prev_block_hash = "0c859545a3498373a57452fac22eb7113df2a465000543520000000000000000"; - notify_message.version = 0x20000004; - notify_message.target = 0x1705ae3a; - notify_message.ntime = 0x647025b5; - - char extranonce_2_str[17]; - extranonce_2_generate(1, 8, extranonce_2_str); - - uint8_t coinbase_tx_hash[32]; - calculate_coinbase_tx_hash("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4b0389130cfab" - "e6d6d5cbab26a2599e92916edec5657a94a0708ddb970f5c45b5d", - "31650707758de07b010000000000001cfd7038212f736c7573682f000000000379ad0c2a000000001976a9147c154ed" - "1dc59609e3d26abb2df2ea3d587cd8c4188ac00000000000000002c6a4c2952534b424c4f434b3ae725d3994b811572" - "c1f345deb98b56b465ef8e153ecbbd27fa37bf1b005161380000000000000000266a24aa21a9ed63b06a7946b190a3f" - "da1d76165b25c9b883bcc6621b040773050ee2a1bb18f1800000000", - "12905085617eff8e", extranonce_2_str, coinbase_tx_hash); - - uint8_t merkles[13][32]; - int num_merkles = 13; - - hex2bin("2b77d9e413e8121cd7a17ff46029591051d0922bd90b2b2a38811af1cb57a2b2", merkles[0], 32); - hex2bin("5c8874cef00f3a233939516950e160949ef327891c9090467cead995441d22c5", merkles[1], 32); - hex2bin("2d91ff8e19ac5fa69a40081f26c5852d366d608b04d2efe0d5b65d111d0d8074", merkles[2], 32); - hex2bin("0ae96f609ad2264112a0b2dfb65624bedbcea3b036a59c0173394bba3a74e887", merkles[3], 32); - hex2bin("e62172e63973d69574a82828aeb5711fc5ff97946db10fc7ec32830b24df7bde", merkles[4], 32); - hex2bin("adb49456453aab49549a9eb46bb26787fb538e0a5f656992275194c04651ec97", merkles[5], 32); - hex2bin("a7bc56d04d2672a8683892d6c8d376c73d250a4871fdf6f57019bcc737d6d2c2", merkles[6], 32); - hex2bin("d94eceb8182b4f418cd071e93ec2a8993a0898d4c93bc33d9302f60dbbd0ed10", merkles[7], 32); - hex2bin("5ad7788b8c66f8f50d332b88a80077ce10e54281ca472b4ed9bbbbcb6cf99083", merkles[8], 32); - hex2bin("9f9d784b33df1b3ed3edb4211afc0dc1909af9758c6f8267e469f5148ed04809", merkles[9], 32); - hex2bin("48fd17affa76b23e6fb2257df30374da839d6cb264656a82e34b350722b05123", merkles[10], 32); - hex2bin("c4f5ab01913fc186d550c1a28f3f3e9ffaca2016b961a6a751f8cca0089df924", merkles[11], 32); - hex2bin("cff737e1d00176dd6bbfa73071adbb370f227cfb5fba186562e4060fcec877e1", merkles[12], 32); - - uint8_t merkle_root[32]; - calculate_merkle_root_hash(coinbase_tx_hash, merkles, num_merkles, merkle_root); - - bm_job base_job = {0}; - construct_bm_job(¬ify_message, merkle_root, 0x1fffe000, 1000000, &base_job); - bm_job * job = NULL; - Thermal_set_fan_percent(&GLOBAL_STATE->DEVICE_CONFIG, 1); - ESP_LOGI(TAG, "Sending work"); - - //(*GLOBAL_STATE->ASIC_functions.send_work_fn)(GLOBAL_STATE, &job); - job = calloc(1, sizeof(bm_job)); - if (job == NULL) { - ESP_LOGE(TAG, "Failed to allocate job"); - tests_done(GLOBAL_STATE, false); - } - memcpy(job, &base_job, sizeof(bm_job)); - ASIC_send_work(GLOBAL_STATE, job); - bm_job * current_job = job; - float asic_temp = Thermal_get_chip_temp(GLOBAL_STATE); - ESP_LOGI(TAG, "ASIC Temp %f", asic_temp); + ESP_LOGI(TAG, "ASIC Temp %.1f°C", asic_temp); - // detect open circiut / no result + // detect open circuit / no result if (asic_temp == -1.0 || asic_temp == 127.0) { - snprintf(logString, sizeof(logString), "TEMP:FAIL :%.0f", asic_temp); - display_msg(logString, GLOBAL_STATE); + ESP_LOGE(TAG, "Open circuit or no result on temperature sensor: %.1f°C", asic_temp); + snprintf(logString, sizeof(logString), "TEMP:FAIL: %.1f°C", asic_temp); + self_test_show_message(GLOBAL_STATE, logString); tests_done(GLOBAL_STATE, false); } - Thermal_set_fan_percent(&GLOBAL_STATE->DEVICE_CONFIG, 0.1f); while (asic_temp < 40.0f) { - snprintf(logString, sizeof(logString), - "ASIC temp > 40°C: %.2f°C\r\n", - asic_temp); - display_msg(logString, GLOBAL_STATE); vTaskDelay(500 / portTICK_PERIOD_MS); asic_temp = Thermal_get_chip_temp(GLOBAL_STATE); + ESP_LOGI(TAG, "Warming up: %.1f°C", asic_temp); + snprintf(logString, sizeof(logString), "ASIC Temp: %.1f°C", asic_temp); + self_test_show_message(GLOBAL_STATE, logString); } Thermal_set_fan_percent(&GLOBAL_STATE->DEVICE_CONFIG, 1.0f); - uint32_t start_ms = esp_timer_get_time() / 1000; - uint32_t duration_ms = 0; - uint32_t counter = 0; - float hashrate = 0; uint32_t hashtest_ms = 30000; - uint32_t last_job_duration = 0; - - int asic_count = GLOBAL_STATE->DEVICE_CONFIG.family.asic_count; - int hash_domains = GLOBAL_STATE->DEVICE_CONFIG.family.asic.hash_domains; + float hashrate = 0; - measurement_t** domain_measurements = heap_caps_malloc(asic_count * sizeof(measurement_t*), MALLOC_CAP_SPIRAM); - measurement_t* data = heap_caps_malloc(asic_count * hash_domains * sizeof(measurement_t), MALLOC_CAP_SPIRAM); - for (size_t asic_nr = 0; asic_nr < asic_count; asic_nr++) { - domain_measurements[asic_nr] = data + (asic_nr * hash_domains); - } - measurement_t* total_measurement = heap_caps_malloc(asic_count * sizeof(measurement_t), MALLOC_CAP_SPIRAM); - measurement_t* error_measurement = heap_caps_malloc(asic_count * sizeof(measurement_t), MALLOC_CAP_SPIRAM); - - memset(total_measurement, 0, asic_count * sizeof(measurement_t)); - memset(domain_measurements[0], 0, asic_count * hash_domains * sizeof(measurement_t)); - memset(error_measurement, 0, asic_count * sizeof(measurement_t)); - - uint32_t last_register_read_ms = 0; - while (duration_ms < hashtest_ms) { - uint32_t now_ms = esp_timer_get_time() / 1000; - if (now_ms - last_register_read_ms >= 1000) { - ASIC_read_registers(GLOBAL_STATE); - last_register_read_ms = now_ms; + ESP_LOGI(TAG, "Starting 30s hashrate monitoring loop"); + while ((esp_timer_get_time() / 1000) - start_ms < hashtest_ms) { + hashrate = GLOBAL_STATE->SYSTEM_MODULE.current_hashrate; + asic_temp = Thermal_get_chip_temp(GLOBAL_STATE); + + if (asic_temp > 62) { + ESP_LOGE(TAG, "Overheat: %.1f°C", asic_temp); + snprintf(logString, sizeof(logString), "TEMP:FAIL: %.1f°C", asic_temp); + self_test_show_message(GLOBAL_STATE, logString); + tests_done(GLOBAL_STATE, false); } - task_result * asic_result = ASIC_process_work(GLOBAL_STATE); - if (asic_result != NULL) { - uint64_t time_us = esp_timer_get_time(); - if (asic_result->register_type != REGISTER_INVALID) { - switch(asic_result->register_type) { - case REGISTER_HASHRATE: - update_hashrate(&total_measurement[asic_result->asic_nr], asic_result->value); - update_hashrate(&domain_measurements[asic_result->asic_nr][0], asic_result->value); - break; - case REGISTER_TOTAL_COUNT: - update_hash_counter(&total_measurement[asic_result->asic_nr], asic_result->value, time_us); - break; - case REGISTER_DOMAIN_0_COUNT: - update_hash_counter(&domain_measurements[asic_result->asic_nr][0], asic_result->value, time_us); - break; - case REGISTER_DOMAIN_1_COUNT: - update_hash_counter(&domain_measurements[asic_result->asic_nr][1], asic_result->value, time_us); - break; - case REGISTER_DOMAIN_2_COUNT: - update_hash_counter(&domain_measurements[asic_result->asic_nr][2], asic_result->value, time_us); - break; - case REGISTER_DOMAIN_3_COUNT: - update_hash_counter(&domain_measurements[asic_result->asic_nr][3], asic_result->value, time_us); - break; - case REGISTER_ERROR_COUNT: - update_hash_counter(&error_measurement[asic_result->asic_nr], asic_result->value, time_us); - break; - case REGISTER_PLL_PARAM: - ESP_LOGD(TAG, "PLL param read asic %d: 0x%08" PRIX32, asic_result->asic_nr, asic_result->value); - break; - case REGISTER_INVALID: - break; - } - continue; - } + uint32_t remaining = (hashtest_ms - ((esp_timer_get_time() / 1000) - start_ms)) / 1000; + snprintf(logString, sizeof(logString), "%.0f Gh/s %.1f°C %lds", hashrate, asic_temp, remaining); + ESP_LOGI(TAG, "%s", logString); - // check the nonce difficulty - double nonce_diff = test_nonce_value(current_job, asic_result->nonce, asic_result->rolled_version); - if (nonce_diff >= DIFFICULTY) { - counter += DIFFICULTY; - duration_ms = (esp_timer_get_time() / 1000) - start_ms; - hashrate = hashCounterToGhs(duration_ms * 1000, counter); - - ESP_LOGI(TAG, "Nonce %lu Nonce difficulty %.32f.", asic_result->nonce, nonce_diff); - ESP_LOGI(TAG, "%f Gh/s , duration %dms", hashrate, duration_ms); - - if (duration_ms - last_job_duration > 1000) { - // resend job every second to keep asics busy - base_job.ntime++; - bm_job * resend_job = calloc(1, sizeof(bm_job)); - if (resend_job != NULL) { - memcpy(resend_job, &base_job, sizeof(bm_job)); - ASIC_send_work(GLOBAL_STATE, resend_job); - current_job = resend_job; - } else { - ESP_LOGE(TAG, "Failed to allocate resend job"); - } - last_job_duration = duration_ms; - asic_temp = Thermal_get_chip_temp(GLOBAL_STATE); - if (asic_temp > 62) { - snprintf(logString, sizeof(logString), "TEMP:FAIL :%.0f", asic_temp); - display_msg(logString, GLOBAL_STATE); - tests_done(GLOBAL_STATE, false); - } - snprintf(logString, sizeof(logString), "%.0fGH/s %.0fC", hashrate, asic_temp); - display_msg(logString, GLOBAL_STATE); - } - } - } - } + self_test_show_message(GLOBAL_STATE, logString); - vTaskDelay(10 / portTICK_PERIOD_MS); + vTaskDelay(1000 / portTICK_PERIOD_MS); + } float expected_hashrate_mhs = GLOBAL_STATE->POWER_MANAGEMENT_MODULE.frequency_value * GLOBAL_STATE->DEVICE_CONFIG.family.asic.small_core_count * @@ -609,45 +363,38 @@ bool self_test(void * pvParameters) ESP_LOGI(TAG, "Hashrate: %.2f Gh/s, Expected: %.2f Gh/s", hashrate, expected_hashrate_mhs); - snprintf(logString, sizeof(logString), "%.0fGH/s ", hashrate); - display_msg(logString, GLOBAL_STATE); if (hashrate < expected_hashrate_mhs) { - display_msg("HASHRATE:FAIL", GLOBAL_STATE); + ESP_LOGE(TAG, "Total hashrate too low"); + self_test_show_message(GLOBAL_STATE, "HASHRATE:FAIL"); tests_done(GLOBAL_STATE, false); } - //Check to make sure all domains are contributing to the hashrate + // Check domain hashrates from monitor module + HashrateMonitorModule * monitor = &GLOBAL_STATE->HASHRATE_MONITOR_MODULE; for (int asic_nr = 0; asic_nr < GLOBAL_STATE->DEVICE_CONFIG.family.asic_count; asic_nr++) { int hash_domains = GLOBAL_STATE->DEVICE_CONFIG.family.asic.hash_domains; for (int domain_nr = 0; domain_nr < hash_domains; domain_nr++) { - float domain_hashrate = domain_measurements[asic_nr][domain_nr].hashrate; - ESP_LOGI(TAG, "AIC %d Domain %d Hashrate: %.2f Gh/s", asic_nr, domain_nr, domain_hashrate); - // divide by 3 because there can be a large variance in hashrate between domains. Just an alive check + float domain_hashrate = monitor->domain_measurements[asic_nr][domain_nr].hashrate; + ESP_LOGI(TAG, "ASIC %d Domain %d Hashrate: %.2f Gh/s", asic_nr, domain_nr, domain_hashrate); + float expected_domain_hashrate = expected_hashrate_mhs / hash_domains / GLOBAL_STATE->DEVICE_CONFIG.family.asic_count; if(domain_hashrate < expected_domain_hashrate / 3 || domain_hashrate > expected_domain_hashrate * 3) { ESP_LOGE(TAG, "ASIC %d Domain %d:FAIL - hashrate %.2f Gh/s, expected ~%.2f Gh/s", asic_nr, domain_nr, domain_hashrate, expected_domain_hashrate); char error_buf[30]; snprintf(error_buf, 30, "ASIC %d DOMAIN %d:FAIL", asic_nr, domain_nr); - display_msg(error_buf, GLOBAL_STATE); + self_test_show_message(GLOBAL_STATE, error_buf); tests_done(GLOBAL_STATE, false); } } } - if (current_job != NULL) { - free_bm_job(current_job); - } - free(GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs); - free(GLOBAL_STATE->valid_jobs); - if (test_core_voltage(GLOBAL_STATE) != ESP_OK) { tests_done(GLOBAL_STATE, false); } - // TODO: Maybe make a test equivalent for test values if (test_power_consumption(GLOBAL_STATE) != ESP_OK) { ESP_LOGE(TAG, "Power Draw Failed, target %.2f W", (float) GLOBAL_STATE->DEVICE_CONFIG.power_consumption_target); - display_msg("POWER:FAIL", GLOBAL_STATE); + self_test_show_message(GLOBAL_STATE, "POWER:FAIL"); tests_done(GLOBAL_STATE, false); } @@ -657,13 +404,16 @@ bool self_test(void * pvParameters) } tests_done(GLOBAL_STATE, true); - - return true; } +/** + * Ends the self test by either resetting or ending the self_test_task + */ static void tests_done(GlobalState * GLOBAL_STATE, bool isTestPassed) { + GLOBAL_STATE->SELF_TEST_MODULE.is_finished = true; VCORE_set_voltage(GLOBAL_STATE, 0.0f); + asic_hold_reset_low(); if (isTestPassed) { if (isFactoryTest) { @@ -673,7 +423,6 @@ static void tests_done(GlobalState * GLOBAL_STATE, bool isTestPassed) ESP_LOGI(TAG, "SELF-TEST PASS! -- Restarting in 10 seconds."); GLOBAL_STATE->SELF_TEST_MODULE.result = "SELF-TEST PASS!"; GLOBAL_STATE->SELF_TEST_MODULE.finished = "Restarting in 10 seconds."; - GLOBAL_STATE->SELF_TEST_MODULE.is_finished = true; vTaskDelay(10000 / portTICK_PERIOD_MS); esp_restart(); } else { @@ -685,7 +434,6 @@ static void tests_done(GlobalState * GLOBAL_STATE, bool isTestPassed) "SELF-TEST FAIL! -- Hold BOOT button for 2 seconds to cancel self-test, or press RESET to run self-test again."); GLOBAL_STATE->SELF_TEST_MODULE.finished = "Hold BOOT button for 2 seconds to cancel self-test, or press RESET to run self-test again."; - GLOBAL_STATE->SELF_TEST_MODULE.is_finished = true; } else { ESP_LOGI(TAG, "SELF-TEST FAIL -- Press RESET button to restart."); GLOBAL_STATE->SELF_TEST_MODULE.finished = "Press RESET button to restart."; @@ -701,5 +449,6 @@ static void tests_done(GlobalState * GLOBAL_STATE, bool isTestPassed) } } } - GLOBAL_STATE->SELF_TEST_MODULE.is_finished = true; + + vTaskDelete(NULL); } diff --git a/main/self_test/self_test.h b/main/self_test/self_test.h index 17f0f383c..62c6b1941 100644 --- a/main/self_test/self_test.h +++ b/main/self_test/self_test.h @@ -1,6 +1,11 @@ #ifndef SELF_TEST_H_ #define SELF_TEST_H_ -bool self_test(void * pvParameters); +#include "esp_err.h" + +esp_err_t self_test_init(void * pvParameters); +void self_test_task(void * pvParameters); +void self_test_show_message(void * pvParameters, char * msg); +void self_test_reset(void); #endif diff --git a/main/system.c b/main/system.c index d0b36770a..0f3c8bb54 100644 --- a/main/system.c +++ b/main/system.c @@ -30,6 +30,8 @@ #include "vcore.h" #include "thermal.h" #include "utils.h" +#include "self_test.h" +#include "filesystem.h" static const char * TAG = "system"; @@ -161,24 +163,78 @@ void SYSTEM_init_versions(GlobalState * GLOBAL_STATE) { } esp_err_t SYSTEM_init_peripherals(GlobalState * GLOBAL_STATE) { - - ESP_RETURN_ON_ERROR(gpio_install_isr_service(0), TAG, "Error installing ISR service"); + esp_err_t ret = gpio_install_isr_service(0); + if (ret != ESP_OK) { + self_test_show_message(GLOBAL_STATE, "ISR:FAIL"); + ESP_LOGE(TAG, "Error installing ISR service"); + return ret; + } - // Initialize the core voltage regulator - ESP_RETURN_ON_ERROR(VCORE_init(GLOBAL_STATE), TAG, "VCORE init failed!"); + ret = display_init(GLOBAL_STATE); + if (ret != ESP_OK) { + self_test_show_message(GLOBAL_STATE, "DISPLAY:FAIL"); + ESP_LOGE(TAG, "Display init failed"); + return ret; + } - ESP_RETURN_ON_ERROR(Thermal_init(&GLOBAL_STATE->DEVICE_CONFIG), TAG, "Thermal init failed!"); + if (!GLOBAL_STATE->SELF_TEST_MODULE.is_active) { + ret = input_init(screen_button_press, toggle_wifi_softap); + } else { + ret = input_init(NULL, self_test_reset); + } + if (ret != ESP_OK) { + self_test_show_message(GLOBAL_STATE, "INPUT:FAIL"); + ESP_LOGE(TAG, "Input init failed"); + return ret; + } - vTaskDelay(500 / portTICK_PERIOD_MS); + ret = screen_start(GLOBAL_STATE); + if (ret != ESP_OK) { + self_test_show_message(GLOBAL_STATE, "SCREEN:FAIL"); + ESP_LOGE(TAG, "Screen start failed"); + return ret; + } - // Ensure overheat_mode config exists - ESP_RETURN_ON_ERROR(ensure_overheat_mode_config(), TAG, "Failed to ensure overheat_mode config"); + ret = ensure_overheat_mode_config(); + if (ret != ESP_OK) { + self_test_show_message(GLOBAL_STATE, "CONFIG:FAIL"); + ESP_LOGE(TAG, "Failed to ensure overheat_mode config"); + return ret; + } - ESP_RETURN_ON_ERROR(display_init(GLOBAL_STATE), TAG, "Display init failed!"); + ret = filesystem_init(GLOBAL_STATE); + if (ret != ESP_OK) { + self_test_show_message(GLOBAL_STATE, "FILESYS:FAIL"); + ESP_LOGE(TAG, "Filesystem init failed"); + return ret; + } + + // Initialize the core voltage regulator + ret = VCORE_init(GLOBAL_STATE); + if (ret != ESP_OK) { + self_test_show_message(GLOBAL_STATE, "VCORE:FAIL"); + ESP_LOGE(TAG, "VCORE init failed"); + return ret; + } - ESP_RETURN_ON_ERROR(input_init(screen_button_press, toggle_wifi_softap), TAG, "Input init failed!"); + // For self-test, we set a stable known voltage before ASIC initialization + if (GLOBAL_STATE->SELF_TEST_MODULE.is_active) { + vTaskDelay(500 / portTICK_PERIOD_MS); - ESP_RETURN_ON_ERROR(screen_start(GLOBAL_STATE), TAG, "Screen start failed!"); + ret = VCORE_set_voltage(GLOBAL_STATE, 1.150); + if (ret != ESP_OK) { + self_test_show_message(GLOBAL_STATE, "VCORE:FAIL"); + ESP_LOGE(TAG, "VCORE set failed"); + return ret; + } + } + + ret = Thermal_init(&GLOBAL_STATE->DEVICE_CONFIG); + if (ret != ESP_OK) { + self_test_show_message(GLOBAL_STATE, "THERMAL:FAIL"); + ESP_LOGE(TAG, "Thermal init failed"); + return ret; + } return ESP_OK; } @@ -266,7 +322,7 @@ void SYSTEM_notify_found_nonce(GlobalState * GLOBAL_STATE, double diff, uint8_t // make the best_nonce_diff into a string suffixString((uint64_t) diff, module->best_diff_string, DIFF_STRING_SIZE, 0); - ESP_LOGI(TAG, "Network diff: %f", network_diff); + ESP_LOGI(TAG, "New best difficulty: %s", module->best_diff_string); } static esp_err_t ensure_overheat_mode_config() { diff --git a/main/tasks/asic_result_task.c b/main/tasks/asic_result_task.c index 5e097180e..e2477f75e 100644 --- a/main/tasks/asic_result_task.c +++ b/main/tasks/asic_result_task.c @@ -53,6 +53,8 @@ void ASIC_result_task(void *pvParameters) //log the ASIC response ESP_LOGI(TAG, "ID: %s, ASIC nr: %d, ver: %08" PRIX32 " Nonce %08" PRIX32 " diff %.1f of %ld.", active_job->jobid, asic_result->asic_nr, asic_result->rolled_version, asic_result->nonce, nonce_diff, active_job->pool_diff); + if (GLOBAL_STATE->SELF_TEST_MODULE.is_active) continue; + if (nonce_diff >= active_job->pool_diff) { char * user = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_user : GLOBAL_STATE->SYSTEM_MODULE.pool_user; diff --git a/main/tasks/power_management_task.c b/main/tasks/power_management_task.c index 77ef7b3e3..a2d14fc33 100644 --- a/main/tasks/power_management_task.c +++ b/main/tasks/power_management_task.c @@ -24,7 +24,6 @@ #define MAX_TEMP 90.0 #define THROTTLE_TEMP 75.0 #define SAFE_TEMP 45.0 -#define THROTTLE_TEMP_RANGE (MAX_TEMP - THROTTLE_TEMP) #define VOLTAGE_START_THROTTLE 4900 #define VOLTAGE_MIN_THROTTLE 3500 @@ -76,6 +75,12 @@ void POWER_MANAGEMENT_task(void * pvParameters) float last_known_asic_frequency = 0.0; while (1) { + if (GLOBAL_STATE->SELF_TEST_MODULE.is_finished) { + ESP_LOGI(TAG, "Stopped"); + vTaskDelete(NULL); + return; + } + power_management->voltage = Power_get_input_voltage(GLOBAL_STATE); power_management->power = Power_get_power(GLOBAL_STATE); power_management->current = Power_get_current(GLOBAL_STATE); @@ -125,7 +130,7 @@ void POWER_MANAGEMENT_task(void * pvParameters) if (asic_temp_valid) { power_management->chip_temp_avg = Thermal_get_chip_temp(GLOBAL_STATE); power_management->chip_temp2_avg = Thermal_get_chip_temp2(GLOBAL_STATE); - ESP_LOGW(TAG, "Safe mode active (cycle %d) - VR: %.1fC ASIC1: %.1fC ASIC2: %.1fC", + ESP_LOGW(TAG, "Safe mode active (cycle %d) - VR: %.1f°C ASIC1: %.1f°C ASIC2: %.1f°C", cooling_cycles, power_management->vr_temp, power_management->chip_temp_avg, power_management->chip_temp2_avg); // Continue if ASIC temps still too high @@ -134,7 +139,7 @@ void POWER_MANAGEMENT_task(void * pvParameters) } } else { // For boards using ASIC thermal diode (600 series), rely on VR temp and time - ESP_LOGW(TAG, "Safe mode active (cycle %d/%d) - VR: %.1fC (ASIC temps unavailable while powered down)", + ESP_LOGW(TAG, "Safe mode active (cycle %d/%d) - VR: %.1f°C (ASIC temps unavailable while powered down)", cooling_cycles, MIN_COOLING_CYCLES, power_management->vr_temp); } }