Merge pull request #490 from shufps/nerdnos

Nerdnos
This commit is contained in:
BitMaker 2024-09-16 03:06:44 +02:00 committed by GitHub
commit df06ff17eb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 2077 additions and 222 deletions

View File

@ -126,12 +126,12 @@
//#include <User_Setups/Setup202_SSD1351_128.h> // Setup file for ESP32/ESP8266 based SSD1351 128x128 1.5inch OLED display
//#include <User_Setups/Setup203_ST7789.h> // Setup file for ESP32/ESP8266 based ST7789 240X280 1.69inch TFT
//#include <User_Setups/Setup203_ST7789.h> // Setup file for ESP32/ESP8266 based ST7789 240X280 1.69inch TFT
//#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
#ifdef NERDMINERV2
//#include <User_Setups/Setup205_ESP32_TouchDown_S3.h> // Setup file for the ESP32 TouchDown S3 based on ILI9488 480 x 320 TFT
#if defined(NERDMINERV2) || defined(NERD_NOS)
#include <User_Setups/Setup206_LilyGo_T_Display_S3.h>
#endif
#ifdef NERMINER_S3_AMOLED
@ -196,7 +196,7 @@
#endif
// Legacy setup support, RPI_ILI9486_DRIVER form is deprecated
// Instead define RPI_DISPLAY_TYPE and also define driver (e.g. ILI9486_DRIVER)
// Instead define RPI_DISPLAY_TYPE and also define driver (e.g. ILI9486_DRIVER)
#if defined (RPI_ILI9486_DRIVER)
#if !defined (ILI9486_DRIVER)
#define ILI9486_DRIVER

View File

