Pull BM1366 work into main
This commit is contained in:
Benjamin Wilson 2023-08-20 13:09:55 -04:00 committed by GitHub
parent a3cdc67d19
commit 9bc0671563
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1136 additions and 230 deletions

View File

@ -1,5 +1,6 @@
idf_component_register(
SRCS
"bm1366.c"
"bm1397.c"
"serial.c"
"crc.c"
@ -9,4 +10,11 @@ REQUIRES
freertos
driver
stratum
)
)
# Include the header files from "main" directory
target_include_directories(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../main")
# Include the header files from "main/tasks" directory
target_include_directories(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../main/tasks")

712
components/bm1397/bm1366.c Normal file
View File

@ -0,0 +1,712 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "serial.h"
#include "bm1366.h"
#include "utils.h"
#include "crc.h"
#include "global_state.h"
#define BM1366_RST_PIN GPIO_NUM_1
#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;
uint16_t version;
uint8_t crc;
} asic_result;
static const char *TAG = "bm1366Module";
static uint8_t asic_response_buffer[CHUNK_SIZE];
static task_result result;
/// @brief
/// @param ftdi
/// @param header
/// @param data
/// @param len
static void _send_BM1366(uint8_t header, uint8_t * data, uint8_t data_len, bool debug) {
packet_type_t packet_type = (header & TYPE_JOB) ? JOB_PACKET : CMD_PACKET;
uint8_t total_length = (packet_type == JOB_PACKET) ? (data_len+6) : (data_len+5);
//allocate memory for buffer
unsigned char *buf = malloc(total_length);
//add the preamble
buf[0] = 0x55;
buf[1] = 0xAA;
//add the header field
buf[2] = header;
//add the length field
buf[3] = (packet_type == JOB_PACKET) ? (data_len+4) : (data_len+3);
//add the data
memcpy(buf+4, data, data_len);
//add the correct crc type
if (packet_type == JOB_PACKET) {
uint16_t crc16_total = crc16_false(buf+2, data_len+2);
buf[4+data_len] = (crc16_total >> 8) & 0xFF;
buf[5+data_len] = crc16_total & 0xFF;
} else {
buf[4+data_len] = crc5(buf+2, data_len+2);
}
//send serial data
SERIAL_send(buf, total_length, debug);
free(buf);
}
static void _send_simple(uint8_t * data, uint8_t total_length){
unsigned char *buf = malloc(total_length);
memcpy(buf, data, total_length);
SERIAL_send(buf, total_length, false);
free(buf);
}
static void _send_chain_inactive(void) {
unsigned char read_address[2] = {0x00, 0x00};
//send serial data
_send_BM1366((TYPE_CMD | GROUP_ALL | CMD_INACTIVE), read_address, 2, false);
}
static void _set_chip_address(uint8_t chipAddr) {
unsigned char read_address[2] = {chipAddr, 0x00};
//send serial data
_send_BM1366((TYPE_CMD | GROUP_SINGLE | CMD_SETADDRESS), read_address, 2, false);
}
// borrowed from cgminer driver-gekko.c calc_gsf_freq()
void BM1366_send_hash_frequency(float frequency) {
unsigned char prefreq1[9] = {0x00, 0x70, 0x0F, 0x0F, 0x0F, 0x00}; //prefreq - pll0_divider
// default 200Mhz if it fails
unsigned char freqbuf[9] = {0x00, 0x08, 0x40, 0xA0, 0x02, 0x25}; //freqbuf - pll0_parameter
float deffreq = 200.0;
float fa, fb, fc1, fc2, newf;
float f1, basef, famax = 0xf0, famin = 0x10;
int i;
//bound the frequency setting
// You can go as low as 13 but it doesn't really scale or
// produce any nonces
if (frequency < 50) {
f1 = 50;
} else if (frequency > 500) {
f1 = 500;
} else {
f1 = frequency;
}
fb = 2; fc1 = 1; fc2 = 5; // initial multiplier of 10
if (f1 >= 500) {
// halve 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 (fa < famin || fa > famax) {
newf = deffreq;
} else {
freqbuf[3] = (int)fa;
freqbuf[4] = (int)fb;
// fc1, fc2 'should' already be 1..15
freqbuf[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_BM1366((TYPE_CMD | GROUP_ALL | CMD_WRITE), prefreq1, 6, false);
}
for (i = 0; i < 2; i++) {
vTaskDelay(10 / portTICK_PERIOD_MS);
_send_BM1366((TYPE_CMD | GROUP_ALL | CMD_WRITE), freqbuf, 6, false);
}
vTaskDelay(10 / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "Setting Frequency to %.2fMHz (%.2f)", frequency, newf);
}
static void _send_init(u_int64_t frequency) {
// //send serial data
// vTaskDelay(SLEEP_TIME / portTICK_PERIOD_MS);
// unsigned char init[6] = { 0x00, 0xA4, 0x90, 0x00, 0xFF, 0xFF};
// _send_BM1366((TYPE_CMD | GROUP_ALL | CMD_WRITE), init, 6, true);
// unsigned char init18[7] = { 0x55, 0xAA, 0x52, 0x05, 0x00, 0x00, 0x0A };
// _send_simple(init18, 7);
// unsigned char init2[6] = { 0x00, 0xA8, 0x00, 0x07, 0x00, 0x00};
// _send_BM1366((TYPE_CMD | GROUP_ALL | CMD_WRITE), init2, 6, true);
// unsigned char init3[6] = { 0x00, 0x18, 0xFF, 0x0F, 0xC1, 0x00 };
// _send_BM1366((TYPE_CMD | GROUP_ALL | CMD_WRITE), init3, 6, true);
// unsigned char init4[7] = { 0x55, 0xAA, 0x53, 0x05, 0x00, 0x00, 0x03 };
// _send_simple(init4, 7);
// unsigned char init5[7] = { 0x55, 0xAA, 0x40, 0x05, 0x00, 0x00, 0x1C };
// _send_simple(init5, 7);
// unsigned char init6[6] = { 0x00, 0x3C, 0x80, 0x00, 0x85, 0x40 };
// _send_BM1366((TYPE_CMD | GROUP_ALL | CMD_WRITE), init6, 6, true);
// unsigned char init7[6] = { 0x00, 0x3C, 0x80, 0x00, 0x80, 0x20};
// _send_BM1366((TYPE_CMD | GROUP_ALL | CMD_WRITE), init7, 6, true);
// unsigned char init17[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0xA4, 0x90, 0x00, 0xFF, 0xFF, 0x1C};
// _send_simple(init17, 11);
unsigned char init0[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0xA4, 0x90, 0x00, 0xFF, 0xFF, 0x1C };
_send_simple(init0, 11);
unsigned char init1[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0xA4, 0x90, 0x00, 0xFF, 0xFF, 0x1C };
_send_simple(init1, 11);
unsigned char init2[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0xA4, 0x90, 0x00, 0xFF, 0xFF, 0x1C };
_send_simple(init2, 11);
unsigned char init3[7] = { 0x55, 0xAA, 0x52, 0x05, 0x00, 0x00, 0x0A };
_send_simple(init3, 7);
unsigned char init4[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0xA8, 0x00, 0x07, 0x00, 0x00, 0x03 };
_send_simple(init4, 11);
unsigned char init5[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x18, 0xFF, 0x0F, 0xC1, 0x00, 0x00 };
_send_simple(init5, 11);
unsigned char init6[7] = { 0x55, 0xAA, 0x53, 0x05, 0x00, 0x00, 0x03 };
_send_simple(init6, 7);
unsigned char init7[7] = { 0x55, 0xAA, 0x40, 0x05, 0x00, 0x00, 0x1C };
_send_simple(init7, 7);
unsigned char init135[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x3C, 0x80, 0x00, 0x85, 0x40, 0x0C };
_send_simple(init135, 11);
unsigned char init136[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x3C, 0x80, 0x00, 0x80, 0x20, 0x19 };
_send_simple(init136, 11);
unsigned char init137[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x14, 0x00, 0x00, 0x00, 0xFF, 0x08 };
_send_simple(init137, 11);
unsigned char init138[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x54, 0x00, 0x00, 0x00, 0x03, 0x1D };
_send_simple(init138, 11);
unsigned char init139[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x58, 0x02, 0x11, 0x11, 0x11, 0x06 };
_send_simple(init139, 11);
unsigned char init171[11] = { 0x55, 0xAA, 0x41, 0x09, 0x00, 0x2C, 0x00, 0x7C, 0x00, 0x03, 0x03 };
_send_simple(init171, 11);
unsigned char init173[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x28, 0x11, 0x30, 0x02, 0x00, 0x03 };
_send_simple(init173, 11);
unsigned char init174[11] = { 0x55, 0xAA, 0x41, 0x09, 0x00, 0xA8, 0x00, 0x07, 0x01, 0xF0, 0x15 };
_send_simple(init174, 11);
unsigned char init175[11] = { 0x55, 0xAA, 0x41, 0x09, 0x00, 0x18, 0xF0, 0x00, 0xC1, 0x00, 0x0C };
_send_simple(init175, 11);
unsigned char init176[11] = { 0x55, 0xAA, 0x41, 0x09, 0x00, 0x3C, 0x80, 0x00, 0x85, 0x40, 0x04 };
_send_simple(init176, 11);
unsigned char init177[11] = { 0x55, 0xAA, 0x41, 0x09, 0x00, 0x3C, 0x80, 0x00, 0x80, 0x20, 0x11 };
_send_simple(init177, 11);
unsigned char init178[11] = { 0x55, 0xAA, 0x41, 0x09, 0x00, 0x3C, 0x80, 0x00, 0x82, 0xAA, 0x05 };
_send_simple(init178, 11);
/////////////////////////////////////////////////////////////////////////////
unsigned char init724[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA2, 0x02, 0x55, 0x0F };
_send_simple(init724, 11);
unsigned char init725[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xAF, 0x02, 0x64, 0x08 };
_send_simple(init725, 11);
unsigned char init726[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA5, 0x02, 0x54, 0x08 };
_send_simple(init726, 11);
unsigned char init727[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA8, 0x02, 0x63, 0x11 };
_send_simple(init727, 11);
unsigned char init728[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB6, 0x02, 0x63, 0x0C };
_send_simple(init728, 11);
unsigned char init729[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA8, 0x02, 0x53, 0x1A };
_send_simple(init729, 11);
unsigned char init730[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB4, 0x02, 0x53, 0x12 };
_send_simple(init730, 11);
unsigned char init731[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA8, 0x02, 0x62, 0x14 };
_send_simple(init731, 11);
unsigned char init732[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xAA, 0x02, 0x43, 0x15 };
_send_simple(init732, 11);
unsigned char init733[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA2, 0x02, 0x52, 0x14 };
_send_simple(init733, 11);
unsigned char init734[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xAB, 0x02, 0x52, 0x12 };
_send_simple(init734, 11);
unsigned char init735[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB4, 0x02, 0x52, 0x17 };
_send_simple(init735, 11);
unsigned char init736[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xBD, 0x02, 0x52, 0x11 };
_send_simple(init736, 11);
unsigned char init737[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA5, 0x02, 0x42, 0x0C };
_send_simple(init737, 11);
unsigned char init738[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA1, 0x02, 0x61, 0x1D };
_send_simple(init738, 11);
unsigned char init739[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA8, 0x02, 0x61, 0x1B };
_send_simple(init739, 11);
unsigned char init740[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xAF, 0x02, 0x61, 0x19 };
_send_simple(init740, 11);
unsigned char init741[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB6, 0x02, 0x61, 0x06 };
_send_simple(init741, 11);
unsigned char init742[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA2, 0x02, 0x51, 0x1B };
_send_simple(init742, 11);
unsigned char init743[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA8, 0x02, 0x51, 0x10 };
_send_simple(init743, 11);
unsigned char init744[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xAE, 0x02, 0x51, 0x0A };
_send_simple(init744, 11);
unsigned char init745[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB4, 0x02, 0x51, 0x18 };
_send_simple(init745, 11);
unsigned char init746[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xBA, 0x02, 0x51, 0x1C };
_send_simple(init746, 11);
unsigned char init747[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA0, 0x02, 0x41, 0x14 };
_send_simple(init747, 11);
unsigned char init748[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA5, 0x02, 0x41, 0x03 };
_send_simple(init748, 11);
unsigned char init749[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xAA, 0x02, 0x41, 0x1F };
_send_simple(init749, 11);
unsigned char init750[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xAF, 0x02, 0x41, 0x08 };
_send_simple(init750, 11);
unsigned char init751[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB4, 0x02, 0x41, 0x02 };
_send_simple(init751, 11);
unsigned char init752[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB9, 0x02, 0x41, 0x0B };
_send_simple(init752, 11);
unsigned char init753[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xBE, 0x02, 0x41, 0x09 };
_send_simple(init753, 11);
unsigned char init754[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x50, 0xC3, 0x02, 0x41, 0x01 };
_send_simple(init754, 11);
unsigned char init755[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA0, 0x02, 0x31, 0x18 };
_send_simple(init755, 11);
unsigned char init756[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA4, 0x02, 0x31, 0x17 };
_send_simple(init756, 11);
unsigned char init757[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA8, 0x02, 0x31, 0x06 };
_send_simple(init757, 11);
unsigned char init758[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xAC, 0x02, 0x31, 0x09 };
_send_simple(init758, 11);
unsigned char init759[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB0, 0x02, 0x31, 0x01 };
_send_simple(init759, 11);
unsigned char init760[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB4, 0x02, 0x31, 0x0E };
_send_simple(init760, 11);
unsigned char init761[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA1, 0x02, 0x60, 0x18 };
_send_simple(init761, 11);
unsigned char init762[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xBC, 0x02, 0x31, 0x10 };
_send_simple(init762, 11);
unsigned char init763[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA8, 0x02, 0x60, 0x1E };
_send_simple(init763, 11);
unsigned char init764[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x50, 0xC4, 0x02, 0x31, 0x0F };
_send_simple(init764, 11);
unsigned char init765[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xAF, 0x02, 0x60, 0x1C };
_send_simple(init765, 11);
unsigned char init766[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x50, 0xCC, 0x02, 0x31, 0x11 };
_send_simple(init766, 11);
unsigned char init767[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB6, 0x02, 0x60, 0x03 };
_send_simple(init767, 11);
unsigned char init768[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x50, 0xD4, 0x02, 0x31, 0x16 };
_send_simple(init768, 11);
unsigned char init769[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA2, 0x02, 0x50, 0x1E };
_send_simple(init769, 11);
unsigned char init770[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA5, 0x02, 0x50, 0x1C };
_send_simple(init770, 11);
unsigned char init771[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA8, 0x02, 0x50, 0x15 };
_send_simple(init771, 11);
unsigned char init772[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xAB, 0x02, 0x50, 0x18 };
_send_simple(init772, 11);
unsigned char init773[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xAE, 0x02, 0x50, 0x0F };
_send_simple(init773, 11);
unsigned char init774[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB1, 0x02, 0x50, 0x0A };
_send_simple(init774, 11);
unsigned char init775[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB4, 0x02, 0x50, 0x1D };
_send_simple(init775, 11);
unsigned char init776[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB7, 0x02, 0x50, 0x10 };
_send_simple(init776, 11);
unsigned char init777[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xBA, 0x02, 0x50, 0x19 };
_send_simple(init777, 11);
unsigned char init778[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xBD, 0x02, 0x50, 0x1B };
_send_simple(init778, 11);
unsigned char init779[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA0, 0x02, 0x40, 0x11 };
_send_simple(init779, 11);
unsigned char init780[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x50, 0xC3, 0x02, 0x50, 0x1E };
_send_simple(init780, 11);
unsigned char init781[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xA5, 0x02, 0x40, 0x06 };
_send_simple(init781, 11);
unsigned char init782[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x50, 0xC9, 0x02, 0x50, 0x15 };
_send_simple(init782, 11);
unsigned char init783[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xAA, 0x02, 0x40, 0x1A };
_send_simple(init783, 11);
unsigned char init784[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x50, 0xCF, 0x02, 0x50, 0x0F };
_send_simple(init784, 11);
unsigned char init785[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xAF, 0x02, 0x40, 0x0D };
_send_simple(init785, 11);
unsigned char init786[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x50, 0xD5, 0x02, 0x50, 0x1D };
_send_simple(init786, 11);
unsigned char init787[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB4, 0x02, 0x40, 0x07 };
_send_simple(init787, 11);
unsigned char init788[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x50, 0xDB, 0x02, 0x50, 0x19 };
_send_simple(init788, 11);
unsigned char init789[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xB9, 0x02, 0x40, 0x0E };
_send_simple(init789, 11);
unsigned char init790[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x50, 0xE1, 0x02, 0x50, 0x1C };
_send_simple(init790, 11);
unsigned char init791[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x40, 0xBE, 0x02, 0x40, 0x0C };
_send_simple(init791, 11);
unsigned char init792[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x50, 0xE7, 0x02, 0x50, 0x06 };
_send_simple(init792, 11);
unsigned char init793[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x08, 0x50, 0xC2, 0x02, 0x40, 0x1C };
_send_simple(init793, 11);
unsigned char init794[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x10, 0x00, 0x00, 0x15, 0x1C, 0x02 };
_send_simple(init794, 11);
unsigned char init795[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0xA4, 0x90, 0x00, 0xFF, 0xFF, 0x1C };
_send_simple(init795, 11);
}
//reset the BM1366 via the RTS line
static void _reset(void) {
gpio_set_level(BM1366_RST_PIN, 0);
//delay for 100ms
vTaskDelay(100 / portTICK_PERIOD_MS);
//set the gpio pin high
gpio_set_level(BM1366_RST_PIN, 1);
//delay for 100ms
vTaskDelay(100 / portTICK_PERIOD_MS);
}
static void _send_read_address(void) {
unsigned char read_address[2] = {0x00, 0x00};
//send serial data
_send_BM1366((TYPE_CMD | GROUP_ALL | CMD_READ), read_address, 2, false);
}
void BM1366_init(u_int64_t frequency) {
ESP_LOGI(TAG, "Initializing BM1366");
memset(asic_response_buffer, 0, 1024);
esp_rom_gpio_pad_select_gpio(BM1366_RST_PIN);
gpio_set_direction(BM1366_RST_PIN, GPIO_MODE_OUTPUT);
//reset the bm1366
_reset();
//send the init command
//_send_read_address();
_send_init(frequency);
}
// Baud formula = 25M/((denominator+1)*8)
// The denominator is 5 bits found in the misc_control (bits 9-13)
int BM1366_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_BM1366((TYPE_CMD | GROUP_ALL | CMD_WRITE), baudrate, 6, false);
return 115749;
}
int BM1366_set_max_baud(void){
///return 115749;
// divider of 0 for 3,125,000
ESP_LOGI(TAG, "Setting max baud of 1000000 ");
unsigned char init8[11] = { 0x55, 0xAA, 0x51, 0x09, 0x00, 0x28, 0x11, 0x30, 0x02, 0x00, 0x03 };
_send_simple(init8, 11);
return 1000000;
}
void BM1366_set_job_difficulty_mask(int difficulty){
return;
// Default mask of 256 diff
unsigned char job_difficulty_mask[9] = {0x00, TICKET_MASK, 0b00000000, 0b00000000, 0b00000000, 0b11111111};
// The mask must be a power of 2 so there are no holes
// Correct: {0b00000000, 0b00000000, 0b11111111, 0b11111111}
// Incorrect: {0b00000000, 0b00000000, 0b11100111, 0b11111111}
difficulty = _largest_power_of_two(difficulty) -1; // (difficulty - 1) if it is a pow 2 then step down to second largest for more hashrate sampling
// convert difficulty into char array
// Ex: 256 = {0b00000000, 0b00000000, 0b00000000, 0b11111111}, {0x00, 0x00, 0x00, 0xff}
// Ex: 512 = {0b00000000, 0b00000000, 0b00000001, 0b11111111}, {0x00, 0x00, 0x01, 0xff}
for (int i = 0; i < 4; i++) {
char value = (difficulty >> (8 * i)) & 0xFF;
//The char is read in backwards to the register so we need to reverse them
//So a mask of 512 looks like 0b00000000 00000000 00000001 1111111
//and not 0b00000000 00000000 10000000 1111111
job_difficulty_mask[5 - i] = _reverse_bits(value);
}
ESP_LOGI(TAG, "Setting job ASIC mask to %d", difficulty);
_send_BM1366((TYPE_CMD | GROUP_ALL | CMD_WRITE), job_difficulty_mask, 6, false);
}
static uint8_t id = 0;
void BM1366_send_work(void *pvParameters, bm_job *next_bm_job) {
GlobalState *GLOBAL_STATE = (GlobalState*) pvParameters;
BM1366_job job;
id = (id + 8) % 128;
job.job_id = id;
job.num_midstates = 0x01;
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.merkle_root, next_bm_job->merkle_root_be, 32);
memcpy(job.prev_block_hash, next_bm_job->prev_block_hash_be, 32);
memcpy(&job.version, &next_bm_job->version, 4);
if (GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id] != NULL) {
free_bm_job(GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id]);
}
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id] = next_bm_job;
pthread_mutex_lock(&GLOBAL_STATE->valid_jobs_lock);
GLOBAL_STATE-> valid_jobs[job.job_id] = 1;
//ESP_LOGI(TAG, "Added Job: %i", job.job_id);
pthread_mutex_unlock(&GLOBAL_STATE->valid_jobs_lock);
_send_BM1366((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), &job, sizeof(BM1366_job), false);
}
asic_result * BM1366_receive_work(void){
//wait for a response, wait time is pretty arbitrary
int received = SERIAL_rx(asic_response_buffer, 11, 60000);
if (received < 0) {
ESP_LOGI(TAG, "Error in serial RX");
return NULL;
} else if(received == 0){
// Didn't find a solution, restart and try again
return NULL;
}
if(received != 11 || asic_response_buffer[0] != 0xAA || asic_response_buffer[1] != 0x55){
ESP_LOGI(TAG, "Serial RX invalid %i", received);
ESP_LOG_BUFFER_HEX(TAG, asic_response_buffer, received);
return NULL;
}
return (asic_result*) asic_response_buffer;
}
uint16_t reverse_uint16(uint16_t num) {
return (num >> 8) | (num << 8);
}
task_result * BM1366_proccess_work(void *pvParameters){
asic_result *asic_result = BM1366_receive_work();
if(asic_result == NULL){
return NULL;
}
uint8_t job_id = asic_result->job_id;
uint8_t rx_job_id = job_id & 0xf8;
GlobalState *GLOBAL_STATE = (GlobalState*) pvParameters;
uint32_t rolled_version = GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->version;
// // // shift the 16 bit value left 13
rolled_version = (reverse_uint16(asic_result->version) << 13) | rolled_version;
result.job_id = rx_job_id;
result.nonce = asic_result->nonce;
result.rolled_version = rolled_version;
return &result;
}

