diff --git a/src/drivers/nerd-nos/bm1397.cpp b/src/drivers/nerd-nos/bm1397.cpp index 4f2fffa..5c2c45a 100644 --- a/src/drivers/nerd-nos/bm1397.cpp +++ b/src/drivers/nerd-nos/bm1397.cpp @@ -48,9 +48,6 @@ typedef struct __attribute__((__packed__)) static const char *TAG = "bm1397Module"; -static uint8_t asic_response_buffer[CHUNK_SIZE]; -static task_result result; - uint32_t increment_bitmask(const uint32_t value, const uint32_t mask); /// @brief @@ -195,7 +192,7 @@ void BM1397_send_hash_frequency(float frequency) vTaskDelay(10 / portTICK_PERIOD_MS); - ESP_LOGI(TAG, "Setting Frequency to %.2fMHz (%.2f)", frequency, newf); + Serial.printf("Setting Frequency to %.2fMHz (%.2f)\n", frequency, newf); } @@ -203,18 +200,19 @@ static uint8_t _send_init(uint64_t frequency, uint16_t asic_count) { // send the init command _send_read_address(); + uint8_t buf[11] = {0}; int chip_counter = 0; while (true) { - int received = SERIAL_rx(asic_response_buffer, 11, 1000); + int received = SERIAL_rx(buf, 11, 1000); if (received > 0) { - ESP_LOG_BUFFER_HEX(TAG, asic_response_buffer, received); + //ESP_LOG_BUFFER_HEX(TAG, asic_response_buffer, received); chip_counter++; } else { break; } } - ESP_LOGI(TAG, "%i chip(s) detected on the chain, expected %i", chip_counter, asic_count); + Serial.printf("%i chip(s) detected on the chain, expected %i\n", chip_counter, asic_count); // send serial data vTaskDelay(SLEEP_TIME / portTICK_PERIOD_MS); @@ -269,9 +267,7 @@ static void _reset(void) uint8_t BM1397_init(uint64_t frequency, uint16_t asic_count) { - ESP_LOGI(TAG, "Initializing BM1397"); - - memset(asic_response_buffer, 0, sizeof(asic_response_buffer)); + Serial.println("Initializing BM1397"); gpio_set_direction(NERD_NOS_GPIO_PEN, GPIO_MODE_OUTPUT); gpio_set_level(NERD_NOS_GPIO_PEN, 1); @@ -299,7 +295,7 @@ int BM1397_set_default_baud(void) int BM1397_set_max_baud(void) { // divider of 0 for 3,125,000 - ESP_LOGI(TAG, "Setting max baud of 3125000"); + Serial.println("Setting max baud of 3125000"); unsigned char baudrate[9] = {0x00, MISC_CONTROL, 0x00, 0x00, 0b01100000, 0b00110001}; ; // baudrate - misc_control _send_BM1397((TYPE_CMD | GROUP_ALL | CMD_WRITE), baudrate, 6, BM1397_SERIALTX_DEBUG); @@ -330,7 +326,7 @@ void BM1397_set_job_difficulty_mask(int difficulty) job_difficulty_mask[5 - i] = reverse_bits(value); } - ESP_LOGI(TAG, "Setting job ASIC mask to %d", difficulty); + Serial.printf("Setting job ASIC mask to %d\n", difficulty); _send_BM1397((TYPE_CMD | GROUP_ALL | CMD_WRITE), job_difficulty_mask, 6, BM1397_SERIALTX_DEBUG); } @@ -361,45 +357,47 @@ void BM1397_send_work(bm_job_t *next_bm_job, uint8_t job_id) _send_BM1397((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), (uint8_t*) &job, sizeof(job_packet_t), BM1397_DEBUG_WORK); } -asic_result *BM1397_receive_work(uint16_t timeout) +bool BM1397_receive_work(uint16_t timeout, asic_result *result) { + uint8_t *rcv_buf = (uint8_t*) result; // wait for a response, wait time is pretty arbitrary - int received = SERIAL_rx(asic_response_buffer, 9, timeout); + int received = SERIAL_rx(rcv_buf, 9, timeout); if (received < 0) { - ESP_LOGI(TAG, "Error in serial RX"); - return NULL; + Serial.println("Error in serial RX"); + return false; } else if (received == 0) { // Didn't find a solution, restart and try again - return NULL; + return false; } - if (received != 9 || asic_response_buffer[0] != 0xAA || asic_response_buffer[1] != 0x55) + if (received != 9 || rcv_buf[0] != 0xAA || rcv_buf[1] != 0x55) { - ESP_LOGI(TAG, "Serial RX invalid %i", received); - ESP_LOG_BUFFER_HEX(TAG, asic_response_buffer, received); - return NULL; + Serial.println("Serial RX invalid. Resetting receive buffer ..."); + //ESP_LOG_BUFFER_HEX(TAG, asic_response_buffer, received); + SERIAL_clear_buffer(); + return false; } + return true; - return (asic_result *)asic_response_buffer; } -task_result *BM1397_proccess_work(uint32_t version, uint16_t timeout) +bool BM1397_proccess_work(uint32_t version, uint16_t timeout, task_result *result) { - asic_result *asic_result = BM1397_receive_work(timeout); + asic_result asic_result; - if (asic_result == NULL) + if (!BM1397_receive_work(timeout, &asic_result)) { ESP_LOGI(TAG, "return null"); - return NULL; + return false; } - uint8_t rx_job_id = (asic_result->job_id & 0xfc) >> 2; - uint8_t rx_midstate_index = asic_result->job_id & 0x03; + uint8_t rx_job_id = (asic_result.job_id & 0xfc) >> 2; + uint8_t rx_midstate_index = asic_result.job_id & 0x03; uint32_t rolled_version = version; for (int i = 0; i < rx_midstate_index; i++) @@ -407,10 +405,10 @@ task_result *BM1397_proccess_work(uint32_t version, uint16_t timeout) rolled_version = increment_bitmask(rolled_version, 0x1fffe000); } - result.job_id = rx_job_id; - result.nonce = asic_result->nonce; - result.rolled_version = rolled_version; + result->job_id = rx_job_id; + result->nonce = asic_result.nonce; + result->rolled_version = rolled_version; - return &result; + return true; } diff --git a/src/drivers/nerd-nos/bm1397.h b/src/drivers/nerd-nos/bm1397.h index 743d140..02213e6 100644 --- a/src/drivers/nerd-nos/bm1397.h +++ b/src/drivers/nerd-nos/bm1397.h @@ -17,5 +17,5 @@ void BM1397_set_job_difficulty_mask(int); int BM1397_set_max_baud(void); int BM1397_set_default_baud(void); void BM1397_send_hash_frequency(float frequency); -task_result *BM1397_proccess_work(uint32_t version, uint16_t timeout); +bool BM1397_proccess_work(uint32_t version, uint16_t timeout, task_result *result); diff --git a/src/drivers/nerd-nos/mining.cpp b/src/drivers/nerd-nos/mining.cpp index 929b072..f24dc13 100644 --- a/src/drivers/nerd-nos/mining.cpp +++ b/src/drivers/nerd-nos/mining.cpp @@ -62,8 +62,9 @@ static void calculate_merkle_root_hash(const char *coinbase_tx, mining_job* job, double_sha256_bin(coinbase_tx_bin, coinbase_tx_bin_len, new_root); memcpy(both_merkles, new_root, 32); - for (size_t i = 0; i < job->merkle_branch.size(); i++) { - hex2bin((const char*) job->merkle_branch[i], &both_merkles[32], 32); + for (size_t i = 0; i < job->merkle_branch_size; i++) { + const char* m = job->merkle_branch[i].c_str(); + hex2bin(m, &both_merkles[32], 32); double_sha256_bin(both_merkles, 64, new_root); memcpy(both_merkles, new_root, 32); } @@ -140,8 +141,8 @@ void nerdnos_send_work(bm_job_t *next_bm_job, uint8_t job_id) { BM1397_send_work(next_bm_job, job_id); } -task_result *nerdnos_proccess_work(uint32_t version, uint16_t timeout) { - return BM1397_proccess_work(version, timeout); +bool nerdnos_proccess_work(uint32_t version, uint16_t timeout, task_result *result) { + return BM1397_proccess_work(version, timeout, result); } void nerdnos_free_bm_job(bm_job_t *job) { diff --git a/src/drivers/nerd-nos/mining.h b/src/drivers/nerd-nos/mining.h index 63098c9..fff9eaf 100644 --- a/src/drivers/nerd-nos/mining.h +++ b/src/drivers/nerd-nos/mining.h @@ -16,7 +16,7 @@ void nerdnos_create_job(mining_subscribe *mWorker, mining_job *job, bm_job_t *ne void nerdnos_send_work(bm_job_t *next_bm_job, uint8_t job_id); // receive and process responses -task_result *nerdnos_proccess_work(uint32_t version, uint16_t timeout); +bool nerdnos_proccess_work(uint32_t version, uint16_t timeout, task_result *result); // test difficulty double nerdnos_test_nonce_value(const bm_job_t *job, const uint32_t nonce, const uint32_t rolled_version, uint8_t hash_result[32]); diff --git a/src/drivers/nerd-nos/serial.cpp b/src/drivers/nerd-nos/serial.cpp index 7a88b2c..bbb56ff 100644 --- a/src/drivers/nerd-nos/serial.cpp +++ b/src/drivers/nerd-nos/serial.cpp @@ -51,8 +51,8 @@ int SERIAL_send(uint8_t *data, int len, bool debug) return uart_write_bytes(UART_NUM_1, (const char *)data, len); } -int SERIAL_check_for_data() { - int length; +size_t SERIAL_check_for_data() { + size_t length; uart_get_buffered_data_len(UART_NUM_1, (size_t*)&length); return length; } @@ -65,7 +65,9 @@ int SERIAL_check_for_data() { int16_t SERIAL_rx(uint8_t *buf, uint16_t size, uint16_t timeout_ms) { // don't return incomplete data - if (SERIAL_check_for_data() < size) { + size_t available = SERIAL_check_for_data(); + if (available && available < size) { + Serial.printf("not returning parts of data ... %d vs %d\n", (int) available, (int) size); return 0; } diff --git a/src/drivers/nerd-nos/utils.cpp b/src/drivers/nerd-nos/utils.cpp index 01a47e1..ce409d3 100644 --- a/src/drivers/nerd-nos/utils.cpp +++ b/src/drivers/nerd-nos/utils.cpp @@ -127,6 +127,24 @@ uint8_t hex2val(char c) } } +bool is_hex_digit(char c) { + return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); +} + +bool is_hex_string(const char* str) { + // Check if the string is exactly 64 characters long + if (strlen(str) != 64) { + return false; + } + // Check if each character is a valid hexadecimal digit + for (size_t i = 0; i < 64; i++) { + if (!is_hex_digit(str[i])) { + return false; + } + } + return true; +} + size_t hex2bin(const char *hex, uint8_t *bin, size_t bin_len) { size_t len = 0; diff --git a/src/drivers/nerd-nos/utils.h b/src/drivers/nerd-nos/utils.h index 78b6852..273a965 100644 --- a/src/drivers/nerd-nos/utils.h +++ b/src/drivers/nerd-nos/utils.h @@ -2,6 +2,7 @@ #include #include +#include int hex2char(uint8_t x, char *c); @@ -38,3 +39,6 @@ unsigned char reverse_bits(unsigned char num); int largest_power_of_two(int num); uint32_t increment_bitmask(const uint32_t value, const uint32_t mask); + +bool is_hex_digit(char c); +bool is_hex_string(const char* str); \ No newline at end of file diff --git a/src/mining_nerdnos.cpp b/src/mining_nerdnos.cpp index 181dfaa..38f815f 100644 --- a/src/mining_nerdnos.cpp +++ b/src/mining_nerdnos.cpp @@ -40,7 +40,7 @@ static bm_job_t asic_jobs[ASIC_JOB_COUNT] = {0}; typedef struct { uint32_t diffs[ASIC_HISTORY_SIZE]; - uint32_t timestamps[ASIC_HISTORY_SIZE]; + uint64_t timestamps[ASIC_HISTORY_SIZE]; uint32_t newest; uint32_t oldest; uint64_t sum; @@ -78,7 +78,7 @@ static void calculate_hashrate(history_t *history, uint32_t diff) { history->diffs[history->newest % ASIC_HISTORY_SIZE] = diff; // micros() wraps around after about 71.58min because it's 32bit casted from 64bit timer :facepalm: - history->timestamps[history->newest % ASIC_HISTORY_SIZE] = esp_timer_get_time(); + history->timestamps[history->newest % ASIC_HISTORY_SIZE] = (uint64_t) esp_timer_get_time(); uint64_t oldest_timestamp = history->timestamps[history->oldest % ASIC_HISTORY_SIZE]; uint64_t newest_timestamp = history->timestamps[history->newest % ASIC_HISTORY_SIZE]; @@ -172,15 +172,11 @@ void runASIC(void * task_id) { // send the job and nerdnos_send_work(&asic_jobs[asic_job_id], asic_job_id); - // the pointer returned is the RS232 receive buffer :shushing-face: - // but we only have a single thread so it should be okay - // process all results if we have more than one - // this is okay because serial uses a buffer and (most likely^^) DMA - task_result *result = NULL; - while ((result = nerdnos_proccess_work(version, 1)) != NULL) { + task_result result = {0}; + while (nerdnos_proccess_work(version, 1, &result)) { // check if the ID is in the valid range and the slot is not empty - if (result->job_id >= ASIC_JOB_COUNT || !asic_jobs[result->job_id].ntime) { - Serial.printf("Invalid job ID or no job found for ID %02x\n", result->job_id); + if (result.job_id >= ASIC_JOB_COUNT || !asic_jobs[result.job_id].ntime) { + Serial.printf("Invalid job ID or no job found for ID %02x\n", result.job_id); continue; } @@ -188,9 +184,9 @@ void runASIC(void * task_id) { // check the nonce difficulty double diff_hash = nerdnos_test_nonce_value( - &asic_jobs[result->job_id], - result->nonce, - result->rolled_version, + &asic_jobs[result.job_id], + result.nonce, + result.rolled_version, hash); // update best diff @@ -199,14 +195,14 @@ void runASIC(void * task_id) { } // calculate the hashrate - if (diff_hash >= asic_jobs[result->job_id].pool_diff) { - calculate_hashrate(&history, asic_jobs[result->job_id].pool_diff); + if (diff_hash >= asic_jobs[result.job_id].pool_diff) { + calculate_hashrate(&history, asic_jobs[result.job_id].pool_diff); Serial.printf("avg hashrate: %.2fGH/s (history spans %.2fs, %d shares)\n", history.avg_gh, history.duration, history.shares); } if(diff_hash > mMiner.poolDifficulty) { - tx_mining_submit_asic(client, mWorker, &asic_jobs[result->job_id], result); + tx_mining_submit_asic(client, mWorker, &asic_jobs[result.job_id], &result); Serial.println("valid share!"); Serial.printf(" - Current diff share: %.3f\n", diff_hash); Serial.printf(" - Current pool diff : %.3f\n", mMiner.poolDifficulty); diff --git a/src/monitor.cpp b/src/monitor.cpp index 3c1afbd..b0a613c 100644 --- a/src/monitor.cpp +++ b/src/monitor.cpp @@ -250,7 +250,7 @@ String getCurrentTemperature() { } String getCurrentVCore() { - return String(nerdnos_get_vcore(), 2); + return String(nerdnos_get_vcore(), 0); } #else String getCurrentHashRate(unsigned long mElapsed) @@ -263,7 +263,7 @@ String getCurrentTemperature() { } String getCurrentVCore() { - return String(0.0, 2); + return String(0.0, 0); } #endif diff --git a/src/stratum.cpp b/src/stratum.cpp index a5ec3ac..3b0fd33 100644 --- a/src/stratum.cpp +++ b/src/stratum.cpp @@ -188,7 +188,20 @@ bool parse_mining_notify(String line, mining_job& mJob) mJob.prev_block_hash = String((const char*) doc["params"][1]); mJob.coinb1 = String((const char*) doc["params"][2]); mJob.coinb2 = String((const char*) doc["params"][3]); - mJob.merkle_branch = doc["params"][4]; + + // this only copies references to the static json buffer + // and can lead to crashes when there is a new stratum response + // and the content of the array is still needed like on NerdNOS + // that computes the merkle tree new each 30ms^^ + //mJob.merkle_branch = doc["params"][4]; + + // This copies the merkle branch + JsonArray merkle_tree = doc["params"][4]; + mJob.merkle_branch_size = merkle_tree.size(); + for (size_t i = 0; i < mJob.merkle_branch_size; i++) { + mJob.merkle_branch[i] = String((const char*) merkle_tree[i]); + } + mJob.version = String((const char*) doc["params"][5]); mJob.nbits = String((const char*) doc["params"][6]); mJob.ntime = String((const char*) doc["params"][7]); diff --git a/src/stratum.h b/src/stratum.h index c0c2ff9..8d5abca 100644 --- a/src/stratum.h +++ b/src/stratum.h @@ -31,7 +31,8 @@ typedef struct mining_job { String coinb1; String coinb2; String nbits; - JsonArray merkle_branch; + String merkle_branch[MAX_MERKLE_BRANCHES]; + size_t merkle_branch_size; String version; uint32_t target; String ntime; diff --git a/src/utils.cpp b/src/utils.cpp index 20120be..1a6a95a 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -170,13 +170,13 @@ void getNextExtranonce2(int extranonce2_size, char *extranonce2) { } miner_data init_miner_data(void){ - + miner_data newMinerData; newMinerData.poolDifficulty = DEFAULT_DIFFICULTY; newMinerData.inRun = false; newMinerData.newJob = false; - + return newMinerData; } @@ -185,14 +185,14 @@ miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){ miner_data mMiner = init_miner_data(); // calculate target - target = (nbits[2:]+'00'*(int(nbits[:2],16) - 3)).zfill(64) - + char target[TARGET_BUFFER_SIZE+1]; memset(target, '0', TARGET_BUFFER_SIZE); int zeros = (int) strtol(mJob.nbits.substring(0, 2).c_str(), 0, 16) - 3; memcpy(target + zeros - 2, mJob.nbits.substring(2).c_str(), mJob.nbits.length() - 2); target[TARGET_BUFFER_SIZE] = 0; Serial.print(" target: "); Serial.println(target); - + // bytearray target size_t size_target = to_byte_array(target, 32, mMiner.bytearray_target); @@ -204,12 +204,12 @@ miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){ // get extranonce2 - extranonce2 = hex(random.randint(0,2**32-1))[2:].zfill(2*extranonce2_size) //To review - char extranonce2_char[2 * mWorker.extranonce2_size+1]; + char extranonce2_char[2 * mWorker.extranonce2_size+1]; mWorker.extranonce2.toCharArray(extranonce2_char, 2 * mWorker.extranonce2_size + 1); getNextExtranonce2(mWorker.extranonce2_size, extranonce2_char); mWorker.extranonce2 = String(extranonce2_char); //mWorker.extranonce2 = "00000002"; - + //get coinbase - coinbase_hash_bin = hashlib.sha256(hashlib.sha256(binascii.unhexlify(coinbase)).digest()).digest() String coinbase = mJob.coinb1 + mWorker.extranonce1 + mWorker.extranonce2 + mJob.coinb2; Serial.print(" coinbase: "); Serial.println(coinbase); @@ -229,10 +229,10 @@ miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){ mbedtls_sha256_context ctx; mbedtls_sha256_init(&ctx); - + byte interResult[32]; // 256 bit byte shaResult[32]; // 256 bit - + mbedtls_sha256_starts_ret(&ctx,0); mbedtls_sha256_update_ret(&ctx, bytearray, str_len); mbedtls_sha256_finish_ret(&ctx, interResult); @@ -249,13 +249,13 @@ miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){ Serial.println(""); #endif - + // copy coinbase hash memcpy(mMiner.merkle_result, shaResult, sizeof(shaResult)); - + byte merkle_concatenated[32 * 2]; - for (size_t k=0; k < mJob.merkle_branch.size(); k++) { - const char* merkle_element = (const char*) mJob.merkle_branch[k]; + for (size_t k=0; k < mJob.merkle_branch_size; k++) { + const char* merkle_element = (const char*) mJob.merkle_branch[k].c_str(); uint8_t bytearray[32]; size_t res = to_byte_array(merkle_element, 64, bytearray); @@ -294,7 +294,7 @@ miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){ #endif } // merkle root from merkle_result - + Serial.print(" merkle sha : "); char merkle_root[65]; for (int i = 0; i < 32; i++) { @@ -308,7 +308,7 @@ miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){ // j.block_header = ''.join([j.version, j.prevhash, merkle_root, j.ntime, j.nbits]) String blockheader = mJob.version + mJob.prev_block_hash + String(merkle_root) + mJob.ntime + mJob.nbits + "00000000"; str_len = blockheader.length()/2; - + //uint8_t bytearray_blockheader[str_len]; res = to_byte_array(blockheader.c_str(), str_len*2, mMiner.bytearray_blockheader); @@ -375,7 +375,7 @@ miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){ #ifdef DEBUG_MINING - Serial.print(" >>> bytearray_blockheader : "); + Serial.print(" >>> bytearray_blockheader : "); for (size_t i = 0; i < 4; i++) Serial.printf("%02x", mMiner.bytearray_blockheader[i]); Serial.println("");