@ -11,13 +11,14 @@
[platformio]
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]
platform = espressif32@6.6.0
board = m5stick-c
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
@ -26,16 +27,16 @@ monitor_speed = 115200
upload_speed = 1500000
# 2 x 4.5MB app, 6.875MB SPIFFS
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-D M5STICK_C=1
;-D DEBUG_MINING=1
lib_deps =
lib_deps =
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
m5stack/M5StickC@^0.2.5
lib_ignore =
lib_ignore =
TFT_eSPI
SD
SD_MMC
@ -48,14 +49,14 @@ lib_ignore =
platform = espressif32@6.6.0
board = esp-wrover-kit
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
monitor_speed = 115200
upload_speed = 921600
board_build.partitions = huge_app.csv
lib_deps =
lib_deps =
fbiego/ESP32Time@^2.0.6
bblanchon/ArduinoJson@^6.21.5
lvgl/lvgl@^8.4.0
@ -63,7 +64,7 @@ lib_deps =
https://github.com/tzapu/WiFiManager.git#v2.0.17
arduino-libraries/NTPClient@^3.2.1
mathertel/OneButton@^2.5.0
build_flags =
build_flags =
-D BOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-I lib
@ -80,7 +81,7 @@ lib_ignore =
platform = espressif32@6.6.0
board = esp32-s3-devkitc-1
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
@ -89,7 +90,7 @@ upload_speed = 921600
board_build.partitions = default_8MB.csv
board_build.mcu = esp32s3
board_build.f_cpu = 240000000L
lib_deps =
lib_deps =
fbiego/ESP32Time@^2.0.6
bblanchon/ArduinoJson@^6.21.5
lvgl/lvgl@^8.4.0
@ -97,7 +98,7 @@ lib_deps =
https://github.com/tzapu/WiFiManager.git#v2.0.17
arduino-libraries/NTPClient@^3.2.1
mathertel/OneButton@^2.5.0
build_flags =
build_flags =
-D BOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-I lib
@ -115,7 +116,7 @@ lib_ignore =
platform = espressif32@6.6.0
board = lolin_s3_mini
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
@ -123,21 +124,21 @@ board_build.arduino.memory_type = qio_opi
monitor_speed = 115200
upload_speed = 115200
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-D BOARD_HAS_PSRAM
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1
-D ESP32RGB=1
-D RGB_LED_PIN=47
;-D DEBUG_MINING=1
lib_deps =
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
fastled/FastLED@^3.6.0
lib_ignore =
lib_ignore =
TFT_eSPI
HANSOLOminerv2
@ -160,13 +161,13 @@ build_flags =
-D HAN=1
-D M5STACK_BOARD=1
;-D DEBUG_MINING=1
lib_deps =
lib_deps =
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
m5stack/M5Stack@^0.4.6
lib_ignore =
lib_ignore =
TFT_eSPI
HANSOLOminerv2
@ -177,26 +178,26 @@ lib_ignore =
platform = espressif32@6.6.0
board = lolin_s2_mini
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
monitor_speed = 115200
upload_speed = 115200
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-D BOARD_HAS_PSRAM
-D DEVKITV1=1
-D PIN_BUTTON_1=0
-D LED_PIN=15
;-D DEBUG_MINING=1
lib_deps =
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 =
lib_ignore =
TFT_eSPI
HANSOLOminerv2
@ -206,7 +207,7 @@ lib_ignore =
platform = espressif32@6.6.0
board = lolin_s3_mini
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
@ -214,21 +215,21 @@ board_build.arduino.memory_type = qio_opi
monitor_speed = 115200
upload_speed = 115200
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-D BOARD_HAS_PSRAM
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1
-D ESP32RGB=1
-D RGB_LED_PIN=48
;-D DEBUG_MINING=1
lib_deps =
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
fastled/FastLED@^3.6.0
lib_ignore =
lib_ignore =
TFT_eSPI
HANSOLOminerv2
@ -241,26 +242,26 @@ lib_ignore =
platform = espressif32@6.6.0
board = esp32dev
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
monitor_speed = 115200
upload_speed = 115200
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-D DEVKITV1=1
-D PIN_BUTTON_1=0
-D LED_PIN=22
-D ACTIVE_LED=LOW
-D INACTIVE_LED=HIGH
lib_deps =
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 =
lib_ignore =
TFT_eSPI
HANSOLOminerv2
@ -270,27 +271,27 @@ lib_ignore =
platform = espressif32@6.6.0
board = seeed_xiao_esp32c3
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
monitor_speed = 115200
upload_speed = 115200
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1
-D DEVKITV1=1
-D PIN_BUTTON_1=9
-D LED_PIN=8
;-D DEBUG_MINING=1
lib_deps =
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 =
lib_ignore =
TFT_eSPI
HANSOLOminerv2
@ -300,28 +301,28 @@ lib_ignore =
platform = espressif32@6.6.0
board = esp32-c3-devkitm-1
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
monitor_speed = 115200
upload_speed = 115200
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1
-D ESP32RGB=1
-D PIN_BUTTON_1=9
-D RGB_LED_PIN=8
;-D DEBUG_MINING=1
lib_deps =
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
fastled/FastLED@^3.6.0
lib_ignore =
lib_ignore =
TFT_eSPI
HANSOLOminerv2
@ -331,7 +332,7 @@ lib_ignore =
platform = espressif32@6.6.0
board = esp32-s3-devkitc-1
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
@ -339,21 +340,21 @@ board_build.arduino.memory_type = qio_opi
monitor_speed = 115200
upload_speed = 115200
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-D BOARD_HAS_PSRAM
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1
-D ESP32RGB=1
-D RGB_LED_PIN=48
;-D DEBUG_MINING=1
lib_deps =
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
fastled/FastLED@^3.6.0
lib_ignore =
lib_ignore =
TFT_eSPI
HANSOLOminerv2
@ -363,7 +364,7 @@ lib_ignore =
platform = espressif32@6.6.0
board = esp32-s3-devkitc-1
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
@ -375,29 +376,31 @@ upload_speed = 115200
;board_build.partitions = default_8MB.csv
board_build.partitions = huge_app.csv
;board_build.partitions = default.csv
build_flags =
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 NERDMINERV2=1
;-D DEBUG_MINING=1
lib_deps =
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 =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
[env:Lilygo-T-Embed]
;--------------------------------------------------------------------
[env:NerdNOS]
platform = espressif32@6.6.0
board = esp32-s3-devkitc-1
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
@ -409,20 +412,52 @@ upload_speed = 115200
;board_build.partitions = default_8MB.csv
board_build.partitions = huge_app.csv
;board_build.partitions = default.csv
build_flags =
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]
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 LILYGO_S3_T_EMBED=1
;-D DEBUG_MINING=1
lib_deps =
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 =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
@ -431,7 +466,7 @@ lib_ignore =
platform = espressif32@6.6.0
board = esp32dev
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
@ -440,16 +475,16 @@ monitor_speed = 115200
upload_speed = 115200
# 2 x 4.5MB app, 6.875MB SPIFFS
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-D DEVKITV1=1
;-D DEBUG_MINING=1
lib_deps =
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 =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
@ -458,7 +493,7 @@ lib_ignore =
platform = espressif32@6.6.0
board = esp32dev ;esp-wrover-kit
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
@ -468,18 +503,18 @@ monitor_speed = 115200
upload_speed = 115200
# 2 x 4.5MB app, 6.875MB SPIFFS
board_build.partitions = huge_app.csv
build_flags =
build_flags =
;-D DEBUG_MINING=1
# Switching from 'TDISPLAY' to 'NERDMINER_T_DISPLAY_V1' fixes font related compile errors
;-D TDISPLAY=1
-D NERDMINER_T_DISPLAY_V1=1
lib_deps =
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 =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
@ -489,19 +524,19 @@ platform = espressif32@6.6.0
board = lilygo-t-amoled
framework = arduino
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-DNERMINER_S3_AMOLED
-DTOUCH=0
-DBOARD_HAS_PSRAM
-DARDUINO_USB_CDC_ON_BOOT
lib_deps =
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
https://github.com/golden-guy/Arduino_wolfssl.git#v5.5.4
lib_ignore =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
@ -511,19 +546,19 @@ platform = espressif32@6.6.0
board = lilygo-t-amoled
framework = arduino
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-DNERMINER_S3_AMOLED
-DTOUCH=1
-DBOARD_HAS_PSRAM
-DARDUINO_USB_CDC_ON_BOOT
lib_deps =
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
https://github.com/golden-guy/Arduino_wolfssl.git#v5.5.4
lib_ignore =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
@ -533,20 +568,20 @@ platform = espressif32@6.6.0
board = esp32-s3-devkitc-1
framework = arduino
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-DNERMINER_S3_DONGLE
-DBOARD_HAS_PSRAM
-DARDUINO_USB_CDC_ON_BOOT
-DTFT_BACKLIGHT_ON=LOW
-DTFT_BL=38
lib_deps =
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
fastled/FastLED@^3.6.0
lib_ignore =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
@ -556,7 +591,7 @@ platform = espressif32@6.6.0
board = esp32-s3-devkitc-1
framework = arduino
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-DNERMINER_S3_GEEK
-DBOARD_HAS_PSRAM
-DARDUINO_USB_CDC_ON_BOOT
@ -566,13 +601,13 @@ build_flags =
-DSDSPI_MISO=37
-DSDSPI_CS=34
-DSD_ID=HSPI
lib_deps =
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 =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
@ -581,7 +616,7 @@ lib_ignore =
platform = espressif32@6.6.0 ;(ESP32-D0WD-V3)
board = esp32cam
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
@ -589,19 +624,19 @@ monitor_speed = 115200
upload_speed = 921600
board_build.partitions = huge_app.csv
board_build.arduino.memory_type = dio_qspi
build_flags =
build_flags =
-D ESP32_CAM
-D BOARD_HAS_PSRAM
-D MONITOR_SPEED=${this.monitor_speed}
;-D DEBUG_MINING
;-D DEBUG_MEMORY
lib_deps =
lib_deps =
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
https://github.com/takkaO/OpenFontRender#v1.2
lib_ignore =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
@ -610,23 +645,23 @@ lib_ignore =
platform = espressif32@6.6.0
board = esp32-s3-t-qt-pro
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
;board_build.arduino.memory_type = qio_opi
monitor_speed = 115200
upload_speed = 115200
build_flags =
build_flags =
-D BOARD_HAS_PSRAM
-D NERMINER_T_QT=1
lib_deps =
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 =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
@ -643,7 +678,7 @@ monitor_speed = 115200
upload_speed = 921600
;build_type = debug
board_build.partitions = huge_app.csv
build_flags =
build_flags =
;-DDEBUG_MEMORY=1
-D ESP32_2432S028_2USB=1
-DTFT_INVERSION_ON
@ -670,7 +705,7 @@ build_flags =
-DSPI_FREQUENCY=55000000
-DSPI_READ_FREQUENCY=20000000
-DSPI_TOUCH_FREQUENCY=2500000
lib_deps =
lib_deps =
https://github.com/takkaO/OpenFontRender#v1.2
bblanchon/ArduinoJson@^6.21.5
https://github.com/tzapu/WiFiManager.git#v2.0.17
@ -678,7 +713,7 @@ lib_deps =
arduino-libraries/NTPClient@^3.2.1
bodmer/TFT_eSPI@^2.5.43
https://github.com/achillhasler/TFT_eTouch
lib_ignore =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
@ -688,17 +723,17 @@ platform = espressif32@6.6.0
board = esp32dev
framework = arduino
monitor_speed = 115200
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
time
colorize
;debug
upload_speed = 921600
;build_type = debug
board_build.partitions = huge_app.csv
build_flags =
build_flags =
;-DDEBUG_MEMORY=1
-D ESP32_2432S028R=1
-D ESP32_2432S028R=1
-DUSER_SETUP_LOADED=1
-DILI9341_2_DRIVER=1
-DTFT_WIDTH=240
@ -722,8 +757,8 @@ build_flags =
-DSPI_FREQUENCY=55000000
-DSPI_READ_FREQUENCY=20000000
-DSPI_TOUCH_FREQUENCY=2500000
lib_deps =
lib_deps =
https://github.com/takkaO/OpenFontRender#v1.2
bblanchon/ArduinoJson@^6.21.5
https://github.com/tzapu/WiFiManager.git#v2.0.17
@ -731,7 +766,7 @@ lib_deps =
arduino-libraries/NTPClient@^3.2.1
bodmer/TFT_eSPI@^2.5.43
https://github.com/achillhasler/TFT_eTouch
lib_ignore =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
@ -768,7 +803,7 @@ lib_deps =
arduino-libraries/NTPClient
bodmer/TFT_eSPI @ ^2.5.31
https://github.com/achillhasler/TFT_eTouch
lib_ignore =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
@ -780,16 +815,16 @@ framework = arduino
monitor_speed = 115200
upload_speed = 115200
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-D NERDMINER_T_DISPLAY_V1=1
-D DEBUG_MINING=1
lib_deps =
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
https://github.com/arduino-libraries/NTPClient@^3.2.1
lib_ignore =
lib_ignore =
HANSOLOminerv2
;--------------------------------------------------------------------
@ -798,25 +833,25 @@ lib_ignore =
platform = espressif32@6.6.0
board = m5stack-stamps3
framework = arduino
monitor_filters =
monitor_filters =
esp32_exception_decoder
time
log2file
monitor_speed = 115200
upload_speed = 115200
board_build.partitions = huge_app.csv
build_flags =
build_flags =
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1
-D ESP32RGB=1
-D RGB_LED_PIN=21
lib_deps =
lib_deps =
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
fastled/FastLED@^3.6.0
lib_ignore =
lib_ignore =
TFT_eSPI
SD
rm67162