View File

@ -12,6 +12,28 @@
#include "bm1397.h"
#include "utils.h"
#include "crc.h"
#include "mining.h"
#include "global_state.h"
#define BM1397_RST_PIN GPIO_NUM_1
#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
@ -25,8 +47,20 @@
#define TICKET_MASK 0x14
#define MISC_CONTROL 0x18
typedef struct __attribute__((__packed__)) {
uint8_t preamble[2];
uint32_t nonce;
uint8_t midstate_num;
uint8_t job_id;
uint8_t crc;
} asic_result;
static const char *TAG = "bm1397Module";
static uint8_t asic_response_buffer[CHUNK_SIZE];
static uint32_t prev_nonce = 0;
static task_result result;
/// @brief
/// @param ftdi
/// @param header
@ -81,29 +115,6 @@ static void _set_chip_address(uint8_t chipAddr) {
_send_BM1397((TYPE_CMD | GROUP_SINGLE | CMD_SETADDRESS), read_address, 2, false);
}
static unsigned char _reverse_bits(unsigned char num) {
unsigned char reversed = 0;
int i;
for (i = 0; i < 8; i++) {
reversed <<= 1; // Left shift the reversed variable by 1
reversed |= num & 1; // Use bitwise OR to set the rightmost bit of reversed to the current bit of num
num >>= 1; // Right shift num by 1 to get the next bit
}
return reversed;
}
static int _largest_power_of_two(int num) {
int power = 0;
while (num > 1) {
num = num >> 1;
power++;
}
return 1 << power;
}
// borrowed from cgminer driver-gekko.c calc_gsf_freq()
void BM1397_send_hash_frequency(float frequency) {
@ -238,6 +249,8 @@ static void _send_read_address(void) {
void BM1397_init(u_int64_t frequency) {
ESP_LOGI(TAG, "Initializing BM1397");
memset(asic_response_buffer, 0, sizeof(asic_response_buffer));
esp_rom_gpio_pad_select_gpio(BM1397_RST_PIN);
gpio_set_direction(BM1397_RST_PIN, GPIO_MODE_OUTPUT);
@ -249,7 +262,6 @@ void BM1397_init(u_int64_t frequency) {
_send_init(frequency);
}
@ -301,10 +313,127 @@ void BM1397_set_job_difficulty_mask(int difficulty){
}
static uint8_t id = 0;
void BM1397_send_work(void *pvParameters, bm_job *next_bm_job) {
GlobalState *GLOBAL_STATE = (GlobalState*) pvParameters;
job_packet job;
// max job number is 128
// there is still some really weird logic with the job id bits for the asic to sort out
// so we have it limited to 128 and it has to increment by 4
id = (id + 4) % 128;
job.job_id = id;
job.num_midstates = next_bm_job->num_midstates;
memcpy(&job.starting_nonce, &next_bm_job->starting_nonce, 4);
memcpy(&job.nbits, &next_bm_job->target, 4);
memcpy(&job.ntime, &next_bm_job->ntime, 4);
memcpy(&job.merkle4, next_bm_job->merkle_root + 28, 4);
memcpy(job.midstate, next_bm_job->midstate, 32);
void BM1397_send_work(struct job_packet *job) {
_send_BM1397((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), (uint8_t*)job, sizeof(struct job_packet), false);
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);
}
if (GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id] != NULL) {
free_bm_job(GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id]);
}
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id] = next_bm_job;
pthread_mutex_lock(&GLOBAL_STATE->valid_jobs_lock);
GLOBAL_STATE-> valid_jobs[job.job_id] = 1;
//ESP_LOGI(TAG, "Added Job: %i", job.job_id);
pthread_mutex_unlock(&GLOBAL_STATE->valid_jobs_lock);
_send_BM1397((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), &job, sizeof(job_packet), false);
}
asic_result * BM1397_receive_work(void){
//wait for a response, wait time is pretty arbitrary
int received = SERIAL_rx(asic_response_buffer, 9, 60000);
if (received < 0) {
ESP_LOGI(TAG, "Error in serial RX");
return NULL;
} else if(received == 0){
// Didn't find a solution, restart and try again
return NULL;
}
if(received != 9 || asic_response_buffer[0] != 0xAA || asic_response_buffer[1] != 0x55){
ESP_LOGI(TAG, "Serial RX invalid %i", received);
ESP_LOG_BUFFER_HEX(TAG, asic_response_buffer, received);
return NULL;
}
return (asic_result*) asic_response_buffer;
}
task_result * BM1397_proccess_work(void *pvParameters){
asic_result *asic_result = BM1397_receive_work();
if(asic_result == NULL){
ESP_LOGI(TAG, "return null");
return NULL;
}
ESP_LOGI(TAG, "return not null");
uint8_t nonce_found = 0;
uint32_t first_nonce = 0;
uint8_t rx_job_id = asic_result->job_id & 0xfc;
uint8_t rx_midstate_index = asic_result->job_id & 0x03;
GlobalState *GLOBAL_STATE = (GlobalState*) pvParameters;
if (GLOBAL_STATE->valid_jobs[rx_job_id] == 0) {
ESP_LOGI(TAG, "Invalid job nonce found, id=%d", rx_job_id);
}
uint32_t rolled_version = GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->version;
for (int i = 0; i < rx_midstate_index; i++) {
rolled_version = increment_bitmask(rolled_version, GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->version_mask);
}
// ASIC may return the same nonce multiple times
// or one that was already found
// most of the time it behavies however
if (nonce_found == 0) {
first_nonce = asic_result->nonce;
nonce_found = 1;
} else if (asic_result->nonce == first_nonce) {
// stop if we've already seen this nonce
return NULL;
}
if (asic_result->nonce == prev_nonce) {
return NULL;
} else {
prev_nonce = asic_result->nonce;
}
result.job_id = rx_job_id;
result.nonce = asic_result->nonce;
result.rolled_version = rolled_version;
return &result;
}

