nerdnos first working version
This commit is contained in:
parent
2043b09157
commit
62503f4af8
@ -131,7 +131,7 @@
|
|||||||
//#include <User_Setups/Setup204_ESP32_TouchDown.h> // Setup file for the ESP32 TouchDown based on ILI9488 480 x 320 TFT
|
//#include <User_Setups/Setup204_ESP32_TouchDown.h> // Setup file for the ESP32 TouchDown based on ILI9488 480 x 320 TFT
|
||||||
|
|
||||||
//#include <User_Setups/Setup205_ESP32_TouchDown_S3.h> // Setup file for the ESP32 TouchDown S3 based on ILI9488 480 x 320 TFT
|
//#include <User_Setups/Setup205_ESP32_TouchDown_S3.h> // Setup file for the ESP32 TouchDown S3 based on ILI9488 480 x 320 TFT
|
||||||
#ifdef NERDMINERV2
|
#if defined(NERDMINERV2) || defined(NERD_NOS)
|
||||||
#include <User_Setups/Setup206_LilyGo_T_Display_S3.h>
|
#include <User_Setups/Setup206_LilyGo_T_Display_S3.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef NERMINER_S3_AMOLED
|
#ifdef NERMINER_S3_AMOLED
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
[platformio]
|
[platformio]
|
||||||
globallib_dir = lib
|
globallib_dir = lib
|
||||||
|
|
||||||
default_envs = NerdminerV2-T-HMI, wt32-sc01, wt32-sc01-plus, han_m5stack, M5Stick-C, esp32cam, ESP32-2432S028R, ESP32_2432S028_2USB, NerminerV2, Lilygo-T-Embed, ESP32-devKitv1, NerminerV2-S3-DONGLE, NerminerV2-S3-GEEK, NerminerV2-S3-AMOLED, NerminerV2-S3-AMOLED-TOUCH, NerminerV2-T-QT, NerdminerV2-T-Display_V1, ESP32-2432S028R, M5-StampS3, ESP32-S3-devKitv1, ESP32-S3-mini-wemos, ESP32-S2-mini-wemos, ESP32-S3-mini-weact, ESP32-D0WD-V3-weact, ESP32-C3-devKitmv1, ESP32-C3-super-mini
|
#default_envs = NerdminerV2-T-HMI, wt32-sc01, wt32-sc01-plus, han_m5stack, M5Stick-C, esp32cam, ESP32-2432S028R, ESP32_2432S028_2USB, NerminerV2, Lilygo-T-Embed, ESP32-devKitv1, NerminerV2-S3-DONGLE, NerminerV2-S3-GEEK, NerminerV2-S3-AMOLED, NerminerV2-S3-AMOLED-TOUCH, NerminerV2-T-QT, NerdminerV2-T-Display_V1, ESP32-2432S028R, M5-StampS3, ESP32-S3-devKitv1, ESP32-S3-mini-wemos, ESP32-S2-mini-wemos, ESP32-S3-mini-weact, ESP32-D0WD-V3-weact, ESP32-C3-devKitmv1, ESP32-C3-super-mini
|
||||||
|
default_envs = NerdNOS
|
||||||
|
|
||||||
[env:M5Stick-C]
|
[env:M5Stick-C]
|
||||||
platform = espressif32@6.6.0
|
platform = espressif32@6.6.0
|
||||||
@ -393,6 +394,40 @@ lib_ignore =
|
|||||||
|
|
||||||
;--------------------------------------------------------------------
|
;--------------------------------------------------------------------
|
||||||
|
|
||||||
|
;--------------------------------------------------------------------
|
||||||
|
|
||||||
|
[env:NerdNOS]
|
||||||
|
platform = espressif32@6.6.0
|
||||||
|
board = esp32-s3-devkitc-1
|
||||||
|
framework = arduino
|
||||||
|
monitor_filters =
|
||||||
|
esp32_exception_decoder
|
||||||
|
time
|
||||||
|
log2file
|
||||||
|
board_build.arduino.memory_type = qio_opi
|
||||||
|
monitor_speed = 115200
|
||||||
|
upload_speed = 115200
|
||||||
|
# 2 x 4.5MB app, 6.875MB SPIFFS
|
||||||
|
;board_build.partitions = large_spiffs_16MB.csv
|
||||||
|
;board_build.partitions = default_8MB.csv
|
||||||
|
board_build.partitions = huge_app.csv
|
||||||
|
;board_build.partitions = default.csv
|
||||||
|
build_flags =
|
||||||
|
-D LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
-D BOARD_HAS_PSRAM
|
||||||
|
-D ARDUINO_USB_MODE=1
|
||||||
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
|
-D NERD_NOS=1
|
||||||
|
;-D DEBUG_MINING=1
|
||||||
|
lib_deps =
|
||||||
|
https://github.com/takkaO/OpenFontRender#v1.2
|
||||||
|
bblanchon/ArduinoJson@^6.21.5
|
||||||
|
https://github.com/tzapu/WiFiManager.git#v2.0.17
|
||||||
|
mathertel/OneButton@^2.5.0
|
||||||
|
arduino-libraries/NTPClient@^3.2.1
|
||||||
|
lib_ignore =
|
||||||
|
HANSOLOminerv2
|
||||||
|
|
||||||
[env:Lilygo-T-Embed]
|
[env:Lilygo-T-Embed]
|
||||||
platform = espressif32@6.6.0
|
platform = espressif32@6.6.0
|
||||||
board = esp32-s3-devkitc-1
|
board = esp32-s3-devkitc-1
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
#include "drivers/displays/display.h"
|
#include "drivers/displays/display.h"
|
||||||
#include "drivers/storage/SDCard.h"
|
#include "drivers/storage/SDCard.h"
|
||||||
#include "timeconst.h"
|
#include "timeconst.h"
|
||||||
|
#include "drivers/nerd-nos/bm1397.h"
|
||||||
|
#include "drivers/nerd-nos/serial.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef TOUCH_ENABLE
|
#ifdef TOUCH_ENABLE
|
||||||
#include "TouchHandler.h"
|
#include "TouchHandler.h"
|
||||||
@ -49,7 +52,13 @@ extern monitor_data mMonitor;
|
|||||||
unsigned long start = millis();
|
unsigned long start = millis();
|
||||||
const char* ntpServer = "pool.ntp.org";
|
const char* ntpServer = "pool.ntp.org";
|
||||||
|
|
||||||
//void runMonitor(void *name);
|
void printBufferHex(const char *prefix, const uint8_t* buf, size_t len) {
|
||||||
|
Serial.printf("%s: ", prefix);
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
Serial.printf("%02X ", buf[i]);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
/********* INIT *****/
|
/********* INIT *****/
|
||||||
void setup()
|
void setup()
|
||||||
@ -134,6 +143,18 @@ void setup()
|
|||||||
BaseType_t res2 = xTaskCreatePinnedToCore(runStratumWorker, "Stratum", 15000, (void*)name, 3, NULL,1);
|
BaseType_t res2 = xTaskCreatePinnedToCore(runStratumWorker, "Stratum", 15000, (void*)name, 3, NULL,1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NERD_NOS
|
||||||
|
SERIAL_init();
|
||||||
|
int chips = BM1397_init(200, 1);
|
||||||
|
Serial.printf("found bm1397: %d\n", chips);
|
||||||
|
//SERIAL_set_baud(BM1397_set_max_baud());
|
||||||
|
|
||||||
|
TaskHandle_t ASICTask = NULL;
|
||||||
|
xTaskCreate(runASIC, "Asic0", 6000, (void*)0, 1, &ASICTask);
|
||||||
|
|
||||||
|
//esp_task_wdt_add(ASICTask);
|
||||||
|
|
||||||
|
#else
|
||||||
/******** CREATE MINER TASKS *****/
|
/******** CREATE MINER TASKS *****/
|
||||||
//for (size_t i = 0; i < THREADS; i++) {
|
//for (size_t i = 0; i < THREADS; i++) {
|
||||||
// char *name = (char*) malloc(32);
|
// char *name = (char*) malloc(32);
|
||||||
@ -147,11 +168,13 @@ void setup()
|
|||||||
|
|
||||||
esp_task_wdt_add(minerTask1);
|
esp_task_wdt_add(minerTask1);
|
||||||
esp_task_wdt_add(minerTask2);
|
esp_task_wdt_add(minerTask2);
|
||||||
|
#endif
|
||||||
/******** MONITOR SETUP *****/
|
/******** MONITOR SETUP *****/
|
||||||
setup_monitor();
|
setup_monitor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void app_error_fault_handler(void *arg) {
|
void app_error_fault_handler(void *arg) {
|
||||||
// Get stack errors
|
// Get stack errors
|
||||||
char *stack = (char *)arg;
|
char *stack = (char *)arg;
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
struct nerdSHA256_context {
|
struct __attribute__((__packed__)) nerdSHA256_context {
|
||||||
uint8_t buffer[64];
|
uint8_t buffer[64];
|
||||||
uint32_t digest[8];
|
uint32_t digest[8];
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#if defined(NERDMINERV2)
|
#if defined(NERDMINERV2)
|
||||||
#include "nerdMinerV2.h"
|
#include "nerdMinerV2.h"
|
||||||
|
#elif defined(NERD_NOS)
|
||||||
|
#include "nerdnos.h"
|
||||||
#elif defined(M5STICK_C)
|
#elif defined(M5STICK_C)
|
||||||
#include "M5Stick-C.h"
|
#include "M5Stick-C.h"
|
||||||
#elif defined(DEVKITV1)
|
#elif defined(DEVKITV1)
|
||||||
|
16
src/drivers/devices/nerdnos.h
Normal file
16
src/drivers/devices/nerdnos.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef _NERD_MINER_V2_H
|
||||||
|
#define _NERD_MINER_V2_H
|
||||||
|
|
||||||
|
#define PIN_BUTTON_1 0
|
||||||
|
#define PIN_BUTTON_2 14
|
||||||
|
#define PIN_ENABLE5V 15
|
||||||
|
|
||||||
|
#define T_DISPLAY
|
||||||
|
|
||||||
|
#define NERD_NOS_GPIO_TX (GPIO_NUM_17)
|
||||||
|
#define NERD_NOS_GPIO_RX (GPIO_NUM_18)
|
||||||
|
#define NERD_NOS_GPIO_RST (GPIO_NUM_12)
|
||||||
|
#define NERD_NOS_GPIO_PEN (GPIO_NUM_13)
|
||||||
|
#define NERD_NOS_GPIO_TMP (GPIO_NUM_2)
|
||||||
|
|
||||||
|
#endif
|
448
src/drivers/nerd-nos/bm1397.cpp
Normal file
448
src/drivers/nerd-nos/bm1397.cpp
Normal file
@ -0,0 +1,448 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "bm1397.h"
|
||||||
|
#include "serial.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "../devices/device.h"
|
||||||
|
#include "crc.h"
|
||||||
|
|
||||||
|
#define TYPE_JOB 0x20
|
||||||
|
#define TYPE_CMD 0x40
|
||||||
|
|
||||||
|
#define GROUP_SINGLE 0x00
|
||||||
|
#define GROUP_ALL 0x10
|
||||||
|
|
||||||
|
#define CMD_JOB 0x01
|
||||||
|
|
||||||
|
#define CMD_SETADDRESS 0x00
|
||||||
|
#define CMD_WRITE 0x01
|
||||||
|
#define CMD_READ 0x02
|
||||||
|
#define CMD_INACTIVE 0x03
|
||||||
|
|
||||||
|
#define RESPONSE_CMD 0x00
|
||||||
|
#define RESPONSE_JOB 0x80
|
||||||
|
|
||||||
|
#define SLEEP_TIME 20
|
||||||
|
#define FREQ_MULT 25.0
|
||||||
|
|
||||||
|
#define CLOCK_ORDER_CONTROL_0 0x80
|
||||||
|
#define CLOCK_ORDER_CONTROL_1 0x84
|
||||||
|
#define ORDERED_CLOCK_ENABLE 0x20
|
||||||
|
#define CORE_REGISTER_CONTROL 0x3C
|
||||||
|
#define PLL3_PARAMETER 0x68
|
||||||
|
#define FAST_UART_CONFIGURATION 0x28
|
||||||
|
#define TICKET_MASK 0x14
|
||||||
|
#define MISC_CONTROL 0x18
|
||||||
|
|
||||||
|
typedef struct __attribute__((__packed__))
|
||||||
|
{
|
||||||
|
uint8_t preamble[2];
|
||||||
|
uint32_t nonce;
|
||||||
|
uint8_t midstate_num;
|
||||||
|
uint8_t job_id;
|
||||||
|
uint8_t crc;
|
||||||
|
} asic_result;
|
||||||
|
|
||||||
|
static const char *TAG = "bm1397Module";
|
||||||
|
|
||||||
|
static uint8_t asic_response_buffer[CHUNK_SIZE];
|
||||||
|
static uint32_t prev_nonce = 0;
|
||||||
|
static task_result result;
|
||||||
|
|
||||||
|
uint32_t increment_bitmask(const uint32_t value, const uint32_t mask);
|
||||||
|
|
||||||
|
/// @brief
|
||||||
|
/// @param ftdi
|
||||||
|
/// @param header
|
||||||
|
/// @param data
|
||||||
|
/// @param len
|
||||||
|
static void _send_BM1397(uint8_t header, uint8_t *data, uint8_t data_len, bool debug)
|
||||||
|
{
|
||||||
|
packet_type_t packet_type = (header & TYPE_JOB) ? JOB_PACKET : CMD_PACKET;
|
||||||
|
uint8_t total_length = (packet_type == JOB_PACKET) ? (data_len + 6) : (data_len + 5);
|
||||||
|
|
||||||
|
// allocate memory for buffer
|
||||||
|
unsigned char *buf = (unsigned char *)malloc(total_length);
|
||||||
|
|
||||||
|
// add the preamble
|
||||||
|
buf[0] = 0x55;
|
||||||
|
buf[1] = 0xAA;
|
||||||
|
|
||||||
|
// add the header field
|
||||||
|
buf[2] = header;
|
||||||
|
|
||||||
|
// add the length field
|
||||||
|
buf[3] = (packet_type == JOB_PACKET) ? (data_len + 4) : (data_len + 3);
|
||||||
|
|
||||||
|
// add the data
|
||||||
|
memcpy(buf + 4, data, data_len);
|
||||||
|
|
||||||
|
// add the correct crc type
|
||||||
|
if (packet_type == JOB_PACKET)
|
||||||
|
{
|
||||||
|
uint16_t crc16_total = crc16_false(buf + 2, data_len + 2);
|
||||||
|
buf[4 + data_len] = (crc16_total >> 8) & 0xFF;
|
||||||
|
buf[5 + data_len] = crc16_total & 0xFF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buf[4 + data_len] = crc5(buf + 2, data_len + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send serial data
|
||||||
|
SERIAL_send(buf, total_length, debug);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _send_read_address(void)
|
||||||
|
{
|
||||||
|
unsigned char read_address[2] = {0x00, 0x00};
|
||||||
|
// send serial data
|
||||||
|
_send_BM1397((TYPE_CMD | GROUP_ALL | CMD_READ), read_address, 2, BM1937_SERIALTX_DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _send_chain_inactive(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned char read_address[2] = {0x00, 0x00};
|
||||||
|
// send serial data
|
||||||
|
_send_BM1397((TYPE_CMD | GROUP_ALL | CMD_INACTIVE), read_address, 2, BM1937_SERIALTX_DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _set_chip_address(uint8_t chipAddr)
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned char read_address[2] = {chipAddr, 0x00};
|
||||||
|
// send serial data
|
||||||
|
_send_BM1397((TYPE_CMD | GROUP_SINGLE | CMD_SETADDRESS), read_address, 2, BM1937_SERIALTX_DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BM1397_send_hash_frequency(float frequency)
|
||||||
|
{
|
||||||
|
unsigned char prefreqall[] = {0x00, 0x70, 0x0F, 0x0F, 0x0F, 0x00};
|
||||||
|
|
||||||
|
// default 200Mhz if it fails
|
||||||
|
unsigned char freqbufall[] = {0x00, 0x08, 0x40, 0xF0, 0x02, 0x35};
|
||||||
|
|
||||||
|
float deffreq = 200.0;
|
||||||
|
|
||||||
|
float fa, fb, fc1, fc2, newf;
|
||||||
|
float f1, basef, famax = 0xf0, famin = 0x10;
|
||||||
|
uint16_t c;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// allow a frequency 'power down'
|
||||||
|
if (frequency == 0)
|
||||||
|
{
|
||||||
|
basef = fa = 0;
|
||||||
|
fb = fc1 = fc2 = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
f1 = frequency;
|
||||||
|
fb = 2; fc1 = 1; fc2 = 5; // initial multiplier of 10
|
||||||
|
if (f1 >= 500)
|
||||||
|
{
|
||||||
|
// halv down to '250-400'
|
||||||
|
fb = 1;
|
||||||
|
}
|
||||||
|
else if (f1 <= 150)
|
||||||
|
{
|
||||||
|
// triple up to '300-450'
|
||||||
|
fc1 = 3;
|
||||||
|
}
|
||||||
|
else if (f1 <= 250)
|
||||||
|
{
|
||||||
|
// double up to '300-500'
|
||||||
|
fc1 = 2;
|
||||||
|
}
|
||||||
|
// else f1 is 250-500
|
||||||
|
|
||||||
|
// f1 * fb * fc1 * fc2 is between 2500 and 5000
|
||||||
|
// - so round up to the next 25 (freq_mult)
|
||||||
|
basef = FREQ_MULT * ceil(f1 * fb * fc1 * fc2 / FREQ_MULT);
|
||||||
|
|
||||||
|
// fa should be between 100 (0x64) and 200 (0xC8)
|
||||||
|
fa = basef / FREQ_MULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// code failure ... basef isn't 400 to 6000
|
||||||
|
if (frequency != 0 && (fa < famin || fa > famax))
|
||||||
|
{
|
||||||
|
newf = deffreq;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
freqbufall[3] = (int)fa;
|
||||||
|
freqbufall[4] = (int)fb;
|
||||||
|
// fc1, fc2 'should' already be 1..15
|
||||||
|
freqbufall[5] = (((int)fc1 & 0xf) << 4) + ((int)fc2 & 0xf);
|
||||||
|
|
||||||
|
newf = basef / ((float)fb * (float)fc1 * (float)fc2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
|
_send_BM1397((TYPE_CMD | GROUP_ALL | CMD_WRITE), prefreqall, 6, BM1937_SERIALTX_DEBUG);
|
||||||
|
}
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
|
_send_BM1397((TYPE_CMD | GROUP_ALL | CMD_WRITE), freqbufall, 6, BM1937_SERIALTX_DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Setting Frequency to %.2fMHz (%.2f)", frequency, newf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t _send_init(uint64_t frequency, uint16_t asic_count)
|
||||||
|
{
|
||||||
|
// send the init command
|
||||||
|
_send_read_address();
|
||||||
|
|
||||||
|
int chip_counter = 0;
|
||||||
|
while (true) {
|
||||||
|
int received = SERIAL_rx(asic_response_buffer, 11, 1000);
|
||||||
|
if (received > 0) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
// send serial data
|
||||||
|
vTaskDelay(SLEEP_TIME / portTICK_PERIOD_MS);
|
||||||
|
_send_chain_inactive();
|
||||||
|
|
||||||
|
// split the chip address space evenly
|
||||||
|
for (uint8_t i = 0; i < asic_count; i++) {
|
||||||
|
_set_chip_address(i * (256 / asic_count));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char init[6] = {0x00, CLOCK_ORDER_CONTROL_0, 0x00, 0x00, 0x00, 0x00}; // init1 - clock_order_control0
|
||||||
|
_send_BM1397((TYPE_CMD | GROUP_ALL | CMD_WRITE), init, 6, BM1937_SERIALTX_DEBUG);
|
||||||
|
|
||||||
|
unsigned char init2[6] = {0x00, CLOCK_ORDER_CONTROL_1, 0x00, 0x00, 0x00, 0x00}; // init2 - clock_order_control1
|
||||||
|
_send_BM1397((TYPE_CMD | GROUP_ALL | CMD_WRITE), init2, 6, BM1937_SERIALTX_DEBUG);
|
||||||
|
|
||||||
|
unsigned char init3[9] = {0x00, ORDERED_CLOCK_ENABLE, 0x00, 0x00, 0x00, 0x01}; // init3 - ordered_clock_enable
|
||||||
|
_send_BM1397((TYPE_CMD | GROUP_ALL | CMD_WRITE), init3, 6, BM1937_SERIALTX_DEBUG);
|
||||||
|
|
||||||
|
unsigned char init4[9] = {0x00, CORE_REGISTER_CONTROL, 0x80, 0x00, 0x80, 0x74}; // init4 - init_4_?
|
||||||
|
_send_BM1397((TYPE_CMD | GROUP_ALL | CMD_WRITE), init4, 6, BM1937_SERIALTX_DEBUG);
|
||||||
|
|
||||||
|
BM1397_set_job_difficulty_mask(BM1397_INITIAL_DIFFICULTY);
|
||||||
|
|
||||||
|
unsigned char init5[9] = {0x00, PLL3_PARAMETER, 0xC0, 0x70, 0x01, 0x11}; // init5 - pll3_parameter
|
||||||
|
_send_BM1397((TYPE_CMD | GROUP_ALL | CMD_WRITE), init5, 6, BM1937_SERIALTX_DEBUG);
|
||||||
|
|
||||||
|
unsigned char init6[9] = {0x00, FAST_UART_CONFIGURATION, 0x06, 0x00, 0x00, 0x0F}; // init6 - fast_uart_configuration
|
||||||
|
_send_BM1397((TYPE_CMD | GROUP_ALL | CMD_WRITE), init6, 6, BM1937_SERIALTX_DEBUG);
|
||||||
|
|
||||||
|
BM1397_set_default_baud();
|
||||||
|
|
||||||
|
BM1397_send_hash_frequency(frequency);
|
||||||
|
|
||||||
|
return chip_counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset the BM1397 via the RTS line
|
||||||
|
static void _reset(void)
|
||||||
|
{
|
||||||
|
gpio_set_level(NERD_NOS_GPIO_RST, 1);
|
||||||
|
|
||||||
|
// delay for 100ms
|
||||||
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
// set the gpio pin high
|
||||||
|
gpio_set_level(NERD_NOS_GPIO_RST, 0);
|
||||||
|
|
||||||
|
// delay for 100ms
|
||||||
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
gpio_set_direction(NERD_NOS_GPIO_PEN, GPIO_MODE_OUTPUT);
|
||||||
|
gpio_set_level(NERD_NOS_GPIO_PEN, 1);
|
||||||
|
|
||||||
|
//esp_rom_gpio_pad_select_gpio(BM1397_RST_PIN);
|
||||||
|
gpio_pad_select_gpio(NERD_NOS_GPIO_RST);
|
||||||
|
gpio_set_direction(NERD_NOS_GPIO_RST, GPIO_MODE_OUTPUT);
|
||||||
|
|
||||||
|
// reset the bm1397
|
||||||
|
_reset();
|
||||||
|
|
||||||
|
return _send_init(frequency, asic_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Baud formula = 25M/((denominator+1)*8)
|
||||||
|
// The denominator is 5 bits found in the misc_control (bits 9-13)
|
||||||
|
int BM1397_set_default_baud(void)
|
||||||
|
{
|
||||||
|
// default divider of 26 (11010) for 115,749
|
||||||
|
unsigned char baudrate[9] = {0x00, MISC_CONTROL, 0x00, 0x00, 0b01111010, 0b00110001}; // baudrate - misc_control
|
||||||
|
_send_BM1397((TYPE_CMD | GROUP_ALL | CMD_WRITE), baudrate, 6, BM1937_SERIALTX_DEBUG);
|
||||||
|
return 115749;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BM1397_set_max_baud(void)
|
||||||
|
{
|
||||||
|
// divider of 0 for 3,125,000
|
||||||
|
ESP_LOGI(TAG, "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, BM1937_SERIALTX_DEBUG);
|
||||||
|
return 3125000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BM1397_set_job_difficulty_mask(int difficulty)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Default mask of 256 diff
|
||||||
|
unsigned char job_difficulty_mask[9] = {0x00, TICKET_MASK, 0b00000000, 0b00000000, 0b00000000, 0b11111111};
|
||||||
|
|
||||||
|
// The mask must be a power of 2 so there are no holes
|
||||||
|
// Correct: {0b00000000, 0b00000000, 0b11111111, 0b11111111}
|
||||||
|
// Incorrect: {0b00000000, 0b00000000, 0b11100111, 0b11111111}
|
||||||
|
difficulty = _largest_power_of_two(difficulty) - 1; // (difficulty - 1) if it is a pow 2 then step down to second largest for more hashrate sampling
|
||||||
|
|
||||||
|
// convert difficulty into char array
|
||||||
|
// Ex: 256 = {0b00000000, 0b00000000, 0b00000000, 0b11111111}, {0x00, 0x00, 0x00, 0xff}
|
||||||
|
// Ex: 512 = {0b00000000, 0b00000000, 0b00000001, 0b11111111}, {0x00, 0x00, 0x01, 0xff}
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
char value = (difficulty >> (8 * i)) & 0xFF;
|
||||||
|
// The char is read in backwards to the register so we need to reverse them
|
||||||
|
// So a mask of 512 looks like 0b00000000 00000000 00000001 1111111
|
||||||
|
// and not 0b00000000 00000000 10000000 1111111
|
||||||
|
|
||||||
|
job_difficulty_mask[5 - i] = _reverse_bits(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Setting job ASIC mask to %d", difficulty);
|
||||||
|
|
||||||
|
_send_BM1397((TYPE_CMD | GROUP_ALL | CMD_WRITE), job_difficulty_mask, 6, BM1937_SERIALTX_DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t id = 0;
|
||||||
|
|
||||||
|
uint8_t BM1397_send_work(bm_job_t *next_bm_job)
|
||||||
|
{
|
||||||
|
job_packet job;
|
||||||
|
// max job number is 128
|
||||||
|
// there is still some really weird logic with the job id bits for the asic to sort out
|
||||||
|
// so we have it limited to 128 and it has to increment by 4
|
||||||
|
id = (id + 4) % 128;
|
||||||
|
|
||||||
|
job.job_id = id;
|
||||||
|
job.num_midstates = next_bm_job->num_midstates;
|
||||||
|
memcpy(&job.starting_nonce, &next_bm_job->starting_nonce, 4);
|
||||||
|
memcpy(&job.nbits, &next_bm_job->target, 4);
|
||||||
|
memcpy(&job.ntime, &next_bm_job->ntime, 4);
|
||||||
|
memcpy(&job.merkle4, next_bm_job->merkle_root + 28, 4);
|
||||||
|
memcpy(job.midstate, next_bm_job->midstate, 32);
|
||||||
|
|
||||||
|
if (job.num_midstates == 4)
|
||||||
|
{
|
||||||
|
memcpy(job.midstate1, next_bm_job->midstate1, 32);
|
||||||
|
memcpy(job.midstate2, next_bm_job->midstate2, 32);
|
||||||
|
memcpy(job.midstate3, next_bm_job->midstate3, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
_send_BM1397((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), (uint8_t*) &job, sizeof(job_packet), BM1397_DEBUG_WORK);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
asic_result *BM1397_receive_work(uint16_t timeout)
|
||||||
|
{
|
||||||
|
|
||||||
|
// wait for a response, wait time is pretty arbitrary
|
||||||
|
int received = SERIAL_rx(asic_response_buffer, 9, timeout);
|
||||||
|
|
||||||
|
if (received < 0)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Error in serial RX");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else if (received == 0)
|
||||||
|
{
|
||||||
|
// Didn't find a solution, restart and try again
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (received != 9 || asic_response_buffer[0] != 0xAA || asic_response_buffer[1] != 0x55)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Serial RX invalid %i", received);
|
||||||
|
ESP_LOG_BUFFER_HEX(TAG, asic_response_buffer, received);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (asic_result *)asic_response_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_result *BM1397_proccess_work(bm_job_t *job, uint16_t timeout)
|
||||||
|
{
|
||||||
|
|
||||||
|
asic_result *asic_result = BM1397_receive_work(timeout);
|
||||||
|
|
||||||
|
if (asic_result == NULL)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "return null");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t nonce_found = 0;
|
||||||
|
uint32_t first_nonce = 0;
|
||||||
|
|
||||||
|
uint8_t rx_job_id = asic_result->job_id & 0xfc;
|
||||||
|
uint8_t rx_midstate_index = asic_result->job_id & 0x03;
|
||||||
|
|
||||||
|
uint32_t rolled_version = job->version;
|
||||||
|
for (int i = 0; i < rx_midstate_index; i++)
|
||||||
|
{
|
||||||
|
rolled_version = increment_bitmask(rolled_version, 0x1fffe000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ASIC may return the same nonce multiple times
|
||||||
|
// or one that was already found
|
||||||
|
// most of the time it behavies however
|
||||||
|
if (nonce_found == 0)
|
||||||
|
{
|
||||||
|
first_nonce = asic_result->nonce;
|
||||||
|
nonce_found = 1;
|
||||||
|
}
|
||||||
|
else if (asic_result->nonce == first_nonce)
|
||||||
|
{
|
||||||
|
// stop if we've already seen this nonce
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asic_result->nonce == prev_nonce)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prev_nonce = asic_result->nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.job_id = rx_job_id;
|
||||||
|
result.nonce = asic_result->nonce;
|
||||||
|
result.rolled_version = rolled_version;
|
||||||
|
|
||||||
|
return &result;
|
||||||
|
}
|
55
src/drivers/nerd-nos/bm1397.h
Normal file
55
src/drivers/nerd-nos/bm1397.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "common.h"
|
||||||
|
#include "mining.h"
|
||||||
|
#include "crc.h"
|
||||||
|
|
||||||
|
#define CRC5_MASK 0x1F
|
||||||
|
#define BM1397_INITIAL_DIFFICULTY 64
|
||||||
|
|
||||||
|
#define BM1937_SERIALTX_DEBUG false
|
||||||
|
#define BM1937_SERIALRX_DEBUG true //false
|
||||||
|
#define BM1397_DEBUG_WORK false //causes insane amount of debug output
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
float frequency;
|
||||||
|
} bm1397Module;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
JOB_PACKET = 0,
|
||||||
|
CMD_PACKET = 1,
|
||||||
|
} packet_type_t;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
JOB_RESP = 0,
|
||||||
|
CMD_RESP = 1,
|
||||||
|
} response_type_t;
|
||||||
|
|
||||||
|
typedef struct __attribute__((__packed__))
|
||||||
|
{
|
||||||
|
uint8_t job_id;
|
||||||
|
uint8_t num_midstates;
|
||||||
|
uint8_t starting_nonce[4];
|
||||||
|
uint8_t nbits[4];
|
||||||
|
uint8_t ntime[4];
|
||||||
|
uint8_t merkle4[4];
|
||||||
|
uint8_t midstate[32];
|
||||||
|
uint8_t midstate1[32];
|
||||||
|
uint8_t midstate2[32];
|
||||||
|
uint8_t midstate3[32];
|
||||||
|
} job_packet;
|
||||||
|
|
||||||
|
uint8_t BM1397_init(uint64_t frequency, uint16_t asic_count);
|
||||||
|
|
||||||
|
uint8_t BM1397_send_work(bm_job_t * next_bm_job);
|
||||||
|
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(bm_job_t *job, uint16_t timeout);
|
||||||
|
|
41
src/drivers/nerd-nos/common.h
Normal file
41
src/drivers/nerd-nos/common.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef COMMON_H_
|
||||||
|
#define COMMON_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct __attribute__((__packed__))
|
||||||
|
{
|
||||||
|
uint8_t job_id;
|
||||||
|
uint32_t nonce;
|
||||||
|
uint32_t rolled_version;
|
||||||
|
} task_result;
|
||||||
|
|
||||||
|
static unsigned char _reverse_bits(unsigned char num)
|
||||||
|
{
|
||||||
|
unsigned char reversed = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
reversed <<= 1; // Left shift the reversed variable by 1
|
||||||
|
reversed |= num & 1; // Use bitwise OR to set the rightmost bit of reversed to the current bit of num
|
||||||
|
num >>= 1; // Right shift num by 1 to get the next bit
|
||||||
|
}
|
||||||
|
|
||||||
|
return reversed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _largest_power_of_two(int num)
|
||||||
|
{
|
||||||
|
int power = 0;
|
||||||
|
|
||||||
|
while (num > 1) {
|
||||||
|
num = num >> 1;
|
||||||
|
power++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1 << power;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printBufferHex(const char *prefix, const uint8_t* buf, size_t len);
|
||||||
|
|
||||||
|
#endif
|
114
src/drivers/nerd-nos/crc.cpp
Normal file
114
src/drivers/nerd-nos/crc.cpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "crc.h"
|
||||||
|
#include "bm1397.h"
|
||||||
|
|
||||||
|
/* compute crc5 over given number of bytes */
|
||||||
|
// adapted from https://mightydevices.com/index.php/2018/02/reverse-engineering-antminer-s1/
|
||||||
|
uint8_t crc5(uint8_t *buffer, uint16_t len)
|
||||||
|
{
|
||||||
|
uint8_t i, j, k, index = 0;
|
||||||
|
uint8_t crc = CRC5_MASK;
|
||||||
|
/* registers */
|
||||||
|
uint8_t crcin[5] = {1, 1, 1, 1, 1};
|
||||||
|
uint8_t crcout[5] = {1, 1, 1, 1, 1};
|
||||||
|
uint8_t din = 0;
|
||||||
|
|
||||||
|
len *= 8;
|
||||||
|
|
||||||
|
/* push data bits */
|
||||||
|
for (j = 0x80, k = 0, i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
/* input bit */
|
||||||
|
din = (buffer[index] & j) != 0;
|
||||||
|
/* shift register */
|
||||||
|
crcout[0] = crcin[4] ^ din;
|
||||||
|
crcout[1] = crcin[0];
|
||||||
|
crcout[2] = crcin[1] ^ crcin[4] ^ din;
|
||||||
|
crcout[3] = crcin[2];
|
||||||
|
crcout[4] = crcin[3];
|
||||||
|
/* next bit */
|
||||||
|
j >>= 1, k++;
|
||||||
|
/* next byte */
|
||||||
|
if (k == 8)
|
||||||
|
j = 0x80, k = 0, index++;
|
||||||
|
/* apply new shift register value */
|
||||||
|
memcpy(crcin, crcout, 5);
|
||||||
|
// crcin = crcout[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
crc = 0;
|
||||||
|
/* extract bitmask from register */
|
||||||
|
if (crcin[4])
|
||||||
|
crc |= 0x10;
|
||||||
|
if (crcin[3])
|
||||||
|
crc |= 0x08;
|
||||||
|
if (crcin[2])
|
||||||
|
crc |= 0x04;
|
||||||
|
if (crcin[1])
|
||||||
|
crc |= 0x02;
|
||||||
|
if (crcin[0])
|
||||||
|
crc |= 0x01;
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// kindly provided by cgminer
|
||||||
|
unsigned int crc16_table[256] = {
|
||||||
|
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||||
|
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
||||||
|
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
||||||
|
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
|
||||||
|
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
|
||||||
|
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
|
||||||
|
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
|
||||||
|
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
|
||||||
|
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||||
|
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
|
||||||
|
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
|
||||||
|
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
|
||||||
|
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
|
||||||
|
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
|
||||||
|
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
|
||||||
|
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
|
||||||
|
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
|
||||||
|
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||||
|
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
|
||||||
|
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||||
|
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
|
||||||
|
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||||
|
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
|
||||||
|
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||||
|
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
|
||||||
|
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
|
||||||
|
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||||
|
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
|
||||||
|
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
|
||||||
|
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
|
||||||
|
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
||||||
|
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0};
|
||||||
|
|
||||||
|
/* CRC-16/CCITT */
|
||||||
|
uint16_t crc16(uint8_t *buffer, uint16_t len)
|
||||||
|
{
|
||||||
|
uint16_t crc;
|
||||||
|
|
||||||
|
crc = 0;
|
||||||
|
while (len-- > 0)
|
||||||
|
crc = crc16_table[((crc >> 8) ^ (*buffer++)) & 0xFF] ^ (crc << 8);
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CRC-16/CCITT-FALSE */
|
||||||
|
uint16_t crc16_false(uint8_t *buffer, uint16_t len)
|
||||||
|
{
|
||||||
|
uint16_t crc;
|
||||||
|
|
||||||
|
crc = 0xffff;
|
||||||
|
while (len-- > 0)
|
||||||
|
crc = crc16_table[((crc >> 8) ^ (*buffer++)) & 0xFF] ^ (crc << 8);
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
18
src/drivers/nerd-nos/crc.h
Normal file
18
src/drivers/nerd-nos/crc.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef CRC_H_
|
||||||
|
#define CRC_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t crc5(uint8_t *buffer, uint16_t len);
|
||||||
|
uint16_t crc16(uint8_t *buffer, uint16_t len);
|
||||||
|
uint16_t crc16_false(uint8_t *buffer, uint16_t len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CRC_H_
|
168
src/drivers/nerd-nos/mining.cpp
Normal file
168
src/drivers/nerd-nos/mining.cpp
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "bm1397.h"
|
||||||
|
#include "mining.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "stratum.h"
|
||||||
|
#include "mbedtls/sha256.h"
|
||||||
|
|
||||||
|
///////cgminer nonce testing
|
||||||
|
/* truediffone == 0x00000000FFFF0000000000000000000000000000000000000000000000000000
|
||||||
|
*/
|
||||||
|
static const double truediffone = 26959535291011309493156476344723991336010898738574164086137773096960.0;
|
||||||
|
|
||||||
|
/* testing a nonce and return the diff - 0 means invalid */
|
||||||
|
double asic_test_nonce_value(const bm_job_t *job, const uint32_t nonce, const uint32_t rolled_version)
|
||||||
|
{
|
||||||
|
double d64, s64, ds;
|
||||||
|
unsigned char header[80];
|
||||||
|
|
||||||
|
// // TODO: use the midstate hash instead of hashing the whole header
|
||||||
|
// uint32_t rolled_version = job->version;
|
||||||
|
// for (int i = 0; i < midstate_index; i++) {
|
||||||
|
// rolled_version = increment_bitmask(rolled_version, job->version_mask);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// copy data from job to header
|
||||||
|
memcpy(header, &rolled_version, 4);
|
||||||
|
memcpy(header + 4, job->prev_block_hash, 32);
|
||||||
|
memcpy(header + 36, job->merkle_root, 32);
|
||||||
|
memcpy(header + 68, &job->ntime, 4);
|
||||||
|
memcpy(header + 72, &job->target, 4);
|
||||||
|
memcpy(header + 76, &nonce, 4);
|
||||||
|
|
||||||
|
unsigned char hash_buffer[32];
|
||||||
|
unsigned char hash_result[32];
|
||||||
|
|
||||||
|
// double hash the header
|
||||||
|
mbedtls_sha256(header, 80, hash_buffer, 0);
|
||||||
|
mbedtls_sha256(hash_buffer, 32, hash_result, 0);
|
||||||
|
|
||||||
|
d64 = truediffone;
|
||||||
|
s64 = le256todouble(hash_result);
|
||||||
|
ds = d64 / s64;
|
||||||
|
|
||||||
|
return ds;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t increment_bitmask(const uint32_t value, const uint32_t mask)
|
||||||
|
{
|
||||||
|
// if mask is zero, just return the original value
|
||||||
|
if (mask == 0)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
uint32_t carry = (value & mask) + (mask & -mask); // increment the least significant bit of the mask
|
||||||
|
uint32_t overflow = carry & ~mask; // find overflowed bits that are not in the mask
|
||||||
|
uint32_t new_value = (value & ~mask) | (carry & mask); // set bits according to the mask
|
||||||
|
|
||||||
|
// Handle carry propagation
|
||||||
|
if (overflow > 0)
|
||||||
|
{
|
||||||
|
uint32_t carry_mask = (overflow << 1); // shift left to get the mask where carry should be propagated
|
||||||
|
new_value = increment_bitmask(new_value, carry_mask); // recursively handle carry propagation
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void calculate_merkle_root_hash(const char *coinbase_tx, mining_job* job, char merkle_root_hash[65])
|
||||||
|
{
|
||||||
|
size_t coinbase_tx_bin_len = strlen(coinbase_tx) / 2;
|
||||||
|
uint8_t coinbase_tx_bin[coinbase_tx_bin_len];
|
||||||
|
hex2bin(coinbase_tx, coinbase_tx_bin, coinbase_tx_bin_len);
|
||||||
|
|
||||||
|
uint8_t both_merkles[64];
|
||||||
|
uint8_t new_root[32];
|
||||||
|
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);
|
||||||
|
double_sha256_bin(both_merkles, 64, new_root);
|
||||||
|
memcpy(both_merkles, new_root, 32);
|
||||||
|
}
|
||||||
|
bin2hex(both_merkles, 32, merkle_root_hash, 65);
|
||||||
|
}
|
||||||
|
|
||||||
|
// take a mining_notify struct with ascii hex strings and convert it to a bm_job struct
|
||||||
|
void construct_bm_job(mining_job *job, const char *merkle_root, uint32_t version_mask, bm_job_t *new_job)
|
||||||
|
{
|
||||||
|
new_job->version = strtoul(job->version.c_str(), NULL, 16);
|
||||||
|
new_job->target = strtoul(job->nbits.c_str(), NULL, 16);
|
||||||
|
new_job->ntime = strtoul(job->ntime.c_str(), NULL, 16);
|
||||||
|
new_job->starting_nonce = 0;
|
||||||
|
|
||||||
|
hex2bin(merkle_root, new_job->merkle_root, 32);
|
||||||
|
|
||||||
|
// hex2bin(merkle_root, new_job.merkle_root_be, 32);
|
||||||
|
swap_endian_words(merkle_root, new_job->merkle_root_be);
|
||||||
|
reverse_bytes(new_job->merkle_root_be, 32);
|
||||||
|
|
||||||
|
swap_endian_words(job->prev_block_hash.c_str(), new_job->prev_block_hash);
|
||||||
|
|
||||||
|
hex2bin(job->prev_block_hash.c_str(), new_job->prev_block_hash_be, 32);
|
||||||
|
reverse_bytes(new_job->prev_block_hash_be, 32);
|
||||||
|
|
||||||
|
////make the midstate hash
|
||||||
|
uint8_t midstate_data[64];
|
||||||
|
|
||||||
|
// copy 68 bytes header data into midstate (and deal with endianess)
|
||||||
|
memcpy(midstate_data, &new_job->version, 4); // copy version
|
||||||
|
memcpy(midstate_data + 4, new_job->prev_block_hash, 32); // copy prev_block_hash
|
||||||
|
memcpy(midstate_data + 36, new_job->merkle_root, 28); // copy merkle_root
|
||||||
|
|
||||||
|
midstate_sha256_bin(midstate_data, 64, new_job->midstate); // make the midstate hash
|
||||||
|
reverse_bytes(new_job->midstate, 32); // reverse the midstate bytes for the BM job packet
|
||||||
|
|
||||||
|
uint32_t rolled_version = increment_bitmask(new_job->version, version_mask);
|
||||||
|
memcpy(midstate_data, &rolled_version, 4);
|
||||||
|
midstate_sha256_bin(midstate_data, 64, new_job->midstate1);
|
||||||
|
reverse_bytes(new_job->midstate1, 32);
|
||||||
|
|
||||||
|
rolled_version = increment_bitmask(rolled_version, version_mask);
|
||||||
|
memcpy(midstate_data, &rolled_version, 4);
|
||||||
|
midstate_sha256_bin(midstate_data, 64, new_job->midstate2);
|
||||||
|
reverse_bytes(new_job->midstate2, 32);
|
||||||
|
|
||||||
|
rolled_version = increment_bitmask(rolled_version, version_mask);
|
||||||
|
memcpy(midstate_data, &rolled_version, 4);
|
||||||
|
midstate_sha256_bin(midstate_data, 64, new_job->midstate3);
|
||||||
|
reverse_bytes(new_job->midstate3, 32);
|
||||||
|
new_job->num_midstates = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void asic_create_job(mining_subscribe *mWorker, mining_job *job, bm_job_t *next_job, uint32_t extranonce_2) {
|
||||||
|
char extranonce_2_str[mWorker->extranonce2_size * 2 + 1]; // +1 zero termination
|
||||||
|
snprintf(extranonce_2_str, sizeof(extranonce_2_str), "%0*lx", (int) mWorker->extranonce2_size * 2, extranonce_2);
|
||||||
|
|
||||||
|
// generate coinbase tx
|
||||||
|
String coinbase_tx = job->coinb1 + mWorker->extranonce1 + extranonce_2_str + job->coinb2;
|
||||||
|
|
||||||
|
// calculate merkle root
|
||||||
|
char merkle_root[65];
|
||||||
|
calculate_merkle_root_hash(coinbase_tx.c_str(), job, merkle_root);
|
||||||
|
|
||||||
|
//Serial.printf("asic merkle root: %s\n", merkle_root);
|
||||||
|
// we need malloc because we will save it in the job array
|
||||||
|
construct_bm_job(job, merkle_root, 0x1fffe000, next_job);
|
||||||
|
|
||||||
|
next_job->jobid = strdup(job->job_id.c_str());
|
||||||
|
next_job->extranonce2 = strdup(extranonce_2_str);
|
||||||
|
//next_job->pool_diff = stratum_difficulty;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t asic_send_work(bm_job_t *next_bm_job) {
|
||||||
|
return BM1397_send_work(next_bm_job);
|
||||||
|
}
|
||||||
|
|
||||||
|
task_result *asic_proccess_work(bm_job_t *job, uint16_t timeout) {
|
||||||
|
return BM1397_proccess_work(job, timeout);
|
||||||
|
}
|
32
src/drivers/nerd-nos/mining.h
Normal file
32
src/drivers/nerd-nos/mining.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "common.h"
|
||||||
|
//#include "stratum.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t version_mask;
|
||||||
|
uint8_t prev_block_hash[32];
|
||||||
|
uint8_t prev_block_hash_be[32];
|
||||||
|
uint8_t merkle_root[32];
|
||||||
|
uint8_t merkle_root_be[32];
|
||||||
|
uint32_t ntime;
|
||||||
|
uint32_t target; // aka difficulty, aka nbits
|
||||||
|
uint32_t starting_nonce;
|
||||||
|
|
||||||
|
uint8_t num_midstates;
|
||||||
|
uint8_t midstate[32];
|
||||||
|
uint8_t midstate1[32];
|
||||||
|
uint8_t midstate2[32];
|
||||||
|
uint8_t midstate3[32];
|
||||||
|
char *jobid;
|
||||||
|
char *extranonce2;
|
||||||
|
} bm_job_t;
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t asic_send_work(bm_job_t *next_bm_job);
|
||||||
|
task_result *asic_proccess_work(bm_job_t *job, uint16_t timeout);
|
||||||
|
|
||||||
|
double asic_test_nonce_value(const bm_job_t *job, const uint32_t nonce, const uint32_t rolled_version);
|
90
src/drivers/nerd-nos/serial.cpp
Normal file
90
src/drivers/nerd-nos/serial.cpp
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include "driver/uart.h"
|
||||||
|
#include "../devices/device.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "serial.h"
|
||||||
|
|
||||||
|
#define BUF_SIZE (1024)
|
||||||
|
|
||||||
|
void SERIAL_init() {
|
||||||
|
|
||||||
|
Serial.println("Initializing serial");
|
||||||
|
// Configure UART1 parameters
|
||||||
|
uart_config_t uart_config = {
|
||||||
|
.baud_rate = 115200,
|
||||||
|
.data_bits = UART_DATA_8_BITS,
|
||||||
|
.parity = UART_PARITY_DISABLE,
|
||||||
|
.stop_bits = UART_STOP_BITS_1,
|
||||||
|
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||||
|
.rx_flow_ctrl_thresh = 122,
|
||||||
|
};
|
||||||
|
// Configure UART1 parameters
|
||||||
|
uart_param_config(UART_NUM_1, &uart_config);
|
||||||
|
// Set UART1 pins(TX: IO17, RX: I018)
|
||||||
|
uart_set_pin(UART_NUM_1, NERD_NOS_GPIO_TX, NERD_NOS_GPIO_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||||
|
|
||||||
|
// Install UART driver (we don't need an event queue here)
|
||||||
|
// tx buffer 0 so the tx time doesn't overlap with the job wait time
|
||||||
|
// by returning before the job is written
|
||||||
|
uart_driver_install(UART_NUM_1, BUF_SIZE * 2, BUF_SIZE * 2, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SERIAL_set_baud(int baud)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Changing UART baud to %i", baud);
|
||||||
|
uart_set_baudrate(UART_NUM_1, baud);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SERIAL_send(uint8_t *data, int len, bool debug)
|
||||||
|
{
|
||||||
|
// if (debug)
|
||||||
|
// {
|
||||||
|
// printf("->");
|
||||||
|
// prettyHex((unsigned char *)data, len);
|
||||||
|
// printf("\n");
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
printBufferHex("TX", data, len);
|
||||||
|
}
|
||||||
|
return uart_write_bytes(UART_NUM_1, (const char *)data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief waits for a serial response from the device
|
||||||
|
/// @param buf buffer to read data into
|
||||||
|
/// @param buf number of ms to wait before timing out
|
||||||
|
/// @return number of bytes read, or -1 on error
|
||||||
|
int16_t SERIAL_rx(uint8_t *buf, uint16_t size, uint16_t timeout_ms)
|
||||||
|
{
|
||||||
|
int16_t bytes_read = uart_read_bytes(UART_NUM_1, buf, size, timeout_ms / portTICK_PERIOD_MS);
|
||||||
|
// if (bytes_read > 0) {
|
||||||
|
// printf("rx: ");
|
||||||
|
// prettyHex((unsigned char*) buf, bytes_read);
|
||||||
|
// printf("\n");
|
||||||
|
// }
|
||||||
|
if (bytes_read > 0) {
|
||||||
|
printBufferHex("RX", buf, bytes_read);
|
||||||
|
}
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SERIAL_debug_rx(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint8_t buf[CHUNK_SIZE];
|
||||||
|
|
||||||
|
ret = SERIAL_rx(buf, 100, 20);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "unable to read data\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buf, 0, 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SERIAL_clear_buffer(void)
|
||||||
|
{
|
||||||
|
uart_flush(UART_NUM_1);
|
||||||
|
}
|
13
src/drivers/nerd-nos/serial.h
Normal file
13
src/drivers/nerd-nos/serial.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef SERIAL_H_
|
||||||
|
#define SERIAL_H_
|
||||||
|
|
||||||
|
#define CHUNK_SIZE 1024
|
||||||
|
|
||||||
|
int SERIAL_send(uint8_t *, int, bool);
|
||||||
|
void SERIAL_init(void);
|
||||||
|
void SERIAL_debug_rx(void);
|
||||||
|
int16_t SERIAL_rx(uint8_t *, uint16_t, uint16_t);
|
||||||
|
void SERIAL_clear_buffer(void);
|
||||||
|
void SERIAL_set_baud(int baud);
|
||||||
|
|
||||||
|
#endif /* SERIAL_H_ */
|
309
src/drivers/nerd-nos/utils.cpp
Normal file
309
src/drivers/nerd-nos/utils.cpp
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "mbedtls/sha256.h"
|
||||||
|
|
||||||
|
#ifndef bswap_16
|
||||||
|
#define bswap_16(a) ((((uint16_t)(a) << 8) & 0xff00) | (((uint16_t)(a) >> 8) & 0xff))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef bswap_32
|
||||||
|
#define bswap_32(a) ((((uint32_t)(a) << 24) & 0xff000000) | \
|
||||||
|
(((uint32_t)(a) << 8) & 0xff0000) | \
|
||||||
|
(((uint32_t)(a) >> 8) & 0xff00) | \
|
||||||
|
(((uint32_t)(a) >> 24) & 0xff))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* General byte order swapping functions.
|
||||||
|
*/
|
||||||
|
#define bswap16(x) __bswap16(x)
|
||||||
|
#define bswap32(x) __bswap32(x)
|
||||||
|
#define bswap64(x) __bswap64(x)
|
||||||
|
|
||||||
|
// in the other utils.cpp^^
|
||||||
|
uint32_t swab32(uint32_t v);
|
||||||
|
void swap_endian_words(const char *hex_words, uint8_t *output);
|
||||||
|
void reverse_bytes(uint8_t *data, size_t len);
|
||||||
|
double le256todouble(const void *target);
|
||||||
|
|
||||||
|
/*
|
||||||
|
uint32_t swab32(uint32_t v)
|
||||||
|
{
|
||||||
|
return bswap_32(v);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// takes 80 bytes and flips every 4 bytes
|
||||||
|
void flip80bytes(void *dest_p, const void *src_p)
|
||||||
|
{
|
||||||
|
uint32_t *dest = (uint32_t*) dest_p;
|
||||||
|
const uint32_t *src = (const uint32_t*) src_p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 20; i++)
|
||||||
|
dest[i] = swab32(src[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flip64bytes(void *dest_p, const void *src_p)
|
||||||
|
{
|
||||||
|
uint32_t *dest = (uint32_t*) dest_p;
|
||||||
|
const uint32_t *src = (const uint32_t*) src_p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
dest[i] = swab32(src[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flip32bytes(void *dest_p, const void *src_p)
|
||||||
|
{
|
||||||
|
uint32_t *dest = (uint32_t*) dest_p;
|
||||||
|
const uint32_t *src = (const uint32_t*) src_p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
dest[i] = swab32(src[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hex2char(uint8_t x, char *c)
|
||||||
|
{
|
||||||
|
if (x <= 9)
|
||||||
|
{
|
||||||
|
*c = x + '0';
|
||||||
|
}
|
||||||
|
else if (x <= 15)
|
||||||
|
{
|
||||||
|
*c = x - 10 + 'a';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen)
|
||||||
|
{
|
||||||
|
if ((hexlen + 1) < buflen * 2)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < buflen; i++)
|
||||||
|
{
|
||||||
|
if (hex2char(buf[i] >> 4, &hex[2 * i]) < 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (hex2char(buf[i] & 0xf, &hex[2 * i + 1]) < 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hex[2 * buflen] = '\0';
|
||||||
|
return 2 * buflen;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t hex2val(char c)
|
||||||
|
{
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
{
|
||||||
|
return c - '0';
|
||||||
|
}
|
||||||
|
else if (c >= 'a' && c <= 'f')
|
||||||
|
{
|
||||||
|
return c - 'a' + 10;
|
||||||
|
}
|
||||||
|
else if (c >= 'A' && c <= 'F')
|
||||||
|
{
|
||||||
|
return c - 'A' + 10;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t hex2bin(const char *hex, uint8_t *bin, size_t bin_len)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
while (*hex && len < bin_len)
|
||||||
|
{
|
||||||
|
bin[len] = hex2val(*hex++) << 4;
|
||||||
|
|
||||||
|
if (!*hex)
|
||||||
|
{
|
||||||
|
len++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bin[len++] |= hex2val(*hex++);
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_hex(const uint8_t *b, size_t len,
|
||||||
|
const size_t in_line, const char *prefix)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
const uint8_t *end = b + len;
|
||||||
|
|
||||||
|
if (prefix == NULL)
|
||||||
|
{
|
||||||
|
prefix = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s", prefix);
|
||||||
|
while (b < end)
|
||||||
|
{
|
||||||
|
if (++i > in_line)
|
||||||
|
{
|
||||||
|
printf("\n%s", prefix);
|
||||||
|
i = 1;
|
||||||
|
}
|
||||||
|
printf("%02X ", (uint8_t)*b++);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void double_sha256(const char *hex_string, char output_hash[65])
|
||||||
|
{
|
||||||
|
size_t bin_len = strlen(hex_string) / 2;
|
||||||
|
uint8_t bin[bin_len];
|
||||||
|
hex2bin(hex_string, bin, bin_len);
|
||||||
|
|
||||||
|
unsigned char first_hash_output[32], second_hash_output[32];
|
||||||
|
|
||||||
|
mbedtls_sha256(bin, bin_len, first_hash_output, 0);
|
||||||
|
mbedtls_sha256(first_hash_output, 32, second_hash_output, 0);
|
||||||
|
|
||||||
|
bin2hex(second_hash_output, 32, output_hash, 65);
|
||||||
|
}
|
||||||
|
|
||||||
|
void double_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t digest[32])
|
||||||
|
{
|
||||||
|
uint8_t first_hash_output[32];
|
||||||
|
|
||||||
|
mbedtls_sha256(data, data_len, first_hash_output, 0);
|
||||||
|
mbedtls_sha256(first_hash_output, 32, digest, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void single_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t *dest)
|
||||||
|
{
|
||||||
|
// mbedtls_sha256(data, data_len, dest, 0);
|
||||||
|
|
||||||
|
// Initialize SHA256 context
|
||||||
|
mbedtls_sha256_context sha256_ctx;
|
||||||
|
mbedtls_sha256_init(&sha256_ctx);
|
||||||
|
mbedtls_sha256_starts(&sha256_ctx, 0);
|
||||||
|
|
||||||
|
// Compute first SHA256 hash of header
|
||||||
|
mbedtls_sha256_update(&sha256_ctx, data, 64);
|
||||||
|
unsigned char hash[32];
|
||||||
|
mbedtls_sha256_finish(&sha256_ctx, hash);
|
||||||
|
|
||||||
|
// Compute midstate from hash
|
||||||
|
memcpy(dest, hash, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void midstate_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t *dest)
|
||||||
|
{
|
||||||
|
mbedtls_sha256_context midstate;
|
||||||
|
|
||||||
|
// Calculate midstate
|
||||||
|
mbedtls_sha256_init(&midstate);
|
||||||
|
mbedtls_sha256_starts(&midstate, 0);
|
||||||
|
mbedtls_sha256_update(&midstate, data, 64);
|
||||||
|
|
||||||
|
// memcpy(dest, midstate.state, 32);
|
||||||
|
flip32bytes(dest, midstate.state);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void swap_endian_words(const char *hex_words, uint8_t *output)
|
||||||
|
{
|
||||||
|
size_t hex_length = strlen(hex_words);
|
||||||
|
if (hex_length % 8 != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Must be 4-byte word aligned\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t binary_length = hex_length / 2;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < binary_length; i += 4)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
unsigned int byte_val;
|
||||||
|
sscanf(hex_words + (i + j) * 2, "%2x", &byte_val);
|
||||||
|
output[i + (3 - j)] = byte_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
void reverse_bytes(uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < len / 2; ++i)
|
||||||
|
{
|
||||||
|
uint8_t temp = data[i];
|
||||||
|
data[i] = data[len - 1 - i];
|
||||||
|
data[len - 1 - i] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
// static const double truediffone = 26959535291011309493156476344723991336010898738574164086137773096960.0;
|
||||||
|
static const double bits192 = 6277101735386680763835789423207666416102355444464034512896.0;
|
||||||
|
static const double bits128 = 340282366920938463463374607431768211456.0;
|
||||||
|
static const double bits64 = 18446744073709551616.0;
|
||||||
|
|
||||||
|
// Converts a little endian 256 bit value to a double
|
||||||
|
double le256todouble(const void *target)
|
||||||
|
{
|
||||||
|
uint64_t *data64;
|
||||||
|
double dcut64;
|
||||||
|
|
||||||
|
data64 = (uint64_t *)(target + 24);
|
||||||
|
dcut64 = *data64 * bits192;
|
||||||
|
|
||||||
|
data64 = (uint64_t *)(target + 16);
|
||||||
|
dcut64 += *data64 * bits128;
|
||||||
|
|
||||||
|
data64 = (uint64_t *)(target + 8);
|
||||||
|
dcut64 += *data64 * bits64;
|
||||||
|
|
||||||
|
data64 = (uint64_t *)(target);
|
||||||
|
dcut64 += *data64;
|
||||||
|
|
||||||
|
return dcut64;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
void prettyHex(unsigned char *buf, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
printf("[");
|
||||||
|
for (i = 0; i < len - 1; i++)
|
||||||
|
{
|
||||||
|
printf("%02X ", buf[i]);
|
||||||
|
}
|
||||||
|
printf("%02X]\n", buf[len - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t flip32(uint32_t val)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
ret |= (val & 0xFF) << 24;
|
||||||
|
ret |= (val & 0xFF00) << 8;
|
||||||
|
ret |= (val & 0xFF0000) >> 8;
|
||||||
|
ret |= (val & 0xFF000000) >> 24;
|
||||||
|
return ret;
|
||||||
|
}
|
35
src/drivers/nerd-nos/utils.h
Normal file
35
src/drivers/nerd-nos/utils.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma one
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int hex2char(uint8_t x, char *c);
|
||||||
|
|
||||||
|
size_t bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen);
|
||||||
|
|
||||||
|
uint8_t hex2val(char c);
|
||||||
|
void flip80bytes(void *dest_p, const void *src_p);
|
||||||
|
void flip32bytes(void *dest_p, const void *src_p);
|
||||||
|
|
||||||
|
size_t hex2bin(const char *hex, uint8_t *bin, size_t bin_len);
|
||||||
|
|
||||||
|
void print_hex(const uint8_t *b, size_t len,
|
||||||
|
const size_t in_line, const char *prefix);
|
||||||
|
|
||||||
|
void double_sha256(const char *hex_string, char output_hash[65]);
|
||||||
|
|
||||||
|
void double_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t digest[32]);
|
||||||
|
|
||||||
|
void single_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t *dest);
|
||||||
|
void midstate_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t *dest);
|
||||||
|
|
||||||
|
void swap_endian_words(const char *hex, uint8_t *output);
|
||||||
|
|
||||||
|
void reverse_bytes(uint8_t *data, size_t len);
|
||||||
|
|
||||||
|
double le256todouble(const void *target);
|
||||||
|
|
||||||
|
void prettyHex(unsigned char *buf, int len);
|
||||||
|
|
||||||
|
uint32_t flip32(uint32_t val);
|
||||||
|
|
102
src/mining.cpp
102
src/mining.cpp
@ -14,6 +14,11 @@
|
|||||||
#include "drivers/displays/display.h"
|
#include "drivers/displays/display.h"
|
||||||
#include "drivers/storage/storage.h"
|
#include "drivers/storage/storage.h"
|
||||||
|
|
||||||
|
#ifdef NERD_NOS
|
||||||
|
#include "drivers/nerd-nos/mining.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
nvs_handle_t stat_handle;
|
nvs_handle_t stat_handle;
|
||||||
|
|
||||||
uint32_t templates = 0;
|
uint32_t templates = 0;
|
||||||
@ -367,6 +372,103 @@ void runMiner(void * task_id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void asic_create_job(mining_subscribe *mWorker, mining_job *job, bm_job_t *next_job, uint32_t extranonce_2);
|
||||||
|
|
||||||
|
void runASIC(void * task_id) {
|
||||||
|
Serial.printf("[MINER] Started runASIC Task!\n");
|
||||||
|
|
||||||
|
uint32_t extranonce_2 = 0;
|
||||||
|
bm_job_t asic_job;
|
||||||
|
while(1) {
|
||||||
|
// wait for new job
|
||||||
|
while(1) {
|
||||||
|
if (mMiner.newJob == true) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vTaskDelay(100 / portTICK_PERIOD_MS); //Small delay
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mMiner.newJob) {
|
||||||
|
mMiner.newJob = false; //Clear newJob flag
|
||||||
|
}
|
||||||
|
mMiner.inRun = true; //Set inRun flag
|
||||||
|
|
||||||
|
Serial.println(">>> STARTING TO HASH NONCES");
|
||||||
|
uint32_t startT = micros();
|
||||||
|
|
||||||
|
while (mMiner.inRun) {
|
||||||
|
mMonitor.NerdStatus = NM_hashing;
|
||||||
|
extranonce_2++;
|
||||||
|
|
||||||
|
// create the next asic job
|
||||||
|
asic_create_job(&mWorker, &mJob, &asic_job, extranonce_2);
|
||||||
|
|
||||||
|
// send the job and
|
||||||
|
uint8_t asic_job_id = asic_send_work(&asic_job);
|
||||||
|
|
||||||
|
// wait 30ms for the response
|
||||||
|
task_result *result = asic_proccess_work(&asic_job, 30);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
// we haven't received anything in time, so send a new job
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result->job_id != asic_job_id) {
|
||||||
|
// job id mismatch
|
||||||
|
Serial.printf("ID mismatch, expected %02x, got %02x\n", asic_job_id, result->job_id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the nonce difficulty
|
||||||
|
double diff_hash = asic_test_nonce_value(
|
||||||
|
&asic_job,
|
||||||
|
result->nonce,
|
||||||
|
result->rolled_version);
|
||||||
|
|
||||||
|
Serial.print(" - Current diff share: "); Serial.println(diff_hash, 12);
|
||||||
|
Serial.print(" - Current pool diff : "); Serial.println(mMiner.poolDifficulty, 12);
|
||||||
|
|
||||||
|
// update best diff
|
||||||
|
if (diff_hash > best_diff)
|
||||||
|
best_diff = diff_hash;
|
||||||
|
|
||||||
|
if(diff_hash > mMiner.poolDifficulty)
|
||||||
|
{
|
||||||
|
tx_mining_submit_with_version(client, mWorker, &asic_job, extranonce_2, result->nonce, result->rolled_version);
|
||||||
|
Serial.println("valid share!");
|
||||||
|
/*
|
||||||
|
Serial.print(" - Current diff share: "); Serial.println(diff_hash,12);
|
||||||
|
Serial.print(" - Current pool diff : "); Serial.println(mMiner.poolDifficulty,12);
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Serial.print(" - TX SHARE: ");
|
||||||
|
for (size_t i = 0; i < 32; i++)
|
||||||
|
Serial.printf("%02x", hash[i]);
|
||||||
|
*/
|
||||||
|
#ifdef DEBUG_MINING
|
||||||
|
Serial.println("");
|
||||||
|
Serial.print(" - Current nonce: "); Serial.println(nonce);
|
||||||
|
Serial.print(" - Current block header: ");
|
||||||
|
for (size_t i = 0; i < 80; i++) {
|
||||||
|
Serial.printf("%02x", mMiner.bytearray_blockheader[i]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Serial.println("");
|
||||||
|
mLastTXtoPool = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.println ("MINER WORK ABORTED >> waiting new job");
|
||||||
|
mMiner.inRun = false;
|
||||||
|
uint32_t duration = micros() - startT;
|
||||||
|
/*
|
||||||
|
if (esp_task_wdt_reset() == ESP_OK)
|
||||||
|
Serial.print(">>> Resetting watchdog timer");
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#define DELAY 100
|
#define DELAY 100
|
||||||
#define REDRAW_EVERY 10
|
#define REDRAW_EVERY 10
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#define MAX_NONCE_STEP 5000000U
|
#define MAX_NONCE_STEP 5000000U
|
||||||
#define MAX_NONCE 25000000U
|
#define MAX_NONCE 25000000U
|
||||||
#define TARGET_NONCE 471136297U
|
#define TARGET_NONCE 471136297U
|
||||||
#define DEFAULT_DIFFICULTY 1e-4
|
#define DEFAULT_DIFFICULTY 64 // 1e-4 TODO-NOS
|
||||||
#define KEEPALIVE_TIME_ms 30000
|
#define KEEPALIVE_TIME_ms 30000
|
||||||
#define POOLINACTIVITY_TIME_ms 60000
|
#define POOLINACTIVITY_TIME_ms 60000
|
||||||
|
|
||||||
@ -15,6 +15,7 @@
|
|||||||
void runMonitor(void *name);
|
void runMonitor(void *name);
|
||||||
void runStratumWorker(void *name);
|
void runStratumWorker(void *name);
|
||||||
void runMiner(void *name);
|
void runMiner(void *name);
|
||||||
|
void runASIC(void *name);
|
||||||
String printLocalTime(void);
|
String printLocalTime(void);
|
||||||
|
|
||||||
void resetStat();
|
void resetStat();
|
||||||
|
@ -55,11 +55,15 @@ bool tx_mining_subscribe(WiFiClient& client, mining_subscribe& mSubscribe)
|
|||||||
|
|
||||||
// Subscribe
|
// Subscribe
|
||||||
id = 1; //Initialize id messages
|
id = 1; //Initialize id messages
|
||||||
|
#ifdef NERD_NOS
|
||||||
|
sprintf(payload, "{\"id\": %u, \"method\": \"mining.subscribe\", \"params\": [\"NerdNOS/%s\"]}\n", id, CURRENT_VERSION);
|
||||||
|
#else
|
||||||
#ifndef HAN
|
#ifndef HAN
|
||||||
sprintf(payload, "{\"id\": %u, \"method\": \"mining.subscribe\", \"params\": [\"NerdMinerV2/%s\"]}\n", id, CURRENT_VERSION);
|
sprintf(payload, "{\"id\": %u, \"method\": \"mining.subscribe\", \"params\": [\"NerdMinerV2/%s\"]}\n", id, CURRENT_VERSION);
|
||||||
#else
|
#else
|
||||||
sprintf(payload, "{\"id\": %u, \"method\": \"mining.subscribe\", \"params\": [\"HAN_SOLOminer/%s\"]}\n", id, CURRENT_VERSION);
|
sprintf(payload, "{\"id\": %u, \"method\": \"mining.subscribe\", \"params\": [\"HAN_SOLOminer/%s\"]}\n", id, CURRENT_VERSION);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
Serial.printf("[WORKER] ==> Mining subscribe\n");
|
Serial.printf("[WORKER] ==> Mining subscribe\n");
|
||||||
Serial.print(" Sending : "); Serial.println(payload);
|
Serial.print(" Sending : "); Serial.println(payload);
|
||||||
@ -226,6 +230,28 @@ bool tx_mining_submit(WiFiClient& client, mining_subscribe mWorker, mining_job m
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool tx_mining_submit_with_version(WiFiClient& client, mining_subscribe mWorker, const bm_job_t* asic_job, uint32_t extranonce2, unsigned long nonce, uint32_t version)
|
||||||
|
{
|
||||||
|
char payload[BUFFER] = {0};
|
||||||
|
|
||||||
|
// Submit
|
||||||
|
id = getNextId(id);
|
||||||
|
sprintf(payload, "{\"id\": %u, \"method\": \"mining.submit\", \"params\": [\"%s\",\"%s\",\"%s\",\"%08lx\",\"%08lx\",\"%08lx\"]}\n",
|
||||||
|
id,
|
||||||
|
mWorker.wName,
|
||||||
|
asic_job->jobid,
|
||||||
|
asic_job->extranonce2,
|
||||||
|
asic_job->ntime,
|
||||||
|
nonce,
|
||||||
|
version ^ asic_job->version
|
||||||
|
);
|
||||||
|
Serial.print(" Sending : "); Serial.print(payload);
|
||||||
|
client.print(payload);
|
||||||
|
//Serial.print(" Receiving: "); Serial.println(client.readStringUntil('\n'));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool parse_mining_set_difficulty(String line, double& difficulty)
|
bool parse_mining_set_difficulty(String line, double& difficulty)
|
||||||
{
|
{
|
||||||
Serial.println(" Parsing Method [SET DIFFICULTY]");
|
Serial.println(" Parsing Method [SET DIFFICULTY]");
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
#include "drivers/nerd-nos/mining.h"
|
||||||
|
|
||||||
#define MAX_MERKLE_BRANCHES 32
|
#define MAX_MERKLE_BRANCHES 32
|
||||||
#define HASH_SIZE 32
|
#define HASH_SIZE 32
|
||||||
@ -61,6 +62,7 @@ bool parse_mining_notify(String line, mining_job& mJob);
|
|||||||
|
|
||||||
//Method Mining.submit
|
//Method Mining.submit
|
||||||
bool tx_mining_submit(WiFiClient& client, mining_subscribe mWorker, mining_job mJob, unsigned long nonce);
|
bool tx_mining_submit(WiFiClient& client, mining_subscribe mWorker, mining_job mJob, unsigned long nonce);
|
||||||
|
bool tx_mining_submit_with_version(WiFiClient& client, mining_subscribe mWorker, const bm_job_t* asic_job, uint32_t extranonce2, unsigned long nonce, uint32_t version);
|
||||||
|
|
||||||
//Difficulty Methods
|
//Difficulty Methods
|
||||||
bool tx_suggest_difficulty(WiFiClient& client, double difficulty);
|
bool tx_suggest_difficulty(WiFiClient& client, double difficulty);
|
||||||
|
Loading…
Reference in New Issue
Block a user