View File

@ -14,6 +14,13 @@
#include "drivers/displays/display.h"
#include "drivers/storage/SDCard.h"
#include "timeconst.h"
#include "drivers/nerd-nos/bm1397.h"
#include "drivers/nerd-nos/serial.h"
#include "drivers/nerd-nos/adc.h"
#ifdef NERD_NOS
#include "mining_nerdnos.h"
#endif
#ifdef TOUCH_ENABLE
#include "TouchHandler.h"
@ -40,7 +47,7 @@ extern monitor_data mMonitor;
#ifdef SD_ID
SDCard SDCrd = SDCard(SD_ID);
#else
#else
SDCard SDCrd = SDCard();
#endif
@ -49,7 +56,13 @@ extern monitor_data mMonitor;
unsigned long start = millis();
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 *****/
void setup()
@ -100,7 +113,7 @@ void setup()
/******** INIT DISPLAY ************/
initDisplay();
/******** PRINT INIT SCREEN *****/
drawLoadingScreen();
delay(2*SECOND_MS);
@ -134,7 +147,20 @@ void setup()
BaseType_t res2 = xTaskCreatePinnedToCore(runStratumWorker, "Stratum", 15000, (void*)name, 3, NULL,1);
#endif
/******** CREATE MINER TASKS *****/
#ifdef NERD_NOS
nerdnos_adc_init();
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 *****/
//for (size_t i = 0; i < THREADS; i++) {
// char *name = (char*) malloc(32);
// sprintf(name, "(%d)", i);
@ -144,14 +170,16 @@ void setup()
TaskHandle_t minerTask1, minerTask2 = NULL;
xTaskCreate(runMiner, "Miner0", 6000, (void*)0, 1, &minerTask1);
xTaskCreate(runMiner, "Miner1", 6000, (void*)1, 1, &minerTask2);
esp_task_wdt_add(minerTask1);
esp_task_wdt_add(minerTask2);
#endif
/******** MONITOR SETUP *****/
setup_monitor();
}
void app_error_fault_handler(void *arg) {
// Get stack errors
char *stack = (char *)arg;

View File

@ -5,7 +5,7 @@
* Description:
* NerdSha256plus is a custom C implementation of sha256d based on Blockstream Jade
* NerdSha256plus is a custom C implementation of sha256d based on Blockstream Jade
code https://github.com/Blockstream/Jade
The folowing file can be used on any ESP32 implementation using both cores
@ -19,7 +19,7 @@
#include <stdint.h>
struct nerdSHA256_context {
struct __attribute__((__packed__)) nerdSHA256_context {
uint8_t buffer[64];
uint32_t digest[8];
};

View File

@ -3,6 +3,8 @@
#if defined(NERDMINERV2)
#include "nerdMinerV2.h"
#elif defined(NERD_NOS)
#include "nerdnos.h"
#elif defined(M5STICK_C)
#include "M5Stick-C.h"
#elif defined(DEVKITV1)

View 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

View File

@ -25,7 +25,7 @@ void tDisplay_Init(void)
pinMode(PIN_ENABLE5V, OUTPUT);
digitalWrite(PIN_ENABLE5V, HIGH);
#endif
tft.init();
#ifdef LILYGO_S3_T_EMBED
tft.setRotation(ROTATION_270);
@ -65,9 +65,14 @@ void tDisplay_MinerScreen(unsigned long mElapsed)
// Print background screen
background.pushImage(0, 0, MinerWidth, MinerHeight, MinerScreen);
#ifdef NERD_NOS
Serial.printf(">>> Completed %s share(s), %s Khashes, avg. hashrate %s GH/s, vCore: %smV, temp: %s°C\n",
data.completedShares.c_str(), data.totalKHashes.c_str(), data.currentHashRate.c_str(),
data.vcore.c_str(), data.currentTemperature.c_str());
#else
Serial.printf(">>> Completed %s share(s), %s Khashes, avg. hashrate %s KH/s\n",
data.completedShares.c_str(), data.totalKHashes.c_str(), data.currentHashRate.c_str());
#endif
// Hashrate
render.setFontSize(35);
@ -211,7 +216,7 @@ void tDisplay_BTCprice(unsigned long mElapsed)
{
clock_data data = getClockData(mElapsed);
data.currentDate ="01/12/2023";
//if(data.currentDate.indexOf("12/2023")>) { tDisplay_ChristmasContent(data); return; }
// Print background screen
@ -231,14 +236,14 @@ void tDisplay_BTCprice(unsigned long mElapsed)
render.rdrawString(data.blockHeight.c_str(), 254, 138, TFT_WHITE);
// Print Hour
background.setFreeFont(FSSB9);
background.setTextSize(1);
background.setTextDatum(TL_DATUM);
background.setTextColor(TFT_BLACK);
background.drawString(data.currentTime.c_str(), 222, 3, GFXFF);
// Print BTC Price
// Print BTC Price
background.setFreeFont(FF24);
background.setTextDatum(TR_DATUM);
background.setTextSize(1);

View File

@ -0,0 +1,56 @@
#include <stdio.h>
#include <math.h>
#include "driver/adc.h"
#include "esp_adc_cal.h"
#define NTC_CHANNEL ADC1_CHANNEL_1 // 10k NTC
#define VCORE_CHANNEL ADC1_CHANNEL_2 // vcore voltage
#define BETA 3380 // Beta value of the thermistor
#define R0 10000 // Resistance at 25°C (10kΩ)
#define ADC_MAX 4095 // Max ADC value for 12-bit resolution
#define DEFAULT_VREF 1100 // Default VREF in millivolts for ESP32 ADC
// ADC Calibration characteristics
static esp_adc_cal_characteristics_t adc1_chars;
void nerdnos_adc_init() {
// Configure the ADC
adc1_config_width(ADC_WIDTH_BIT_12); // Set ADC width (12-bit)
adc1_config_channel_atten(NTC_CHANNEL, ADC_ATTEN_DB_11); // Set attenuation to read the full range of 0 to 3.3V
adc1_config_channel_atten(VCORE_CHANNEL, ADC_ATTEN_DB_11); // Set attenuation to read the full range of 0 to 3.3V
// Characterize ADC at given attenuation
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 0, &adc1_chars);
}
float nerdnos_get_temperature() {
// Convert the raw ADC value to a voltage using esp_adc_cal
uint32_t voltage_mv = esp_adc_cal_raw_to_voltage(adc1_get_raw(NTC_CHANNEL), &adc1_chars); // Voltage in millivolts
// Convert millivolts to volts
float voltage = voltage_mv / 1000.0;
// Ensure the voltage is within a valid range
if (voltage <= 0) {
printf("Error: Invalid voltage reading.\n");
return -273.15; // Return a clearly invalid temperature to indicate an error
}
// Calculate the thermistor resistance using the voltage divider formula
// R_T = R0 * (Vout / (VREF - Vout))
float thermistor_resistance = R0 * (voltage / (3.3 - voltage));
// Use the Beta parameter equation to calculate the temperature in Kelvin
float temperature_kelvin = (float)(BETA / (log(thermistor_resistance / R0) + (BETA / 298.15)));
// Convert the temperature to Celsius
float temperature_celsius = temperature_kelvin - 273.15;
return temperature_celsius;
}
float nerdnos_get_vcore() {
return esp_adc_cal_raw_to_voltage(adc1_get_raw(VCORE_CHANNEL), &adc1_chars);
}

View File

@ -0,0 +1,5 @@
#pragma once
void nerdnos_adc_init();
float nerdnos_get_temperature();
float nerdnos_get_vcore();

View File

@ -0,0 +1,414 @@
#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"
#include "utils.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 const uint8_t chip_id[] = {0xAA, 0x55, 0x13, 0x97, 0x18, 0x00};
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);
// memory for buffer
uint8_t buf[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);
}
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, BM1397_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, BM1397_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, BM1397_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, BM1397_SERIALTX_DEBUG);
}
for (i = 0; i < 2; i++)
{
vTaskDelay(10 / portTICK_PERIOD_MS);
_send_BM1397((TYPE_CMD | GROUP_ALL | CMD_WRITE), freqbufall, 6, BM1397_SERIALTX_DEBUG);
}
vTaskDelay(10 / portTICK_PERIOD_MS);
Serial.printf("Setting Frequency to %.2fMHz (%.2f)\n", frequency, newf);
}
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(buf, 9, 1000);
if (received > 0 && !memcmp(chip_id, buf, sizeof(chip_id))) {
chip_counter++;
} else {
break;
}
}
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);
_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, BM1397_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, BM1397_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, BM1397_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, BM1397_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, BM1397_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, BM1397_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)
{
Serial.println("Initializing BM1397");
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, BM1397_SERIALTX_DEBUG);
return 115749;
}
int BM1397_set_max_baud(void)
{
// divider of 0 for 3,125,000
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);
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);
}
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);
}
void BM1397_send_work(bm_job_t *next_bm_job, uint8_t job_id)
{
job_packet_t 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
job.job_id = (job_id * 4) % 128;
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_t), BM1397_DEBUG_WORK);
}
bool BM1397_receive_work(uint16_t timeout, asic_result *result)
{
uint8_t *rcv_buf = (uint8_t*) result;
// non blocking read
int received = SERIAL_rx_non_blocking(rcv_buf, 9);
if (received < 0)
{
Serial.println("Error in serial RX");
return false;
}
else if (!received)
{
// we have not received any data
return false;
}
if (received != 9 || rcv_buf[0] != 0xAA || rcv_buf[1] != 0x55)
{
Serial.println("Serial RX invalid. Resetting receive buffer ...");
SERIAL_clear_buffer();
return false;
}
return true;
}
bool BM1397_proccess_work(uint32_t version, uint16_t timeout, task_result *result)
{
asic_result asic_result;
if (!BM1397_receive_work(timeout, &asic_result))
{
ESP_LOGI(TAG, "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;
uint32_t rolled_version = version;
for (int i = 0; i < rx_midstate_index; i++)
{
rolled_version = increment_bitmask(rolled_version, 0x1fffe000);
}
result->job_id = rx_job_id;
result->nonce = asic_result.nonce;
result->rolled_version = rolled_version;
return true;
}

View File

@ -0,0 +1,21 @@
#pragma once
#include <stdio.h>
#include "nerdnos.h"
#include "crc.h"
#define CRC5_MASK 0x1F
#define BM1397_SERIALTX_DEBUG false
#define BM1397_SERIALRX_DEBUG true //false
#define BM1397_DEBUG_WORK false //causes insane amount of debug output
uint8_t BM1397_init(uint64_t frequency, uint16_t asic_count);
void BM1397_send_work(bm_job_t * next_bm_job, uint8_t job_id);
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);
bool BM1397_proccess_work(uint32_t version, uint16_t timeout, task_result *result);

View File

@ -0,0 +1,6 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
void printBufferHex(const char *prefix, const uint8_t* buf, size_t len);

View 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;
}