View File

@ -0,0 +1,46 @@
#ifndef BM1366_H_
#define BM1366_H_
#include "driver/gpio.h"
#include "mining.h"
#include "common.h"
#define CRC5_MASK 0x1F
static const u_int64_t BM1366_FREQUENCY = CONFIG_ASIC_FREQUENCY;
static const u_int64_t BM1366_CORE_COUNT = 672;
static const u_int64_t BM1366_HASHRATE_S = BM1366_FREQUENCY * BM1366_CORE_COUNT * 1000000;
//2^32
//static const u_int64_t NONCE_SPACE = 4294967296;
static const double BM1366_FULLSCAN_MS = 2140;
typedef struct {
float frequency;
} bm1366Module;
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 merkle_root[32];
uint8_t prev_block_hash[32];
uint8_t version[4];
} BM1366_job;
void BM1366_init(u_int64_t frequency);
void BM1366_send_init(void);
void BM1366_send_work(void *GLOBAL_STATE, bm_job *next_bm_job);
void BM1366_set_job_difficulty_mask(int);
int BM1366_set_max_baud(void);
int BM1366_set_default_baud(void);
void BM1366_send_hash_frequency(float frequency);
task_result * BM1366_proccess_work(void *GLOBAL_STATE);
#endif /* BM1366_H_ */

