mirror of
https://github.com/skot/ESP-Miner.git
synced 2025-03-29 11:11:45 +01:00
Modularized 3 tasks, created global state struct
This commit is contained in:
parent
b604e0ccc6
commit
a7bae3ce71
@ -1,3 +1,12 @@
|
||||
idf_component_register(SRCS "bm1397.c" "serial.c" "crc.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES freertos driver stratum)
|
||||
idf_component_register(
|
||||
SRCS
|
||||
"bm1397.c"
|
||||
"serial.c"
|
||||
"crc.c"
|
||||
INCLUDE_DIRS
|
||||
"include"
|
||||
REQUIRES
|
||||
freertos
|
||||
driver
|
||||
stratum
|
||||
)
|
@ -1,3 +1,12 @@
|
||||
idf_component_register(SRCS "utils.c" "mining.c" "stratum_api.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES json mbedtls)
|
||||
idf_component_register(
|
||||
SRCS
|
||||
"utils.c"
|
||||
"mining.c"
|
||||
"stratum_api.c"
|
||||
|
||||
INCLUDE_DIRS
|
||||
"include"
|
||||
REQUIRES
|
||||
json
|
||||
mbedtls
|
||||
)
|
@ -1,12 +1,19 @@
|
||||
idf_component_register(SRCS
|
||||
"adc.c"
|
||||
"DS4432U.c"
|
||||
"EMC2101.c"
|
||||
"fonts.c"
|
||||
"INA260.c"
|
||||
"led_controller.c"
|
||||
"miner.c"
|
||||
"oled.c"
|
||||
"system.c"
|
||||
"work_queue.c"
|
||||
INCLUDE_DIRS ".")
|
||||
idf_component_register(
|
||||
SRCS
|
||||
"adc.c"
|
||||
"DS4432U.c"
|
||||
"EMC2101.c"
|
||||
"fonts.c"
|
||||
"INA260.c"
|
||||
"led_controller.c"
|
||||
"miner.c"
|
||||
"oled.c"
|
||||
"system.c"
|
||||
"work_queue.c"
|
||||
"./tasks/stratum_task.c"
|
||||
"./tasks/create_jobs_task.c"
|
||||
"./tasks/asic_task.c"
|
||||
INCLUDE_DIRS
|
||||
"."
|
||||
"tasks"
|
||||
)
|
||||
|
36
main/global_state.h
Normal file
36
main/global_state.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef GLOBAL_STATE_H_
|
||||
#define GLOBAL_STATE_H_
|
||||
|
||||
#include "work_queue.h"
|
||||
#include "bm1397.h"
|
||||
#include "system.h"
|
||||
|
||||
|
||||
|
||||
#define STRATUM_USER CONFIG_STRATUM_USER
|
||||
|
||||
|
||||
typedef struct {
|
||||
work_queue stratum_queue;
|
||||
work_queue ASIC_jobs_queue;
|
||||
|
||||
bm1397Module BM1397_MODULE;
|
||||
SystemModule SYSTEM_MODULE;
|
||||
|
||||
char * extranonce_str;
|
||||
int extranonce_2_len;
|
||||
int abandon_work;
|
||||
|
||||
uint8_t * valid_jobs;
|
||||
pthread_mutex_t valid_jobs_lock;
|
||||
|
||||
uint32_t stratum_difficulty;
|
||||
|
||||
int sock;
|
||||
|
||||
} GlobalState;
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* GLOBAL_STATE_H_ */
|
379
main/miner.c
379
main/miner.c
@ -1,366 +1,26 @@
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_netif.h"
|
||||
|
||||
#include "protocol_examples_common.h"
|
||||
#include "addr_from_stdin.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/ip4_addr.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "stratum_api.h"
|
||||
#include "mining.h"
|
||||
#include "work_queue.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "system.h"
|
||||
#include "serial.h"
|
||||
#include "bm1397.h"
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#define PORT CONFIG_STRATUM_PORT
|
||||
#define STRATUM_URL CONFIG_STRATUM_URL
|
||||
#define STRATUM_USER CONFIG_STRATUM_USER
|
||||
#define STRATUM_PW CONFIG_STRATUM_PW
|
||||
#include "stratum_task.h"
|
||||
#include "asic_task.h"
|
||||
#include "create_jobs_task.h"
|
||||
#include "global_state.h"
|
||||
|
||||
static GlobalState GLOBAL_STATE = {
|
||||
.extranonce_str = NULL,
|
||||
.extranonce_2_len = 0,
|
||||
.abandon_work = 0,
|
||||
.stratum_difficulty = 8192
|
||||
};
|
||||
|
||||
#define STRATUM_DIFFICULTY CONFIG_STRATUM_DIFFICULTY
|
||||
|
||||
static const char *TAG = "miner";
|
||||
|
||||
TaskHandle_t sysTaskHandle = NULL;
|
||||
TaskHandle_t serialTaskHandle = NULL;
|
||||
|
||||
static work_queue stratum_queue;
|
||||
static work_queue ASIC_jobs_queue;
|
||||
|
||||
static char * extranonce_str = NULL;
|
||||
static int extranonce_2_len = 0;
|
||||
|
||||
static int sock;
|
||||
|
||||
static int abandon_work = 0;
|
||||
static uint32_t stratum_difficulty = 8192;
|
||||
static bool difficulty_changed = false;
|
||||
|
||||
bm_job ** active_jobs;
|
||||
uint8_t * valid_jobs;
|
||||
pthread_mutex_t valid_jobs_lock;
|
||||
|
||||
static SystemModule SYSTEM_MODULE;
|
||||
static bm1397Module BM1397_MODULE;
|
||||
|
||||
static void ASIC_task(void * pvParameters)
|
||||
{
|
||||
SERIAL_init();
|
||||
|
||||
BM1397_init();
|
||||
|
||||
uint8_t buf[CHUNK_SIZE];
|
||||
memset(buf, 0, 1024);
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
active_jobs = malloc(sizeof(bm_job *) * 128);
|
||||
valid_jobs = malloc(sizeof(uint8_t) * 128);
|
||||
for (int i = 0; i < 128; i++) {
|
||||
active_jobs[i] = NULL;
|
||||
valid_jobs[i] = 0;
|
||||
}
|
||||
|
||||
uint32_t prev_nonce = 0;
|
||||
|
||||
int baud = BM1397_set_max_baud();
|
||||
SERIAL_set_baud(baud);
|
||||
|
||||
SYSTEM_notify_mining_started(&SYSTEM_MODULE);
|
||||
ESP_LOGI(TAG, "Mining!");
|
||||
while (1) {
|
||||
bm_job * next_bm_job = (bm_job *) queue_dequeue(&ASIC_jobs_queue);
|
||||
struct job_packet job;
|
||||
// max job number is 128
|
||||
id = (id + 4) % 128;
|
||||
job.job_id = id;
|
||||
job.num_midstates = 1;
|
||||
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 (active_jobs[job.job_id] != NULL) {
|
||||
free(active_jobs[job.job_id]->jobid);
|
||||
free(active_jobs[job.job_id]->extranonce2);
|
||||
free(active_jobs[job.job_id]);
|
||||
}
|
||||
active_jobs[job.job_id] = next_bm_job;
|
||||
|
||||
pthread_mutex_lock(&valid_jobs_lock);
|
||||
valid_jobs[job.job_id] = 1;
|
||||
pthread_mutex_unlock(&valid_jobs_lock);
|
||||
|
||||
SERIAL_clear_buffer();
|
||||
BM1397_send_work(&job); //send the job to the ASIC
|
||||
|
||||
//wait for a response
|
||||
int received = SERIAL_rx(buf, 9, BM1397_FULLSCAN_MS);
|
||||
|
||||
if (received < 0) {
|
||||
ESP_LOGI(TAG, "Error in serial RX");
|
||||
continue;
|
||||
} else if(received == 0){
|
||||
// Didn't find a solution, restart and try again
|
||||
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 nonce_found = 0;
|
||||
uint32_t first_nonce = 0;
|
||||
|
||||
struct nonce_response nonce;
|
||||
memcpy((void *) &nonce, buf, sizeof(struct nonce_response));
|
||||
|
||||
if (valid_jobs[nonce.job_id] == 0) {
|
||||
ESP_LOGI(TAG, "Invalid job nonce found");
|
||||
}
|
||||
|
||||
//print_hex((uint8_t *) &nonce.nonce, 4, 4, "nonce: ");
|
||||
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;
|
||||
}
|
||||
|
||||
// check the nonce difficulty
|
||||
double nonce_diff = test_nonce_value(active_jobs[nonce.job_id], nonce.nonce);
|
||||
|
||||
ESP_LOGI(TAG, "Nonce difficulty %.2f of %d.", nonce_diff, active_jobs[nonce.job_id]->pool_diff);
|
||||
|
||||
if (nonce_diff > active_jobs[nonce.job_id]->pool_diff)
|
||||
{
|
||||
SYSTEM_notify_found_nonce(&SYSTEM_MODULE, active_jobs[nonce.job_id]->pool_diff);
|
||||
|
||||
submit_share(sock, STRATUM_USER, active_jobs[nonce.job_id]->jobid, active_jobs[nonce.job_id]->ntime,
|
||||
active_jobs[nonce.job_id]->extranonce2, nonce.nonce);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void create_jobs_task(void * pvParameters)
|
||||
{
|
||||
while (1) {
|
||||
char * next_notify_json_str = (char *) queue_dequeue(&stratum_queue);
|
||||
ESP_LOGI(TAG, "New Work Dequeued");
|
||||
uint32_t free_heap_size = esp_get_free_heap_size();
|
||||
ESP_LOGI(TAG, "miner heap free size: %u bytes", free_heap_size);
|
||||
|
||||
mining_notify params = parse_mining_notify_message(next_notify_json_str);
|
||||
|
||||
uint32_t extranonce_2 = 0;
|
||||
while (extranonce_2 < UINT_MAX && abandon_work == 0)
|
||||
{
|
||||
char * extranonce_2_str = extranonce_2_generate(extranonce_2, extranonce_2_len);
|
||||
|
||||
char *coinbase_tx = construct_coinbase_tx(params.coinbase_1, params.coinbase_2, extranonce_str, extranonce_2_str);
|
||||
//ESP_LOGI(TAG, "Coinbase tx: %s", coinbase_tx);
|
||||
|
||||
char *merkle_root = calculate_merkle_root_hash(coinbase_tx, (uint8_t(*)[32])params.merkle_branches, params.n_merkle_branches);
|
||||
//ESP_LOGI(TAG, "Merkle root: %s", merkle_root);
|
||||
|
||||
bm_job next_job = construct_bm_job(¶ms, merkle_root);
|
||||
|
||||
next_job.pool_diff = stratum_difficulty; //each job is tied to the _current_ difficulty
|
||||
// Check if diff is a power of 2, we can skip stuff later if it is.
|
||||
next_job.pool_diff_pow2 = (stratum_difficulty != 0 && (stratum_difficulty & (stratum_difficulty - 1)) == 0);
|
||||
|
||||
bm_job * queued_next_job = malloc(sizeof(bm_job));
|
||||
memcpy(queued_next_job, &next_job, sizeof(bm_job));
|
||||
queued_next_job->extranonce2 = strdup(extranonce_2_str);
|
||||
queued_next_job->jobid = strdup(params.job_id);
|
||||
|
||||
queue_enqueue(&ASIC_jobs_queue, queued_next_job);
|
||||
|
||||
free(coinbase_tx);
|
||||
free(merkle_root);
|
||||
free(extranonce_2_str);
|
||||
extranonce_2++;
|
||||
}
|
||||
|
||||
if (abandon_work == 1) {
|
||||
abandon_work = 0;
|
||||
ASIC_jobs_queue_clear(&ASIC_jobs_queue);
|
||||
}
|
||||
|
||||
free_mining_notify(params);
|
||||
free(next_notify_json_str);
|
||||
}
|
||||
}
|
||||
|
||||
ip_addr_t ip_Addr;
|
||||
bool bDNSFound = false;
|
||||
|
||||
void dns_found_cb(const char * name, const ip_addr_t * ipaddr, void * callback_arg)
|
||||
{
|
||||
ip_Addr = *ipaddr;
|
||||
bDNSFound = true;
|
||||
}
|
||||
|
||||
static void stratum_task(void * pvParameters)
|
||||
{
|
||||
initialize_stratum_buffer();
|
||||
char host_ip[20];
|
||||
int addr_family = 0;
|
||||
int ip_protocol = 0;
|
||||
|
||||
//get ip address from hostname
|
||||
IP_ADDR4(&ip_Addr, 0, 0, 0, 0);
|
||||
printf("Get IP for URL: %s\n", STRATUM_URL);
|
||||
dns_gethostbyname(STRATUM_URL, &ip_Addr, dns_found_cb, NULL);
|
||||
while (!bDNSFound);
|
||||
|
||||
//make IP address string from ip_Addr
|
||||
snprintf(host_ip, sizeof(host_ip), "%d.%d.%d.%d",
|
||||
ip4_addr1(&ip_Addr.u_addr.ip4),
|
||||
ip4_addr2(&ip_Addr.u_addr.ip4),
|
||||
ip4_addr3(&ip_Addr.u_addr.ip4),
|
||||
ip4_addr4(&ip_Addr.u_addr.ip4));
|
||||
printf("Connecting to: stratum+tcp://%s:%d (%s)\n", STRATUM_URL, PORT, host_ip);
|
||||
|
||||
while (1) {
|
||||
struct sockaddr_in dest_addr;
|
||||
dest_addr.sin_addr.s_addr = inet_addr(host_ip);
|
||||
dest_addr.sin_family = AF_INET;
|
||||
dest_addr.sin_port = htons(PORT);
|
||||
addr_family = AF_INET;
|
||||
ip_protocol = IPPROTO_IP;
|
||||
|
||||
sock = socket(addr_family, SOCK_STREAM, ip_protocol);
|
||||
if (sock < 0)
|
||||
{
|
||||
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);
|
||||
|
||||
int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
|
||||
if (err != 0)
|
||||
{
|
||||
ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t version_mask = 0;
|
||||
|
||||
subscribe_to_stratum(sock, &extranonce_str, &extranonce_2_len);
|
||||
|
||||
configure_version_rolling(sock);
|
||||
|
||||
auth_to_stratum(sock, STRATUM_USER);
|
||||
|
||||
ESP_LOGI(TAG, "Extranonce: %s", extranonce_str);
|
||||
ESP_LOGI(TAG, "Extranonce 2 length: %d", extranonce_2_len);
|
||||
|
||||
suggest_difficulty(sock, STRATUM_DIFFICULTY);
|
||||
|
||||
while (1)
|
||||
{
|
||||
char * line = receive_jsonrpc_line(sock);
|
||||
ESP_LOGI(TAG, "stratum rx: %s", line); //debug incoming stratum messages
|
||||
|
||||
stratum_method method = parse_stratum_method(line);
|
||||
|
||||
if (method == MINING_NOTIFY) {
|
||||
if ((difficulty_changed || should_abandon_work(line)) && stratum_queue.count > 0) {
|
||||
|
||||
if (difficulty_changed) {
|
||||
ESP_LOGI(TAG, "pool diff changed, clearing queues");
|
||||
difficulty_changed = false;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "clean_jobs is true, clearing queues");
|
||||
}
|
||||
|
||||
abandon_work = 1;
|
||||
queue_clear(&stratum_queue);
|
||||
|
||||
pthread_mutex_lock(&valid_jobs_lock);
|
||||
ASIC_jobs_queue_clear(&ASIC_jobs_queue);
|
||||
for (int i = 0; i < 128; i = i + 4) {
|
||||
valid_jobs[i] = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&valid_jobs_lock);
|
||||
}
|
||||
if (stratum_queue.count == QUEUE_SIZE) {
|
||||
char * next_notify_json_str = (char *) queue_dequeue(&stratum_queue);
|
||||
free(next_notify_json_str);
|
||||
}
|
||||
queue_enqueue(&stratum_queue, line);
|
||||
} else if (method == MINING_SET_DIFFICULTY) {
|
||||
uint32_t new_difficulty = parse_mining_set_difficulty_message(line);
|
||||
if (new_difficulty != stratum_difficulty) {
|
||||
stratum_difficulty = new_difficulty;
|
||||
difficulty_changed = true;
|
||||
ESP_LOGI(TAG, "Set stratum difficulty: %d", stratum_difficulty);
|
||||
BM1397_set_job_difficulty_mask(stratum_difficulty);
|
||||
}
|
||||
free(line);
|
||||
|
||||
} else if (method == MINING_SET_VERSION_MASK) {
|
||||
version_mask = parse_mining_set_version_mask_message(line);
|
||||
|
||||
//1fffe000
|
||||
ESP_LOGI(TAG, "Set version mask: %08x", version_mask);
|
||||
free(line);
|
||||
|
||||
} else if (method == STRATUM_RESULT) {
|
||||
int16_t parsed_id;
|
||||
if (parse_stratum_result_message(line, &parsed_id)) {
|
||||
ESP_LOGI(TAG, "message id %d result accepted", parsed_id);
|
||||
SYSTEM_notify_accepted_share(&SYSTEM_MODULE);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "message id %d result rejected", parsed_id);
|
||||
SYSTEM_notify_rejected_share(&SYSTEM_MODULE);
|
||||
}
|
||||
free(line);
|
||||
} else {
|
||||
free(line);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (sock != -1)
|
||||
{
|
||||
ESP_LOGE(TAG, "Shutting down socket and restarting...");
|
||||
shutdown(sock, 0);
|
||||
close(sock);
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
@ -369,7 +29,7 @@ void app_main(void)
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
xTaskCreate(SYSTEM_task, "SYSTEM_task", 4096, (void*)&SYSTEM_MODULE, 10, &sysTaskHandle);
|
||||
xTaskCreate(SYSTEM_task, "SYSTEM_task", 4096, (void*)&GLOBAL_STATE.SYSTEM_MODULE, 10, NULL);
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
@ -377,12 +37,11 @@ void app_main(void)
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
queue_init(&stratum_queue);
|
||||
queue_init(&ASIC_jobs_queue);
|
||||
queue_init(&GLOBAL_STATE.stratum_queue);
|
||||
queue_init(&GLOBAL_STATE.ASIC_jobs_queue);
|
||||
|
||||
xTaskCreate(stratum_task, "stratum admin", 8192, NULL, 15, NULL);
|
||||
xTaskCreate(create_jobs_task, "stratum miner", 8192, NULL, 10, NULL);
|
||||
xTaskCreate(ASIC_task, "asic", 8192, NULL, 10, &serialTaskHandle);
|
||||
xTaskCreate(stratum_task, "stratum admin", 8192, (void*)&GLOBAL_STATE, 15, NULL);
|
||||
xTaskCreate(create_jobs_task, "stratum miner", 8192, (void*)&GLOBAL_STATE, 10, NULL);
|
||||
xTaskCreate(ASIC_task, "asic", 8192, (void*)&GLOBAL_STATE, 10, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -180,9 +180,9 @@ static void _update_system_performance(SystemModule* module){
|
||||
}
|
||||
|
||||
|
||||
void SYSTEM_task(void *parameters) {
|
||||
void SYSTEM_task(void *pvParameters) {
|
||||
|
||||
SystemModule *module = (SystemModule*)parameters;
|
||||
SystemModule *module = (SystemModule*)pvParameters;
|
||||
_init_system(module);
|
||||
|
||||
while(1){
|
||||
|
123
main/tasks/asic_task.c
Normal file
123
main/tasks/asic_task.c
Normal file
@ -0,0 +1,123 @@
|
||||
#include "global_state.h"
|
||||
#include "work_queue.h"
|
||||
#include "serial.h"
|
||||
#include "bm1397.h"
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "ASIC_task";
|
||||
|
||||
static bm_job ** active_jobs;
|
||||
|
||||
void ASIC_task(void * pvParameters)
|
||||
{
|
||||
|
||||
GlobalState *GLOBAL_STATE = (GlobalState*)pvParameters;
|
||||
|
||||
SERIAL_init();
|
||||
|
||||
BM1397_init();
|
||||
|
||||
uint8_t buf[CHUNK_SIZE];
|
||||
memset(buf, 0, 1024);
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
active_jobs = malloc(sizeof(bm_job *) * 128);
|
||||
GLOBAL_STATE->valid_jobs = malloc(sizeof(uint8_t) * 128);
|
||||
for (int i = 0; i < 128; i++) {
|
||||
active_jobs[i] = NULL;
|
||||
GLOBAL_STATE->valid_jobs[i] = 0;
|
||||
}
|
||||
|
||||
uint32_t prev_nonce = 0;
|
||||
|
||||
int baud = BM1397_set_max_baud();
|
||||
SERIAL_set_baud(baud);
|
||||
|
||||
SYSTEM_notify_mining_started(&GLOBAL_STATE->SYSTEM_MODULE);
|
||||
ESP_LOGI(TAG, "Mining!");
|
||||
while (1) {
|
||||
bm_job * next_bm_job = (bm_job *) queue_dequeue(&GLOBAL_STATE->ASIC_jobs_queue);
|
||||
struct job_packet job;
|
||||
// max job number is 128
|
||||
id = (id + 4) % 128;
|
||||
job.job_id = id;
|
||||
job.num_midstates = 1;
|
||||
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 (active_jobs[job.job_id] != NULL) {
|
||||
free(active_jobs[job.job_id]->jobid);
|
||||
free(active_jobs[job.job_id]->extranonce2);
|
||||
free(active_jobs[job.job_id]);
|
||||
}
|
||||
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);
|
||||
|
||||
SERIAL_clear_buffer();
|
||||
BM1397_send_work(&job); //send the job to the ASIC
|
||||
|
||||
//wait for a response
|
||||
int received = SERIAL_rx(buf, 9, BM1397_FULLSCAN_MS);
|
||||
|
||||
if (received < 0) {
|
||||
ESP_LOGI(TAG, "Error in serial RX");
|
||||
continue;
|
||||
} else if(received == 0){
|
||||
// Didn't find a solution, restart and try again
|
||||
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 nonce_found = 0;
|
||||
uint32_t first_nonce = 0;
|
||||
|
||||
struct nonce_response nonce;
|
||||
memcpy((void *) &nonce, buf, sizeof(struct nonce_response));
|
||||
|
||||
if (GLOBAL_STATE->valid_jobs[nonce.job_id] == 0) {
|
||||
ESP_LOGI(TAG, "Invalid job nonce found");
|
||||
}
|
||||
|
||||
//print_hex((uint8_t *) &nonce.nonce, 4, 4, "nonce: ");
|
||||
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;
|
||||
}
|
||||
|
||||
// check the nonce difficulty
|
||||
double nonce_diff = test_nonce_value(active_jobs[nonce.job_id], nonce.nonce);
|
||||
|
||||
ESP_LOGI(TAG, "Nonce difficulty %.2f of %d.", nonce_diff, active_jobs[nonce.job_id]->pool_diff);
|
||||
|
||||
if (nonce_diff > active_jobs[nonce.job_id]->pool_diff)
|
||||
{
|
||||
SYSTEM_notify_found_nonce(&GLOBAL_STATE->SYSTEM_MODULE, active_jobs[nonce.job_id]->pool_diff);
|
||||
|
||||
submit_share(GLOBAL_STATE->sock, STRATUM_USER, active_jobs[nonce.job_id]->jobid, active_jobs[nonce.job_id]->ntime,
|
||||
active_jobs[nonce.job_id]->extranonce2, nonce.nonce);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
6
main/tasks/asic_task.h
Normal file
6
main/tasks/asic_task.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef ASIC_TASK_H_
|
||||
#define ASIC_TASK_H_
|
||||
|
||||
void ASIC_task(void * pvParameters);
|
||||
|
||||
#endif
|
66
main/tasks/create_jobs_task.c
Normal file
66
main/tasks/create_jobs_task.c
Normal file
@ -0,0 +1,66 @@
|
||||
#include "work_queue.h"
|
||||
#include "global_state.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "mining.h"
|
||||
#include <limits.h>
|
||||
#include "string.h"
|
||||
|
||||
|
||||
|
||||
static const char *TAG = "create_jobs_task";
|
||||
|
||||
void create_jobs_task(void * pvParameters)
|
||||
{
|
||||
|
||||
GlobalState *GLOBAL_STATE = (GlobalState*)pvParameters;
|
||||
|
||||
|
||||
while (1) {
|
||||
char * next_notify_json_str = (char *) queue_dequeue(&GLOBAL_STATE->stratum_queue);
|
||||
ESP_LOGI(TAG, "New Work Dequeued");
|
||||
uint32_t free_heap_size = esp_get_free_heap_size();
|
||||
ESP_LOGI(TAG, "miner heap free size: %u bytes", free_heap_size);
|
||||
|
||||
mining_notify params = parse_mining_notify_message(next_notify_json_str);
|
||||
|
||||
uint32_t extranonce_2 = 0;
|
||||
while (extranonce_2 < UINT_MAX && GLOBAL_STATE->abandon_work == 0)
|
||||
{
|
||||
char * extranonce_2_str = extranonce_2_generate(extranonce_2, GLOBAL_STATE->extranonce_2_len);
|
||||
|
||||
char *coinbase_tx = construct_coinbase_tx(params.coinbase_1, params.coinbase_2, GLOBAL_STATE->extranonce_str, extranonce_2_str);
|
||||
//ESP_LOGI(TAG, "Coinbase tx: %s", coinbase_tx);
|
||||
|
||||
char *merkle_root = calculate_merkle_root_hash(coinbase_tx, (uint8_t(*)[32])params.merkle_branches, params.n_merkle_branches);
|
||||
//ESP_LOGI(TAG, "Merkle root: %s", merkle_root);
|
||||
|
||||
bm_job next_job = construct_bm_job(¶ms, merkle_root);
|
||||
|
||||
next_job.pool_diff = GLOBAL_STATE->stratum_difficulty; //each job is tied to the _current_ difficulty
|
||||
|
||||
bm_job * queued_next_job = malloc(sizeof(bm_job));
|
||||
memcpy(queued_next_job, &next_job, sizeof(bm_job));
|
||||
queued_next_job->extranonce2 = strdup(extranonce_2_str);
|
||||
queued_next_job->jobid = strdup(params.job_id);
|
||||
|
||||
queue_enqueue(&GLOBAL_STATE->ASIC_jobs_queue, queued_next_job);
|
||||
|
||||
free(coinbase_tx);
|
||||
free(merkle_root);
|
||||
free(extranonce_2_str);
|
||||
extranonce_2++;
|
||||
}
|
||||
|
||||
if (GLOBAL_STATE->abandon_work == 1) {
|
||||
GLOBAL_STATE->abandon_work = 0;
|
||||
ASIC_jobs_queue_clear(&GLOBAL_STATE->ASIC_jobs_queue);
|
||||
}
|
||||
|
||||
free_mining_notify(params);
|
||||
free(next_notify_json_str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
6
main/tasks/create_jobs_task.h
Normal file
6
main/tasks/create_jobs_task.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef CREATE_JOBS_TASK_H_
|
||||
#define CREATE_JOBS_TASK_H_
|
||||
|
||||
void create_jobs_task(void * pvParameters);
|
||||
|
||||
#endif
|
162
main/tasks/stratum_task.c
Normal file
162
main/tasks/stratum_task.c
Normal file
@ -0,0 +1,162 @@
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "addr_from_stdin.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "work_queue.h"
|
||||
#include "bm1397.h"
|
||||
#include "global_state.h"
|
||||
|
||||
#define PORT CONFIG_STRATUM_PORT
|
||||
#define STRATUM_URL CONFIG_STRATUM_URL
|
||||
|
||||
#define STRATUM_PW CONFIG_STRATUM_PW
|
||||
#define STRATUM_DIFFICULTY CONFIG_STRATUM_DIFFICULTY
|
||||
|
||||
static const char *TAG = "stratum_task";
|
||||
static ip_addr_t ip_Addr;
|
||||
static bool bDNSFound = false;
|
||||
static bool difficulty_changed = false;
|
||||
|
||||
|
||||
void dns_found_cb(const char * name, const ip_addr_t * ipaddr, void * callback_arg)
|
||||
{
|
||||
ip_Addr = *ipaddr;
|
||||
bDNSFound = true;
|
||||
}
|
||||
|
||||
|
||||
void stratum_task(void * pvParameters)
|
||||
{
|
||||
|
||||
GlobalState *GLOBAL_STATE = (GlobalState*)pvParameters;
|
||||
|
||||
initialize_stratum_buffer();
|
||||
char host_ip[20];
|
||||
int addr_family = 0;
|
||||
int ip_protocol = 0;
|
||||
|
||||
//get ip address from hostname
|
||||
IP_ADDR4(&ip_Addr, 0, 0, 0, 0);
|
||||
printf("Get IP for URL: %s\n", STRATUM_URL);
|
||||
dns_gethostbyname(STRATUM_URL, &ip_Addr, dns_found_cb, NULL);
|
||||
while (!bDNSFound);
|
||||
|
||||
//make IP address string from ip_Addr
|
||||
snprintf(host_ip, sizeof(host_ip), "%d.%d.%d.%d",
|
||||
ip4_addr1(&ip_Addr.u_addr.ip4),
|
||||
ip4_addr2(&ip_Addr.u_addr.ip4),
|
||||
ip4_addr3(&ip_Addr.u_addr.ip4),
|
||||
ip4_addr4(&ip_Addr.u_addr.ip4));
|
||||
printf("Connecting to: stratum+tcp://%s:%d (%s)\n", STRATUM_URL, PORT, host_ip);
|
||||
|
||||
while (1) {
|
||||
struct sockaddr_in dest_addr;
|
||||
dest_addr.sin_addr.s_addr = inet_addr(host_ip);
|
||||
dest_addr.sin_family = AF_INET;
|
||||
dest_addr.sin_port = htons(PORT);
|
||||
addr_family = AF_INET;
|
||||
ip_protocol = IPPROTO_IP;
|
||||
|
||||
GLOBAL_STATE->sock = socket(addr_family, SOCK_STREAM, ip_protocol);
|
||||
if (GLOBAL_STATE->sock < 0)
|
||||
{
|
||||
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);
|
||||
|
||||
int err = connect(GLOBAL_STATE->sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
|
||||
if (err != 0)
|
||||
{
|
||||
ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t version_mask = 0;
|
||||
|
||||
subscribe_to_stratum(GLOBAL_STATE->sock, &GLOBAL_STATE->extranonce_str, &GLOBAL_STATE->extranonce_2_len);
|
||||
|
||||
configure_version_rolling(GLOBAL_STATE->sock);
|
||||
|
||||
auth_to_stratum(GLOBAL_STATE->sock, STRATUM_USER);
|
||||
|
||||
ESP_LOGI(TAG, "Extranonce: %s", GLOBAL_STATE->extranonce_str);
|
||||
ESP_LOGI(TAG, "Extranonce 2 length: %d", GLOBAL_STATE->extranonce_2_len);
|
||||
|
||||
suggest_difficulty(GLOBAL_STATE->sock, STRATUM_DIFFICULTY);
|
||||
|
||||
while (1)
|
||||
{
|
||||
char * line = receive_jsonrpc_line( GLOBAL_STATE->sock);
|
||||
ESP_LOGI(TAG, "stratum rx: %s", line); //debug incoming stratum messages
|
||||
|
||||
stratum_method method = parse_stratum_method(line);
|
||||
|
||||
if (method == MINING_NOTIFY) {
|
||||
if ((difficulty_changed || should_abandon_work(line)) && GLOBAL_STATE->stratum_queue.count > 0) {
|
||||
|
||||
if (difficulty_changed) {
|
||||
ESP_LOGI(TAG, "pool diff changed, clearing queues");
|
||||
difficulty_changed = false;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "clean_jobs is true, clearing queues");
|
||||
}
|
||||
|
||||
GLOBAL_STATE->abandon_work = 1;
|
||||
queue_clear(&GLOBAL_STATE->stratum_queue);
|
||||
|
||||
pthread_mutex_lock(&GLOBAL_STATE->valid_jobs_lock);
|
||||
ASIC_jobs_queue_clear(&GLOBAL_STATE->ASIC_jobs_queue);
|
||||
for (int i = 0; i < 128; i = i + 4) {
|
||||
GLOBAL_STATE->valid_jobs[i] = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&GLOBAL_STATE->valid_jobs_lock);
|
||||
}
|
||||
if ( GLOBAL_STATE->stratum_queue.count == QUEUE_SIZE) {
|
||||
char * next_notify_json_str = (char *) queue_dequeue(&GLOBAL_STATE->stratum_queue);
|
||||
free(next_notify_json_str);
|
||||
}
|
||||
queue_enqueue(&GLOBAL_STATE->stratum_queue, line);
|
||||
} else if (method == MINING_SET_DIFFICULTY) {
|
||||
uint32_t new_difficulty = parse_mining_set_difficulty_message(line);
|
||||
if (new_difficulty != GLOBAL_STATE->stratum_difficulty) {
|
||||
GLOBAL_STATE->stratum_difficulty = new_difficulty;
|
||||
difficulty_changed = true;
|
||||
ESP_LOGI(TAG, "Set stratum difficulty: %d", GLOBAL_STATE->stratum_difficulty);
|
||||
BM1397_set_job_difficulty_mask(GLOBAL_STATE->stratum_difficulty);
|
||||
}
|
||||
free(line);
|
||||
|
||||
} else if (method == MINING_SET_VERSION_MASK) {
|
||||
version_mask = parse_mining_set_version_mask_message(line);
|
||||
|
||||
//1fffe000
|
||||
ESP_LOGI(TAG, "Set version mask: %08x", version_mask);
|
||||
free(line);
|
||||
|
||||
} else if (method == STRATUM_RESULT) {
|
||||
int16_t parsed_id;
|
||||
if (parse_stratum_result_message(line, &parsed_id)) {
|
||||
ESP_LOGI(TAG, "message id %d result accepted", parsed_id);
|
||||
SYSTEM_notify_accepted_share(&GLOBAL_STATE->SYSTEM_MODULE);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "message id %d result rejected", parsed_id);
|
||||
SYSTEM_notify_rejected_share(&GLOBAL_STATE->SYSTEM_MODULE);
|
||||
}
|
||||
free(line);
|
||||
} else {
|
||||
free(line);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (GLOBAL_STATE->sock != -1)
|
||||
{
|
||||
ESP_LOGE(TAG, "Shutting down socket and restarting...");
|
||||
shutdown(GLOBAL_STATE->sock, 0);
|
||||
close(GLOBAL_STATE->sock);
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
6
main/tasks/stratum_task.h
Normal file
6
main/tasks/stratum_task.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef STRATUM_TASK_H_
|
||||
#define STRATUM_TASK_H_
|
||||
|
||||
void stratum_task(void * pvParameters);
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user