View File

@ -0,0 +1,8 @@
#pragma once
#include <stdint.h>
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);

View File

@ -0,0 +1,157 @@
#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"
#include "../../mining.h"
///////cgminer nonce testing
/* truediffone == 0x00000000FFFF0000000000000000000000000000000000000000000000000000
*/
static const double truediffone = 26959535291011309493156476344723991336010898738574164086137773096960.0;
/* testing a nonce and return the diff - 0 means invalid */
double nerdnos_test_nonce_value(const bm_job_t *job, const uint32_t nonce, const uint32_t rolled_version, uint8_t hash_result[32])
{
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];
// 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;
}
static 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++) {
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);
}
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
static 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 nerdnos_create_job(mining_subscribe *mWorker, mining_job *job, bm_job_t *next_job, uint32_t extranonce_2, uint32_t stratum_difficulty) {
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);
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;
}
void nerdnos_send_work(bm_job_t *next_bm_job, uint8_t job_id) {
BM1397_send_work(next_bm_job, job_id);
}
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) {
free(job->jobid);
free(job->extranonce2);
// mark as free
job->ntime = 0;
}
void nerdnos_set_asic_difficulty(uint32_t difficulty) {
BM1397_set_job_difficulty_mask(difficulty);
}

View File

@ -0,0 +1,25 @@
#pragma once
#include <stdint.h>
#include "nerdnos.h"
// forward declaration to resolve circular inclusions
typedef struct mining_subscribe mining_subscribe;
typedef struct mining_job mining_job;
// set the asic hardware difficulty
void nerdnos_set_asic_difficulty(uint32_t current_difficulty);
// create asic job
void nerdnos_create_job(mining_subscribe *mWorker, mining_job *job, bm_job_t *next_job, uint32_t extranonce_2, uint32_t stratum_difficulty);
// send new work to the asic
void nerdnos_send_work(bm_job_t *next_bm_job, uint8_t job_id);
// receive and process responses
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]);
// free allocated RAM for strings on bm_job_t
void nerdnos_free_bm_job(bm_job_t *job);

View File