View File

@ -2,30 +2,15 @@
#define BM1397_H_
#include "driver/gpio.h"
#include "mining.h"
#include "common.h"
#define BM1397_RST_PIN GPIO_NUM_1
#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 CRC5_MASK 0x1F
static const u_int64_t BM1397_FREQUENCY = CONFIG_BM1397_FREQUENCY;
static const u_int64_t ASIC_FREQUENCY = CONFIG_ASIC_FREQUENCY;
static const u_int64_t BM1397_CORE_COUNT = 672;
static const u_int64_t BM1397_HASHRATE_S = BM1397_FREQUENCY * BM1397_CORE_COUNT * 1000000;
static const u_int64_t BM1397_HASHRATE_S = ASIC_FREQUENCY * BM1397_CORE_COUNT * 1000000;
//2^32
static const u_int64_t NONCE_SPACE = 4294967296;
static const double BM1397_FULLSCAN_MS = ((double)NONCE_SPACE / (double)BM1397_HASHRATE_S) * 1000;
@ -44,7 +29,7 @@ typedef enum {
CMD_RESP = 1,
} response_type_t;
struct __attribute__((__packed__)) job_packet {
typedef struct __attribute__((__packed__)) {
uint8_t job_id;
uint8_t num_midstates;
uint8_t starting_nonce[4];
@ -55,23 +40,19 @@ struct __attribute__((__packed__)) job_packet {
uint8_t midstate1[32];
uint8_t midstate2[32];
uint8_t midstate3[32];
};
} job_packet;
struct __attribute__((__packed__)) nonce_response {
uint8_t preamble[2];
uint32_t nonce;
uint8_t midstate_num;
uint8_t job_id;
uint8_t crc;
};
void BM1397_init(u_int64_t frequency);
void BM1397_send_init(void);
void BM1397_send_work(struct job_packet *job);
void BM1397_send_work(void *GLOBAL_STATE, bm_job *next_bm_job);
void BM1397_set_job_difficulty_mask(int);
int BM1397_set_max_baud(void);
int BM1397_set_default_baud(void);
void BM1397_send_hash_frequency(float frequency);
task_result * BM1397_proccess_work(void *GLOBAL_STATE);
#endif /* BM1397_H_ */

View File

@ -0,0 +1,34 @@
#ifndef COMMON_H_
#define COMMON_H_
typedef struct __attribute__((__packed__)) {
uint8_t job_id;
uint32_t nonce;
uint32_t rolled_version;
} task_result;
static unsigned char _reverse_bits(unsigned char num) {
unsigned char reversed = 0;
int i;
for (i = 0; i < 8; i++) {
reversed <<= 1; // Left shift the reversed variable by 1
reversed |= num & 1; // Use bitwise OR to set the rightmost bit of reversed to the current bit of num
num >>= 1; // Right shift num by 1 to get the next bit
}
return reversed;
}
static int _largest_power_of_two(int num) {
int power = 0;
while (num > 1) {
num = num >> 1;
power++;
}
return 1 << power;
}
#endif

View File

@ -33,7 +33,7 @@ TEST_CASE("Check known working midstate + job command", "[bm1397]")
0x7E, 0x02, 0x70, 0x35, 0xB1, 0xAC, 0xBA, 0xF2, 0x3E, 0xA0, 0x1A, 0x52, 0x73, 0x44, 0xFA, 0xF7, 0x6A, 0xB4, 0x76, 0xD3, 0x28, 0x21, 0x61, 0x18, 0xB7, 0x76, 0x0F, 0x7B, 0x1B, 0x22, 0xD2, 0x29,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
struct job_packet test_job;
job_packet test_job;
memcpy((uint8_t *) &test_job, work1, 146);
uint8_t buf[1024];
@ -41,7 +41,7 @@ TEST_CASE("Check known working midstate + job command", "[bm1397]")
BM1397_send_work(&test_job);
uint16_t received = SERIAL_rx(buf, 9, 20);
TEST_ASSERT_GREATER_OR_EQUAL_UINT16(sizeof(struct nonce_response), received);
TEST_ASSERT_GREATER_OR_EQUAL_UINT16(sizeof(struct asic_result), received);
int i;
for (i = 0; i < received - 1; i++) {
@ -50,8 +50,8 @@ TEST_CASE("Check known working midstate + job command", "[bm1397]")
}
}
struct nonce_response nonce;
memcpy((void *) &nonce, buf + i, sizeof(struct nonce_response));
struct asic_result nonce;
memcpy((void *) &nonce, buf + i, sizeof(struct asic_result));
// expected nonce 9B 04 4C 0A
TEST_ASSERT_EQUAL_UINT32(0x0a4c049b, nonce.nonce);
TEST_ASSERT_EQUAL_UINT8(0x18, nonce.job_id & 0xfc);

View File

@ -8,7 +8,9 @@ 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;
@ -32,7 +34,7 @@ char * calculate_merkle_root_hash(const char * coinbase_tx, const uint8_t merkle
bm_job construct_bm_job(mining_notify * params, const char * merkle_root, const uint32_t version_mask);
double test_nonce_value(const bm_job * job, const uint32_t nonce, const uint8_t midstate_index);
double test_nonce_value(const bm_job * job, const uint32_t nonce, const uint32_t rolled_version);
char * extranonce_2_generate(uint32_t extranonce_2, uint32_t length);

View File

@ -63,8 +63,16 @@ bm_job construct_bm_job(mining_notify * params, const char * merkle_root, const
new_job.pool_diff = params->difficulty;
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(params->prev_block_hash, new_job.prev_block_hash);
hex2bin(params->prev_block_hash, 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];
@ -117,15 +125,15 @@ char * extranonce_2_generate(uint32_t extranonce_2, uint32_t length)
static const double truediffone = 26959535291011309493156476344723991336010898738574164086137773096960.0;
/* testing a nonce and return the diff - 0 means invalid */
double test_nonce_value(const bm_job * job, const uint32_t nonce, const uint8_t midstate_index) {
double test_nonce_value(const bm_job * job, const uint32_t nonce, const uint32_t rolled_version) {
double d64, s64, ds;
unsigned char header[80];
// TODO: use the midstate hash instead of hashing the whole header
uint32_t rolled_version = job->version;
for (int i = 0; i < midstate_index; i++) {
rolled_version = increment_bitmask(rolled_version, job->version_mask);
}
// // 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);

View File

@ -254,7 +254,7 @@ int STRATUM_V1_subscribe(int socket, char ** extranonce, int * extranonce2_len)
{
// Subscribe
char subscribe_msg[BUFFER_SIZE];
sprintf(subscribe_msg, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": [\"bitaxe v2.2\"]}\n", send_uid++);
sprintf(subscribe_msg, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": [\"bitaxe %s\"]}\n", send_uid++, CONFIG_ASIC_MODEL);
debug_stratum_tx(subscribe_msg);
write(socket, subscribe_msg, strlen(subscribe_msg));
char * line;

View File

@ -6,3 +6,5 @@ stratumurl,data,string,public-pool.io
stratumport,data,u16,21496
stratumuser,data,string,1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa.bitaxe
stratumpass,data,string,x
asicfrequency,data,u16,450
asicvoltage,data,u16,1400

View File

@ -1,13 +1,19 @@
menu "Bitaxe Configuration"
config BM1397_VOLTAGE
config ASIC_MODEL
string "ASIC Model"
default "BM1397"
help
BM1397 or BM1366
config ASIC_VOLTAGE
int "ASIC Core Voltage (mV)"
range 1000 1800
default 1400
help
The core voltage to set the BM1397 ASIC to.
The core voltage to set the ASIC to. 1200 for BM1366 or 1400 for BM1397 is typical.
config BM1397_FREQUENCY
config ASIC_FREQUENCY
int "ASIC Hash Frequency (MHz)"
range 200 800
default 250

View File

@ -3,16 +3,28 @@
#include "work_queue.h"
#include "bm1397.h"
#include "bm1366.h"
#include "system.h"
#include "stratum_api.h"
#include "asic_task.h"
#include "power_management_task.h"
#include "serial.h"
#include "common.h"
#define STRATUM_USER CONFIG_STRATUM_USER
typedef struct {
void (*init_fn)(u_int64_t);
task_result * (*receive_result_fn)(void *GLOBAL_STATE);
int (*set_max_baud_fn)(void);
void (*set_difficulty_mask_fn)(int);
void (*send_work_fn)(void *GLOBAL_STATE, bm_job *next_bm_job);
} AsicFunctions;
typedef struct {
AsicFunctions ASIC_functions;
double asic_job_frequency_ms;
work_queue stratum_queue;
work_queue ASIC_jobs_queue;
@ -22,6 +34,7 @@ typedef struct {
PowerManagementModule POWER_MANAGEMENT_MODULE;
char * extranonce_str;
int extranonce_2_len;
int abandon_work;
@ -34,7 +47,10 @@ typedef struct {
int sock;
} GlobalState;
#endif /* GLOBAL_STATE_H_ */

View File

@ -15,6 +15,10 @@
#include "asic_result_task.h"
#include "nvs_config.h"
#define ASIC_MODEL CONFIG_ASIC_MODEL
static GlobalState GLOBAL_STATE = {
.extranonce_str = NULL,
.extranonce_2_len = 0,
@ -22,7 +26,7 @@ static GlobalState GLOBAL_STATE = {
.version_mask = 0,
.POWER_MANAGEMENT_MODULE = {
.frequency_multiplier = 1,
.frequency_value = BM1397_FREQUENCY
.frequency_value = ASIC_FREQUENCY
}
};
@ -30,6 +34,39 @@ static const char *TAG = "miner";
void app_main(void)
{
if(strcmp(ASIC_MODEL, "BM1366") == 0){
ESP_LOGI(TAG, "ASIC: BM1366");
AsicFunctions ASIC_functions = {
.init_fn = BM1366_init,
.receive_result_fn = BM1366_proccess_work,
.set_max_baud_fn = BM1366_set_max_baud,
.set_difficulty_mask_fn = BM1366_set_job_difficulty_mask,
.send_work_fn = BM1366_send_work
};
GLOBAL_STATE.asic_job_frequency_ms = BM1366_FULLSCAN_MS;
GLOBAL_STATE.ASIC_functions = ASIC_functions;
}else if(strcmp(ASIC_MODEL, "BM1397") == 0){
ESP_LOGI(TAG, "ASIC: BM1397");
AsicFunctions ASIC_functions = {
.init_fn = BM1397_init,
.receive_result_fn = BM1397_proccess_work,
.set_max_baud_fn = BM1397_set_max_baud,
.set_difficulty_mask_fn = BM1397_set_job_difficulty_mask,
.send_work_fn = BM1397_send_work
};
GLOBAL_STATE.asic_job_frequency_ms = BM1397_FULLSCAN_MS;
GLOBAL_STATE.ASIC_functions = ASIC_functions;
}else{
ESP_LOGI(TAG, "Invalid ASIC model");
exit(EXIT_FAILURE);
}
ESP_LOGI(TAG, "Welcome to the bitaxe!");
//wait between 0 and 5 seconds for multiple units
vTaskDelay(rand() % 5001 / portTICK_PERIOD_MS);
@ -70,7 +107,7 @@ void app_main(void)
SERIAL_init();
BM1397_init(GLOBAL_STATE.POWER_MANAGEMENT_MODULE.frequency_value);
(*GLOBAL_STATE.ASIC_functions.init_fn)(GLOBAL_STATE.POWER_MANAGEMENT_MODULE.frequency_value);
//set the startup_done flag
GLOBAL_STATE.SYSTEM_MODULE.startup_done = true;

View File

@ -9,8 +9,9 @@
#define NVS_CONFIG_STRATUM_PORT "stratumport"
#define NVS_CONFIG_STRATUM_USER "stratumuser"
#define NVS_CONFIG_STRATUM_PASS "stratumpass"
#define NVS_CONFIG_BM1397_FREQ "bm1397frequency"
#define NVS_CONFIG_BM1397_VOLTAGE "bm1397voltage"
#define NVS_CONFIG_ASIC_FREQ "asicfrequency"
#define NVS_CONFIG_ASIC_VOLTAGE "asicvoltage"
#define NVS_CONFIG_ASIC_MODEL "asicModel"
char * nvs_config_get_string(const char * key, const char * default_value);
uint16_t nvs_config_get_u16(const char * key, const uint16_t default_value);

View File

@ -21,7 +21,7 @@
static const char *TAG = "SystemModule";
#define BM1397_VOLTAGE CONFIG_BM1397_VOLTAGE
#define ASIC_VOLTAGE CONFIG_ASIC_VOLTAGE
static void _suffix_string(uint64_t, char *, size_t, int);
@ -66,7 +66,7 @@ static void _init_system(SystemModule* module) {
ADC_init();
//DS4432U tests
DS4432U_set_vcore(BM1397_VOLTAGE / 1000.0);
DS4432U_set_vcore(ASIC_VOLTAGE / 1000.0);
//Fan Tests
EMC2101_init();

View File

@ -5,102 +5,58 @@
#include <string.h>
#include "esp_log.h"
#include "nvs_config.h"
#include "utils.h"
const char * TAG = "asic_result";
void ASIC_result_task(void * pvParameters)
{
GlobalState *GLOBAL_STATE = (GlobalState*) pvParameters;
uint8_t buf[CHUNK_SIZE];
memset(buf, 0, 1024);
SERIAL_clear_buffer();
uint32_t prev_nonce = 0;
char * user = nvs_config_get_string(NVS_CONFIG_STRATUM_USER, STRATUM_USER);
while(1){
//wait for a response, wait time is pretty arbitrary
int received = SERIAL_rx(buf, 9, 60000);
task_result *asic_result = (*GLOBAL_STATE->ASIC_functions.receive_result_fn)(GLOBAL_STATE);
if (received < 0) {
ESP_LOGI(TAG, "Error in serial RX");
continue;
} else if(received == 0){
// Didn't find a solution, restart and try again
if(asic_result == NULL){
continue;
}
if(received != 9 || buf[0] != 0xAA || buf[1] != 0x55){
ESP_LOGI(TAG, "Serial RX invalid %i", received);
ESP_LOG_BUFFER_HEX(TAG, buf, received);
continue;
}
uint8_t job_id = asic_result->job_id;
uint8_t nonce_found = 0;
uint32_t first_nonce = 0;
struct nonce_response nonce;
memcpy((void *) &nonce, buf, sizeof(struct nonce_response));
uint8_t rx_job_id = nonce.job_id & 0xfc;
uint8_t rx_midstate_index = nonce.job_id & 0x03;
if (GLOBAL_STATE->valid_jobs[rx_job_id] == 0) {
ESP_LOGI(TAG, "Invalid job nonce found, id=%d", nonce.job_id);
}
// ASIC may return the same nonce multiple times
// or one that was already found
// most of the time it behavies however
if (nonce_found == 0) {
first_nonce = nonce.nonce;
nonce_found = 1;
} else if (nonce.nonce == first_nonce) {
// stop if we've already seen this nonce
break;
}
if (nonce.nonce == prev_nonce) {
continue;
} else {
prev_nonce = nonce.nonce;
if (GLOBAL_STATE->valid_jobs[job_id] == 0) {
ESP_LOGI(TAG, "Invalid job nonce found, id=%d", job_id);
}
// check the nonce difficulty
double nonce_diff = test_nonce_value(
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id],
nonce.nonce,
rx_midstate_index
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id],
asic_result->nonce,
asic_result->rolled_version
);
ESP_LOGI(TAG, "Nonce difficulty %.2f of %ld.", nonce_diff, GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->pool_diff);
ESP_LOGI(TAG, "Nonce difficulty %.2f of %ld.", nonce_diff, GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->pool_diff);
if (nonce_diff > GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->pool_diff)
if (nonce_diff > GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->pool_diff)
{
SYSTEM_notify_found_nonce(
&GLOBAL_STATE->SYSTEM_MODULE,
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->pool_diff,
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->pool_diff,
nonce_diff,
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->target
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->target
);
uint32_t rolled_version = GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->version;
for (int i = 0; i < rx_midstate_index; i++) {
rolled_version = increment_bitmask(rolled_version, GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->version_mask);
}
STRATUM_V1_submit_share(
GLOBAL_STATE->sock,
user,
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->jobid,
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->extranonce2,
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->ntime,
nonce.nonce,
rolled_version ^ GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->version
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->jobid,
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->extranonce2,
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->ntime,
asic_result->nonce,
asic_result->rolled_version ^ GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->version
);
}

View File

@ -19,18 +19,17 @@ void ASIC_task(void * pvParameters)
GlobalState *GLOBAL_STATE = (GlobalState*) pvParameters;
uint8_t id = 0;
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs = malloc(sizeof(bm_job *) * 128);
GLOBAL_STATE->valid_jobs = malloc(sizeof(uint8_t) * 128);
for (int i = 0; i < 128; i++) {
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[i] = NULL;
GLOBAL_STATE->valid_jobs[i] = 0;
}
int baud = BM1397_set_max_baud();
int baud = (*GLOBAL_STATE->ASIC_functions.set_max_baud_fn)();
SERIAL_set_baud(baud);
SYSTEM_notify_mining_started(&GLOBAL_STATE->SYSTEM_MODULE);
@ -40,50 +39,17 @@ void ASIC_task(void * pvParameters)
bm_job * next_bm_job = (bm_job *) queue_dequeue(&GLOBAL_STATE->ASIC_jobs_queue);
if(next_bm_job->pool_diff != GLOBAL_STATE->stratum_difficulty){
ESP_LOGI(TAG, "New difficulty %ld", next_bm_job->pool_diff);
BM1397_set_job_difficulty_mask(next_bm_job->pool_diff);
//ESP_LOGI(TAG, "New difficulty %d", next_bm_job->pool_diff);
(*GLOBAL_STATE->ASIC_functions.set_difficulty_mask_fn)(next_bm_job->pool_diff);
GLOBAL_STATE->stratum_difficulty = next_bm_job->pool_diff;
}
struct job_packet job;
// max job number is 128
// there is still some really weird logic with the job id bits for the asic to sort out
// so we have it limited to 128 and it has to increment by 4
id = (id + 4) % 128;
job.job_id = id;
job.num_midstates = next_bm_job->num_midstates;
memcpy(&job.starting_nonce, &next_bm_job->starting_nonce, 4);
memcpy(&job.nbits, &next_bm_job->target, 4);
memcpy(&job.ntime, &next_bm_job->ntime, 4);
memcpy(&job.merkle4, next_bm_job->merkle_root + 28, 4);
memcpy(job.midstate, next_bm_job->midstate, 32);
if (job.num_midstates == 4)
{
memcpy(job.midstate1, next_bm_job->midstate1, 32);
memcpy(job.midstate2, next_bm_job->midstate2, 32);
memcpy(job.midstate3, next_bm_job->midstate3, 32);
}
if (GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id] != NULL) {
free_bm_job(GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id]);
}
GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job.job_id] = next_bm_job;
pthread_mutex_lock(&GLOBAL_STATE->valid_jobs_lock);
GLOBAL_STATE-> valid_jobs[job.job_id] = 1;
pthread_mutex_unlock(&GLOBAL_STATE->valid_jobs_lock);
BM1397_send_work(&job); //send the job to the ASIC
(*GLOBAL_STATE->ASIC_functions.send_work_fn)(GLOBAL_STATE, next_bm_job); //send the job to the ASIC
//Time to execute the above code is ~0.3ms
vTaskDelay((BM1397_FULLSCAN_MS - 0.3 ) / portTICK_PERIOD_MS);
//vTaskDelay((BM1397_FULLSCAN_MS - 0.3 ) / portTICK_PERIOD_MS);
vTaskDelay((GLOBAL_STATE->asic_job_frequency_ms - 0.3) / portTICK_PERIOD_MS);
}
}

View File

@ -18,6 +18,7 @@
#define VOLTAGE_START_THROTTLE 4900
#define VOLTAGE_MIN_THROTTLE 3500
#define VOLTAGE_RANGE (VOLTAGE_START_THROTTLE - VOLTAGE_MIN_THROTTLE)
#define ASIC_MODEL CONFIG_ASIC_MODEL
static const char * TAG = "power_management";
@ -33,7 +34,7 @@ static float _fbound(float value, float lower_bound, float upper_bound)
// void _power_init(PowerManagementModule * power_management){
// power_management->frequency_multiplier = 1;
// power_management->frequency_value = BM1397_FREQUENCY;
// power_management->frequency_value = ASIC_FREQUENCY;
// }
@ -46,75 +47,76 @@ void POWER_MANAGEMENT_task(void * pvParameters){
int last_frequency_increase = 0;
while(1){
power_management->fan_speed = EMC2101_get_fan_speed();
power_management->chip_temp = EMC2101_get_chip_temp();
power_management->voltage = INA260_read_voltage();
power_management->power = INA260_read_power() / 1000;
power_management->current = INA260_read_current();
if(strcmp(ASIC_MODEL, "BM1397") == 0){
power_management->fan_speed = EMC2101_get_fan_speed();
power_management->chip_temp = EMC2101_get_chip_temp();
// Voltage
// We'll throttle between 4.9v and 3.5v
float voltage_multiplier = _fbound((power_management->voltage - VOLTAGE_MIN_THROTTLE) * (1/(float)VOLTAGE_RANGE), 0, 1);
// Voltage
// We'll throttle between 4.9v and 3.5v
float voltage_multiplier = _fbound((power_management->voltage - VOLTAGE_MIN_THROTTLE) * (1/(float)VOLTAGE_RANGE), 0, 1);
// Temperature
float temperature_multiplier = 1;
float over_temp = -(THROTTLE_TEMP - power_management->chip_temp);
if(over_temp > 0){
temperature_multiplier = (THROTTLE_TEMP_RANGE - over_temp)/THROTTLE_TEMP_RANGE;
}
float lowest_multiplier = 1;
float multipliers[2] = {voltage_multiplier, temperature_multiplier};
for(int i = 0; i < 2; i++){
if(multipliers[i] < lowest_multiplier){
lowest_multiplier = multipliers[i];
// Temperature
float temperature_multiplier = 1;
float over_temp = -(THROTTLE_TEMP - power_management->chip_temp);
if(over_temp > 0){
temperature_multiplier = (THROTTLE_TEMP_RANGE - over_temp)/THROTTLE_TEMP_RANGE;
}
float lowest_multiplier = 1;
float multipliers[2] = {voltage_multiplier, temperature_multiplier};
for(int i = 0; i < 2; i++){
if(multipliers[i] < lowest_multiplier){
lowest_multiplier = multipliers[i];
}
}
}
power_management->frequency_multiplier = lowest_multiplier;
power_management->frequency_multiplier = lowest_multiplier;
float target_frequency = _fbound(power_management->frequency_multiplier * BM1397_FREQUENCY, 0, BM1397_FREQUENCY);
float target_frequency = _fbound(power_management->frequency_multiplier * ASIC_FREQUENCY, 0, ASIC_FREQUENCY);
if(target_frequency < 50){
// TODO: Turn the chip off
}
if(target_frequency < 50){
// TODO: Turn the chip off
}
// chip is coming back from a low/no voltage event
if(power_management->frequency_value < 50 && target_frequency > 50){
// TODO recover gracefully?
esp_restart();
}
// chip is coming back from a low/no voltage event
if(power_management->frequency_value < 50 && target_frequency > 50){
// TODO recover gracefully?
esp_restart();
}
if(power_management->frequency_value > target_frequency){
power_management->frequency_value = target_frequency;
last_frequency_increase = 0;
BM1397_send_hash_frequency(power_management->frequency_value);
ESP_LOGI(TAG, "target %f, Freq %f, Temp %f, Power %f", target_frequency, power_management->frequency_value, power_management->chip_temp, power_management->power);
}else{
if(
last_frequency_increase > 120 &&
power_management->frequency_value != BM1397_FREQUENCY
){
float add = (target_frequency + power_management->frequency_value) / 2;
power_management->frequency_value += _fbound(add, 2 , 20);
if(power_management->frequency_value > target_frequency){
power_management->frequency_value = target_frequency;
last_frequency_increase = 0;
BM1397_send_hash_frequency(power_management->frequency_value);
ESP_LOGI(TAG, "target %f, Freq %f, Temp %f, Power %f", target_frequency, power_management->frequency_value, power_management->chip_temp, power_management->power);
last_frequency_increase = 60;
}else{
last_frequency_increase++;
if(
last_frequency_increase > 120 &&
power_management->frequency_value != ASIC_FREQUENCY
){
float add = (target_frequency + power_management->frequency_value) / 2;
power_management->frequency_value += _fbound(add, 2 , 20);
BM1397_send_hash_frequency(power_management->frequency_value);
ESP_LOGI(TAG, "target %f, Freq %f, Temp %f, Power %f", target_frequency, power_management->frequency_value, power_management->chip_temp, power_management->power);
last_frequency_increase = 60;
}else{
last_frequency_increase++;
}
}
}
//ESP_LOGI(TAG, "target %f, Freq %f, Volt %f, Power %f", target_frequency, power_management->frequency_value, power_management->voltage, power_management->power);
vTaskDelay(POLL_RATE / portTICK_PERIOD_MS);
}

View File

@ -16,6 +16,6 @@ include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(IDF_TARGET "esp32s3")
idf_build_set_property(COMPILE_DEFINITIONS "-DCONFIG_BM1397_FREQUENCY=100" APPEND)
idf_build_set_property(COMPILE_DEFINITIONS "-DCONFIG_ASIC_FREQUENCY=100" APPEND)
project(unit_test_stratum)