@ -0,0 +1,66 @@
#pragma once
#include <stdint.h>
#define BM1397_INITIAL_DIFFICULTY 128
typedef struct __attribute__((__packed__))
{
uint8_t job_id;
uint32_t nonce;
uint32_t rolled_version;
} task_result;
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;
uint32_t pool_diff;
} bm_job_t;
/*
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_t;

View File

@ -0,0 +1,104 @@
#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);
}
size_t SERIAL_check_for_data() {
size_t length;
uart_get_buffered_data_len(UART_NUM_1, (size_t*)&length);
return length;
}
/// @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_non_blocking(uint8_t *buf, uint16_t size) {
// check how much data we have
size_t available = SERIAL_check_for_data();
// no data available, return 0
if (!available) {
return 0;
}
// check for incomplete data
if (available && available < size) {
Serial.printf("not returning incomplete data ... %d vs %d\n", (int) available, (int) size);
return 0;
}
// timeout 0 means non_blocking read
return SERIAL_rx(buf, size, 0);
}
/// @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_clear_buffer(void)
{
uart_flush(UART_NUM_1);
}

View File

@ -0,0 +1,11 @@
#pragma once
#define CHUNK_SIZE 1024
int SERIAL_send(uint8_t *, int, bool);
void SERIAL_init(void);
int16_t SERIAL_rx(uint8_t *, uint16_t, uint16_t);
int16_t SERIAL_rx_non_blocking(uint8_t *buf, uint16_t size);
void SERIAL_clear_buffer(void);
void SERIAL_set_baud(int baud);

View File

@ -0,0 +1,375 @@
#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;
}
}
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;
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;
}
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;
}
int largest_power_of_two(int num)
{
int power = 0;
while (num > 1) {
num = num >> 1;
power++;
}
return 1 << power;
}
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;
}

View File

@ -0,0 +1,44 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <stdbool.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);
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);

View File

@ -35,9 +35,9 @@ extern TSettings Settings;
IPAddress serverIP(1, 1, 1, 1); //Temporally save poolIPaddres
//Global work data
static WiFiClient client;
static miner_data mMiner; //Global miner data (Create a miner class TODO)
//Global work data
WiFiClient client;
miner_data mMiner; //Global miner data (Create a miner class TODO)
mining_subscribe mWorker;
mining_job mJob;
monitor_data mMonitor;
@ -49,15 +49,15 @@ int saveIntervalsSize = sizeof(saveIntervals)/sizeof(saveIntervals[0]);
int currentIntervalIndex = 0;
bool checkPoolConnection(void) {
if (client.connected()) {
return true;
}
isMinerSuscribed = false;
Serial.println("Client not connected, trying to connect...");
Serial.println("Client not connected, trying to connect...");
//Resolve first time pool DNS and save IP
if(serverIP == IPAddress(1,1,1,1)) {
WiFi.hostByName(Settings.PoolAddress.c_str(), serverIP);
@ -76,14 +76,14 @@ bool checkPoolConnection(void) {
return true;
}
//Implements a socketKeepAlive function and
//Implements a socketKeepAlive function and
//checks if pool is not sending any data to reconnect again.
//Even connection could be alive, pool could stop sending new job NOTIFY
unsigned long mStart0Hashrate = 0;
bool checkPoolInactivity(unsigned int keepAliveTime, unsigned long inactivityTime){
bool checkPoolInactivity(unsigned int keepAliveTime, unsigned long inactivityTime){
unsigned long currentKHashes = (Mhashes*1000) + hashes/1000;
unsigned long elapsedKHs = currentKHashes - totalKHashes;
unsigned long elapsedKHs = currentKHashes - totalKHashes;
// If no shares sent to pool
// send something to pool to hold socket oppened
@ -98,12 +98,14 @@ bool checkPoolInactivity(unsigned int keepAliveTime, unsigned long inactivityTim
}*/
}
#ifndef NERD_NOS
if(elapsedKHs == 0){
//Check if hashrate is 0 during inactivityTIme
if(mStart0Hashrate == 0) mStart0Hashrate = millis();
if(mStart0Hashrate == 0) mStart0Hashrate = millis();
if((millis()-mStart0Hashrate) > inactivityTime) { mStart0Hashrate=0; return true;}
return false;
}
#endif
mStart0Hashrate = 0;
return false;
@ -121,18 +123,18 @@ void runStratumWorker(void *name) {
#endif
// connect to pool
double currentPoolDifficulty = DEFAULT_DIFFICULTY;
while(true) {
if(WiFi.status() != WL_CONNECTED){
// WiFi is disconnected, so reconnect now
mMonitor.NerdStatus = NM_Connecting;
WiFi.reconnect();
vTaskDelay(5000 / portTICK_PERIOD_MS);
continue;
}
}
if(!checkPoolConnection()){
//If server is not reachable add random delay for connection retries
@ -148,11 +150,11 @@ void runStratumWorker(void *name) {
mWorker = init_mining_subscribe();
// STEP 1: Pool server connection (SUBSCRIBE)
if(!tx_mining_subscribe(client, mWorker)) {
if(!tx_mining_subscribe(client, mWorker)) {
client.stop();
continue;
continue;
}
strcpy(mWorker.wName, Settings.BtcWallet);
strcpy(mWorker.wPass, Settings.PoolPassword);
// STEP 2: Pool authorize work (Block Info)
@ -172,7 +174,7 @@ void runStratumWorker(void *name) {
Serial.println(" Detected more than 2 min without data form stratum server. Closing socket and reopening...");
client.stop();
isMinerSuscribed=false;
continue;
continue;
}
//Read pending messages from pool
@ -208,9 +210,9 @@ void runStratumWorker(void *name) {
}
vTaskDelay(500 / portTICK_PERIOD_MS); //Small delay
}
}
@ -218,7 +220,7 @@ void runStratumWorker(void *name) {
//This works only with one thread, TODO -> Class or miner_data for each thread
void runMiner(void * task_id) {
unsigned int miner_id = (uint32_t)task_id;
@ -245,7 +247,7 @@ void runMiner(void * task_id) {
//Prepare Premining data
nerdSHA256_context nerdMidstate; //NerdShaplus
uint8_t hash[32];
//Calcular midstate
nerd_mids(&nerdMidstate, mMiner.bytearray_blockheader); //NerdShaplus
@ -265,8 +267,8 @@ void runMiner(void * task_id) {
header64 = mMiner.bytearray_blockheader + 64;
else
header64 = mMiner.bytearray_blockheader2 + 64;
bool is16BitShare=true;
bool is16BitShare=true;
Serial.println(">>> STARTING TO HASH NONCES");
while(true) {
if (miner_id == 0)
@ -281,7 +283,7 @@ void runMiner(void * task_id) {
/*Serial.print("hash1: ");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x", hash[i]);
Serial.println("");
Serial.println("");
Serial.print("hash2: ");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x", hash2[i]);
@ -302,7 +304,7 @@ void runMiner(void * task_id) {
//Check target to submit
//Difficulty of 1 > 0x00000000FFFF0000000000000000000000000000000000000000000000000000
//NM2 pool diff 1e-9 > Target = diff_1 / diff_pool > 0x00003B9ACA00....00
//Swapping diff bytes little endian >>>>>>>>>>>>>>>> 0x0000DC59D300....00
//Swapping diff bytes little endian >>>>>>>>>>>>>>>> 0x0000DC59D300....00
//if((hash[29] <= 0xDC) && (hash[28] <= 0x59)) //0x00003B9ACA00 > diff value for 1e-9
double diff_hash = diff_from_target(hash);
@ -327,9 +329,9 @@ void runMiner(void * task_id) {
}
#endif
Serial.println("");
mLastTXtoPool = millis();
mLastTXtoPool = millis();
}
// check if 32bit share
if(hash[29] !=0 || hash[28] !=0) {
// increment nonce
@ -455,7 +457,7 @@ void runMonitor(void *name)
seconds_elapsed = 0;
if(currentIntervalIndex < saveIntervalsSize - 1)
currentIntervalIndex++;
}
}
}
animateCurrentScreen(frame);
doLedStuff(frame);

View File

@ -6,7 +6,7 @@
#define MAX_NONCE_STEP 5000000U
#define MAX_NONCE 25000000U
#define TARGET_NONCE 471136297U
#define DEFAULT_DIFFICULTY 1e-4
#define DEFAULT_DIFFICULTY 64 // 1e-4 TODO-NOS
#define KEEPALIVE_TIME_ms 30000
#define POOLINACTIVITY_TIME_ms 60000
@ -15,11 +15,12 @@
void runMonitor(void *name);
void runStratumWorker(void *name);
void runMiner(void *name);
void runASIC(void *name);
String printLocalTime(void);
void resetStat();
typedef struct{
typedef struct {
uint8_t bytearray_target[32];
uint8_t bytearray_pooltarget[32];
uint8_t merkle_result[32];

274
src/mining_nerdnos.cpp Normal file
View File

@ -0,0 +1,274 @@
#include <Arduino.h>
#include <ArduinoJson.h>
#include <WiFi.h>
#include <esp_task_wdt.h>
#include <nvs_flash.h>
#include <nvs.h>
//#include "ShaTests/nerdSHA256.h"
#include "ShaTests/nerdSHA256plus.h"
#include "stratum.h"
#include "mining.h"
#include "utils.h"
#include "monitor.h"
#include "timeconst.h"
#include "drivers/displays/display.h"
#include "drivers/storage/storage.h"
#include "drivers/nerd-nos/nerdnos.h"
#include "mining_nerdnos.h"
#include "drivers/nerd-nos/adc.h"
#include "drivers/nerd-nos/bm1397.h"
extern WiFiClient client;
extern mining_subscribe mWorker;
extern mining_job mJob;
extern miner_data mMiner;
extern monitor_data mMonitor;
extern pthread_mutex_t job_mutex;
extern double best_diff;
extern unsigned long mLastTXtoPool;
// we can have 32 different job ids
#define ASIC_JOB_COUNT 32
// to track the jobs
static bm_job_t asic_jobs[ASIC_JOB_COUNT] = {0};
// to track hashrate
#define ASIC_HISTORY_SIZE 128
// define temperature readings
#define MAX_SAFE_TEMP 80.0 // Define maximum safe temperature (in Celsius)
#define TEMP_CHECK_INTERVAL 5000 // Check temperature every 5 seconds (in milliseconds)
typedef struct {
uint32_t diffs[ASIC_HISTORY_SIZE];
uint64_t timestamps[ASIC_HISTORY_SIZE];
uint32_t newest;
uint32_t oldest;
uint64_t sum;
double avg_gh;
double duration;
int shares;
} history_t;
static pthread_mutex_t job_interval_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t job_interval_cond = PTHREAD_COND_INITIALIZER;
history_t history = {0};
double nerdnos_get_avg_hashrate() {
return history.avg_gh;
}
static void safe_free_job(bm_job_t *job) {
if (job && job->ntime) {
nerdnos_free_bm_job(job);
job->ntime = 0; // Only clear the ntime pointer to mark it free
}
}
// incremental ringbuffer based hashrate calculation
static void calculate_hashrate(history_t *history, uint32_t diff) {
// if we have wrapped around at least once our ringbuffer is full
// and we have to remove the oldest element
if (history->newest + 1 >= ASIC_HISTORY_SIZE) {
history->sum -= history->diffs[history->oldest % ASIC_HISTORY_SIZE];
history->oldest++;
}
// add and store the newest sample
history->sum += 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] = (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];
history->duration = (double) (newest_timestamp - oldest_timestamp) / 1.0e6;
history->shares = (int) history->newest - (int) history->oldest + 1;
if (history->duration) {
double avg = (double) (history->sum << 32llu) / history->duration;
history->avg_gh = avg / 1.0e9;
}
history->newest++;
}
// triggers the job creation
static void create_job_timer(TimerHandle_t xTimer)
{
pthread_mutex_lock(&job_interval_mutex);
pthread_cond_signal(&job_interval_cond);
pthread_mutex_unlock(&job_interval_mutex);
}
void runASIC(void * task_id) {
Serial.printf("[MINER] Started runASIC Task!\n");
// Create the timer
TimerHandle_t job_timer = xTimerCreate("NERDNOS_Job_Timer", NERDNOS_JOB_INTERVAL_MS / portTICK_PERIOD_MS, pdTRUE, NULL, create_job_timer);
if (job_timer == NULL) {
Serial.println("Failed to create NERDNOS timer");
return;
}
// Start the timer
if (xTimerStart(job_timer, 0) != pdPASS) {
Serial.println("Failed to start NERDNOS timer");
return;
}
uint32_t extranonce_2 = 0;
unsigned long lastTempCheck = 0;
while(1) {
// wait for new job
while(!mMiner.newJob) {
vTaskDelay(100 / portTICK_PERIOD_MS);
}
mMiner.newJob = false; //Clear newJob flag
mMiner.inRun = true; //Set inRun flag
Serial.println(">>> STARTING TO HASH NONCES");
uint32_t startT = micros();
memset(asic_jobs, 0, sizeof(asic_jobs));
// we are assuming the version doesn't change from job to job
uint32_t version = strtoul(mJob.version.c_str(), NULL, 16);
mMonitor.NerdStatus = NM_hashing;
uint32_t current_difficulty = 0;
while (mMiner.inRun) {
// wait for the timer to start a new job
// also yields the CPU
pthread_mutex_lock(&job_interval_mutex);
pthread_cond_wait(&job_interval_cond, &job_interval_mutex);
pthread_mutex_unlock(&job_interval_mutex);
// Temperature check
unsigned long currentTime = millis();
if (currentTime - lastTempCheck > TEMP_CHECK_INTERVAL) {
float currentTemp = nerdnos_get_temperature(); // Get ASIC temperature
if (currentTemp > MAX_SAFE_TEMP) {
gpio_set_level(NERD_NOS_GPIO_PEN, 0); // Disable Buck
Serial.println("ASIC temperature too high. Disabling power.");
// Wait for temperature to drop
while (nerdnos_get_temperature() > (MAX_SAFE_TEMP - 15)) { // 15 degree hysteresis
vTaskDelay(2000 / portTICK_PERIOD_MS); // Check every 2 second
}
gpio_set_level(NERD_NOS_GPIO_PEN, 1); // Enable Buck again
Serial.println("Temperature safe. Re-enabling ASIC.");
BM1397_init(200, 1); // Re-Init ASIC
}
lastTempCheck = currentTime;
}
// increment extranonce2
extranonce_2++;
// use extranonce2 as job id
uint8_t asic_job_id = (uint8_t) (extranonce_2 % ASIC_JOB_COUNT);
// free memory if this slot was used before
safe_free_job(&asic_jobs[asic_job_id]);
// create the next asic job
// make sure that another task doesn't mess with the data while
// we are using it
pthread_mutex_lock(&job_mutex);
nerdnos_create_job(&mWorker, &mJob, &asic_jobs[asic_job_id], extranonce_2, mMiner.poolDifficulty);
pthread_mutex_unlock(&job_mutex);
// don't send difficulty while the job mutex is locked
if (current_difficulty != asic_jobs[asic_job_id].pool_diff) {
current_difficulty = asic_jobs[asic_job_id].pool_diff;
nerdnos_set_asic_difficulty(current_difficulty);
Serial.printf("Set difficulty to %lu\n", current_difficulty);
}
// send the job and
nerdnos_send_work(&asic_jobs[asic_job_id], asic_job_id);
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);
continue;
}
uint8_t hash[32];
// check the nonce difficulty
double diff_hash = nerdnos_test_nonce_value(
&asic_jobs[result.job_id],
result.nonce,
result.rolled_version,
hash);
// update best diff
if (diff_hash > best_diff) {
best_diff = diff_hash;
}
// calculate the hashrate
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);
Serial.println("valid share!");
Serial.printf(" - Current diff share: %.3f\n", diff_hash);
Serial.printf(" - Current pool diff : %.3f\n", mMiner.poolDifficulty);
Serial.printf("Free heap after share: %u bytes\n", ESP.getFreeHeap());
for (size_t i = 0; i < 32; i++) {
Serial.printf("%02x", hash[i]);
}
Serial.println();
#ifdef DEBUG_MINING
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]);
}
Serial.println();
#endif
mLastTXtoPool = millis();
}
}
}
Serial.println("MINER WORK ABORTED >> waiting new job");
mMiner.inRun = false;
uint32_t duration = micros() - startT;
// clean jobs
for (int i = 0; i < ASIC_JOB_COUNT; i++) {
safe_free_job(&asic_jobs[i]);
}
/*
if (esp_task_wdt_reset() == ESP_OK)
Serial.print(">>> Resetting watchdog timer");
*/
}
}

6
src/mining_nerdnos.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#define NERDNOS_JOB_INTERVAL_MS 30
void runASIC(void * task_id);
double nerdnos_get_avg_hashrate();

View File

@ -9,6 +9,11 @@
#include "monitor.h"
#include "drivers/storage/storage.h"
#ifdef NERD_NOS
#include "mining_nerdnos.h"
#include "drivers/nerd-nos/adc.h"
#endif
extern uint32_t templates;
extern uint32_t hashes;
extern uint32_t Mhashes;
@ -24,7 +29,7 @@ extern double best_diff; // track best diff
extern monitor_data mMonitor;
//from saved config
extern TSettings Settings;
extern TSettings Settings;
bool invertColors = false;
WiFiUDP ntpUDP;
@ -40,7 +45,7 @@ void setup_monitor(void){
/******** TIME ZONE SETTING *****/
timeClient.begin();
// Adjust offset depending on your zone
// GMT +2 in seconds (zona horaria de Europa Central)
timeClient.setTimeOffset(3600 * Settings.Timezone);
@ -55,11 +60,11 @@ void setup_monitor(void){
unsigned long mGlobalUpdate =0;
void updateGlobalData(void){
if((mGlobalUpdate == 0) || (millis() - mGlobalUpdate > UPDATE_Global_min * 60 * 1000)){
if (WiFi.status() != WL_CONNECTED) return;
//Make first API call to get global hash and current difficulty
HTTPClient http;
try {
@ -68,7 +73,7 @@ void updateGlobalData(void){
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
DynamicJsonDocument doc(1024);
deserializeJson(doc, payload);
String temp = "";
@ -86,14 +91,14 @@ void updateGlobalData(void){
}
http.end();
//Make third API call to get fees
http.begin(getFees);
httpCode = http.GET();
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
DynamicJsonDocument doc(1024);
deserializeJson(doc, payload);
String temp = "";
@ -108,7 +113,7 @@ void updateGlobalData(void){
mGlobalUpdate = millis();
}
http.end();
} catch(...) {
http.end();
@ -119,11 +124,11 @@ void updateGlobalData(void){
unsigned long mHeightUpdate = 0;
String getBlockHeight(void){
if((mHeightUpdate == 0) || (millis() - mHeightUpdate > UPDATE_Height_min * 60 * 1000)){
if (WiFi.status() != WL_CONNECTED) return current_block;
HTTPClient http;
try {
http.begin(getHeightAPI);
@ -136,24 +141,24 @@ String getBlockHeight(void){
current_block = payload;
mHeightUpdate = millis();
}
}
http.end();
} catch(...) {
http.end();
}
}
return current_block;
}
unsigned long mBTCUpdate = 0;
String getBTCprice(void){
if((mBTCUpdate == 0) || (millis() - mBTCUpdate > UPDATE_BTC_min * 60 * 1000)){
if (WiFi.status() != WL_CONNECTED) return (String(bitcoin_price) + "$");
HTTPClient http;
try {
http.begin(getBTCAPI);
@ -170,13 +175,13 @@ String getBTCprice(void){
mBTCUpdate = millis();
}
http.end();
} catch(...) {
http.end();
}
}
return (String(bitcoin_price) + "$");
}
@ -186,7 +191,7 @@ unsigned long initialTime = 0;
unsigned long mPoolUpdate = 0;
void getTime(unsigned long* currentHours, unsigned long* currentMinutes, unsigned long* currentSeconds){
//Check if need an NTP call to check current time
if((mTriggerUpdate == 0) || (millis() - mTriggerUpdate > UPDATE_PERIOD_h * 60 * 60 * 1000)){ //60 sec. * 60 min * 1000ms
if(WiFi.status() == WL_CONNECTED) {
@ -206,7 +211,7 @@ void getTime(unsigned long* currentHours, unsigned long* currentMinutes, unsigne
}
String getDate(){
unsigned long elapsedTime = (millis() - mTriggerUpdate) / 1000; // Tiempo transcurrido en segundos
unsigned long currentTime = initialTime + elapsedTime; // La hora actual
@ -229,16 +234,39 @@ String getTime(void){
char LocalHour[10];
sprintf(LocalHour, "%02d:%02d", currentHours, currentMinutes);
String mystring(LocalHour);
return LocalHour;
}
#ifdef NERD_NOS
String getCurrentHashRate(unsigned long mElapsed) {
// we have too little space for 2 digits after the decimal point
return String(nerdnos_get_avg_hashrate(), 1);
}
String getCurrentTemperature() {
return String(nerdnos_get_temperature(), 2);
}
String getCurrentVCore() {
return String(nerdnos_get_vcore(), 0);
}
#else
String getCurrentHashRate(unsigned long mElapsed)
{
return String((1.0 * (elapsedKHs * 1000)) / mElapsed, 2);
}
String getCurrentTemperature() {
return String(0.0, 2);
}
String getCurrentVCore() {
return String(0.0, 0);
}
#endif
mining_data getMiningData(unsigned long mElapsed)
{
mining_data data;
@ -258,6 +286,8 @@ mining_data getMiningData(unsigned long mElapsed)
data.totalMHashes = Mhashes;
data.totalKHashes = totalKHashes;
data.currentHashRate = getCurrentHashRate(mElapsed);
data.currentTemperature = getCurrentTemperature();
data.vcore = getCurrentVCore();
data.templates = templates;
data.bestDiff = best_diff_string;
data.timeMining = timeMining;
@ -328,7 +358,7 @@ String getPoolAPIUrl(void) {
poolAPIUrl = String(getPublicPool);
if (Settings.PoolAddress == "public-pool.io") {
poolAPIUrl = "https://public-pool.io:40557/api/client/";
}
}
else {
if (Settings.PoolAddress == "nerdminers.org") {
poolAPIUrl = "https://pool.nerdminers.org/users/";
@ -354,13 +384,13 @@ String getPoolAPIUrl(void) {
}
pool_data getPoolData(void){
//pool_data pData;
if((mPoolUpdate == 0) || (millis() - mPoolUpdate > UPDATE_POOL_min * 60 * 1000)){
if (WiFi.status() != WL_CONNECTED) return pData;
//pool_data pData;
if((mPoolUpdate == 0) || (millis() - mPoolUpdate > UPDATE_POOL_min * 60 * 1000)){
if (WiFi.status() != WL_CONNECTED) return pData;
//Make first API call to get global hash and current difficulty
HTTPClient http;
http.setReuse(true);
try {
http.setReuse(true);
try {
String btcWallet = Settings.BtcWallet;
// Serial.println(btcWallet);
if (btcWallet.indexOf(".")>0) btcWallet = btcWallet.substring(0,btcWallet.indexOf("."));
@ -397,16 +427,16 @@ pool_data getPoolData(void){
double temp;
if (doc.containsKey("bestDifficulty")) {
temp = doc["bestDifficulty"].as<double>();
temp = doc["bestDifficulty"].as<double>();
char best_diff_string[16] = {0};
suffix_string(temp, best_diff_string, 16, 0);
pData.bestDifficulty = String(best_diff_string);
}
doc.clear();
mPoolUpdate = millis();
Serial.println("\n####### Pool Data OK!");
Serial.println("\n####### Pool Data OK!");
} else {
Serial.println("\n####### Pool Data HTTP Error!");
Serial.println("\n####### Pool Data HTTP Error!");
/* Serial.println(httpCode);
String payload = http.getString();
Serial.println(payload); */
@ -415,18 +445,18 @@ pool_data getPoolData(void){
pData.workersHash = "E";
pData.workersCount = 0;
http.end();
return pData;
return pData;
}
http.end();
} catch(...) {
Serial.println("####### Pool Error!");
Serial.println("####### Pool Error!");
// mPoolUpdate = millis();
pData.bestDifficulty = "P";
pData.workersHash = "Error";
pData.workersCount = 0;
http.end();
return pData;
}
}
}
return pData;
}

View File

@ -12,7 +12,7 @@
//Time update period
#define UPDATE_PERIOD_h 5
//API BTC price (Update to USDT cus it's more liquidity and flow price updade)
//API BTC price (Update to USDT cus it's more liquidity and flow price updade)
#define getBTCAPI "https://api.blockchain.com/v3/exchange/tickers/BTC-USDT"
#define UPDATE_BTC_min 1
@ -73,6 +73,8 @@ typedef struct {
String valids;
String temp;
String currentTime;
String currentTemperature;
String vcore;
}mining_data;
typedef struct {
@ -81,7 +83,7 @@ typedef struct {
String currentHashRate;
String btcPrice;
String blockHeight;
String currentTime;
String currentTime;
String currentDate;
}clock_data;

View File

@ -10,7 +10,9 @@
#include "utils.h"
#include "version.h"
#include <pthread.h>
pthread_mutex_t job_mutex = PTHREAD_MUTEX_INITIALIZER;
StaticJsonDocument<BUFFER_JSON_DOC> doc;
unsigned long id = 1;
@ -30,57 +32,61 @@ bool verifyPayload (String* line){
line->trim();
if(line->isEmpty()) return false;
return true;
}
bool checkError(const StaticJsonDocument<BUFFER_JSON_DOC> doc) {
if (!doc.containsKey("error")) return false;
if (doc["error"].size() == 0) return false;
Serial.printf("ERROR: %d | reason: %s \n", (const int) doc["error"][0], (const char*) doc["error"][1]);
return true;
return true;
}
// STEP 1: Pool server connection (SUBSCRIBE)
// Docs:
// Docs:
// - https://cs.braiins.com/stratum-v1/docs
// - https://github.com/aeternity/protocol/blob/master/STRATUM.md#mining-subscribe
bool tx_mining_subscribe(WiFiClient& client, mining_subscribe& mSubscribe)
{
char payload[BUFFER] = {0};
// Subscribe
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
sprintf(payload, "{\"id\": %u, \"method\": \"mining.subscribe\", \"params\": [\"NerdMinerV2/%s\"]}\n", id, CURRENT_VERSION);
#else
sprintf(payload, "{\"id\": %u, \"method\": \"mining.subscribe\", \"params\": [\"HAN_SOLOminer/%s\"]}\n", id, CURRENT_VERSION);
#endif
#endif
Serial.printf("[WORKER] ==> Mining subscribe\n");
Serial.print(" Sending : "); Serial.println(payload);
client.print(payload);
vTaskDelay(200 / portTICK_PERIOD_MS); //Small delay
String line = client.readStringUntil('\n');
if(!parse_mining_subscribe(line, mSubscribe)) return false;
Serial.print(" sub_details: "); Serial.println(mSubscribe.sub_details);
Serial.print(" extranonce1: "); Serial.println(mSubscribe.extranonce1);
Serial.print(" extranonce2_size: "); Serial.println(mSubscribe.extranonce2_size);
if((mSubscribe.extranonce1.length() == 0) ) {
Serial.printf("[WORKER] >>>>>>>>> Work aborted\n");
if((mSubscribe.extranonce1.length() == 0) ) {
Serial.printf("[WORKER] >>>>>>>>> Work aborted\n");
Serial.printf("extranonce1 length: %u \n", mSubscribe.extranonce1.length());
doc.clear();
doc.garbageCollect();
return false;
return false;
}
return true;
}
@ -89,15 +95,17 @@ bool parse_mining_subscribe(String line, mining_subscribe& mSubscribe)
{
if(!verifyPayload(&line)) return false;
Serial.print(" Receiving: "); Serial.println(line);
DeserializationError error = deserializeJson(doc, line);
if (error || checkError(doc)) return false;
if (!doc.containsKey("result")) return false;
pthread_mutex_lock(&job_mutex);
mSubscribe.sub_details = String((const char*) doc["result"][0][0][1]);
mSubscribe.extranonce1 = String((const char*) doc["result"][1]);
mSubscribe.extranonce2_size = doc["result"][2];
pthread_mutex_unlock(&job_mutex);
return true;
}
@ -122,9 +130,9 @@ bool tx_mining_auth(WiFiClient& client, const char * user, const char * pass)
// Authorize
id = getNextId(id);
sprintf(payload, "{\"params\": [\"%s\", \"%s\"], \"id\": %u, \"method\": \"mining.authorize\"}\n",
sprintf(payload, "{\"params\": [\"%s\", \"%s\"], \"id\": %u, \"method\": \"mining.authorize\"}\n",
user, pass, id);
Serial.printf("[WORKER] ==> Autorize work\n");
Serial.print(" Sending : "); Serial.println(payload);
client.print(payload);
@ -142,7 +150,7 @@ stratum_method parse_mining_method(String line)
{
if(!verifyPayload(&line)) return STRATUM_PARSE_ERROR;
Serial.print(" Receiving: "); Serial.println(line);
DeserializationError error = deserializeJson(doc, line);
if (error || checkError(doc)) return STRATUM_PARSE_ERROR;
@ -169,21 +177,36 @@ bool parse_mining_notify(String line, mining_job& mJob)
{
Serial.println(" Parsing Method [MINING NOTIFY]");
if(!verifyPayload(&line)) return false;
DeserializationError error = deserializeJson(doc, line);
if (error) return false;
if (!doc.containsKey("params")) return false;
pthread_mutex_lock(&job_mutex);
mJob.job_id = String((const char*) doc["params"][0]);
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]);
mJob.clean_jobs = doc["params"][8]; //bool
pthread_mutex_unlock(&job_mutex);
#ifdef DEBUG_MINING
Serial.print(" job_id: "); Serial.println(mJob.job_id);
@ -198,7 +221,7 @@ bool parse_mining_notify(String line, mining_job& mJob)
#endif
//Check if parameters where correctly received
if (checkError(doc)) {
Serial.printf("[WORKER] >>>>>>>>> Work aborted\n");
Serial.printf("[WORKER] >>>>>>>>> Work aborted\n");
return false;
}
return true;
@ -226,11 +249,33 @@ bool tx_mining_submit(WiFiClient& client, mining_subscribe mWorker, mining_job m
return true;
}
bool tx_mining_submit_asic(WiFiClient& client, mining_subscribe mWorker, const bm_job_t* asic_job, task_result *result)
{
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,
result->nonce,
result->rolled_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)
{
Serial.println(" Parsing Method [SET DIFFICULTY]");
if(!verifyPayload(&line)) return false;
DeserializationError error = deserializeJson(doc, line);
if (error) return false;
@ -248,7 +293,7 @@ bool tx_suggest_difficulty(WiFiClient& client, double difficulty)
id = getNextId(id);
sprintf(payload, "{\"id\": %d, \"method\": \"mining.suggest_difficulty\", \"params\": [%.10g]}\n", id, difficulty);
Serial.print(" Sending : "); Serial.print(payload);
return client.print(payload);

View File

@ -6,6 +6,7 @@
#include <Arduino.h>
#include <ArduinoJson.h>
#include <WiFi.h>
#include "drivers/nerd-nos/mining.h"
#define MAX_MERKLE_BRANCHES 32
#define HASH_SIZE 32
@ -15,7 +16,7 @@
#define BUFFER_JSON_DOC 4096
#define BUFFER 1024
typedef struct {
typedef struct mining_subscribe {
String sub_details;
String extranonce1;
String extranonce2;
@ -24,13 +25,14 @@ typedef struct {
char wPass[20];
} mining_subscribe;
typedef struct {
typedef struct mining_job {
String job_id;
String prev_block_hash;
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;
@ -61,8 +63,9 @@ bool parse_mining_notify(String line, mining_job& mJob);
//Method Mining.submit
bool tx_mining_submit(WiFiClient& client, mining_subscribe mWorker, mining_job mJob, unsigned long nonce);
bool tx_mining_submit_asic(WiFiClient& client, mining_subscribe mWorker, const bm_job_t* asic_job, task_result *result);
//Difficulty Methods
//Difficulty Methods
bool tx_suggest_difficulty(WiFiClient& client, double difficulty);
bool parse_mining_set_difficulty(String line, double& difficulty);

View File

@ -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("");