Compare commits

...

57 Commits

Author SHA1 Message Date
JP Compagnone
6a6b917102
Merge f267f2857c50aa5b39cf856e6dc13845bcef6c82 into 9d8198a4bb091b5404ab67c570a705cd319cfae6 2025-03-16 22:43:09 +00:00
John-Paul Compagnone
f267f2857c api: add expected hashrate 2025-03-16 18:43:01 -04:00
skot
9d8198a4bb
Update readme.md with latest unlock settings 2025-03-16 13:13:18 -04:00
w3irdrobot
36e06236b0
Improve null handling in API settings PATCH (#748)
* Improve null handling in API settings PATCH

* Use CJSON lib function for string detection

This reverts commit e0cbb877723ef86d139fee67d3ddfb856f57e1fb.
2025-03-16 16:12:13 +01:00
WantClue
c5609dfce1
fix: ports over everything to bitaxeorg (#774) 2025-03-15 22:41:10 +01:00
WantClue
dd4ecbc72e
fix: swap update www and esp-miner (#771) 2025-03-14 14:11:38 +01:00
WantClue
64218d63d2
Overclock url params (#770)
* fix: use url params to unlock overclock

* fix: better message

* chore: wording update again

* chore: shorten message more

* feat: add nvs storage of oc mode

* fix: remove duplicate

---------

Co-authored-by: mrv777 <mrv777@users.noreply.github.com>
2025-03-13 22:41:44 +01:00
mrv777
e29b8e3afb
fix: use url params to unlock overclock (#729)
* fix: use url params to unlock overclock

* fix: better message

* chore: wording update again

* chore: shorten message more
2025-03-13 21:54:13 +01:00
mutatrum
a5842a54b3
Verify CHIP_ID response (#745)
* Verify CHIP_ID response

Fixes #740

* Log warning on CHIP_ID mismatch

* Fix CHIP_ID checksum calculation

* On BM1397, CORE_NUM should be 0x18

* CORE_NUM and ADDR log only and early exit when no chips are detected

* Fix compile error

* Refactored out duplicated code

Moved count_asic_chips and receive_work functions to common.c
Moved asic_response_buffer to local scope
Unified preamble and crc check on serial rx
Fixed typo in proccess_work
Moved CRC5_MASK define to proper location

* Change receive_work read timeout log to debug

* Changed wrong log to debug

* Fix merge

* Fix length check for bm1397

* add ASIC TX dubugging on BM1397 (crap, does this fix the ticket mask?!)

---------

Co-authored-by: Skot <skot@bitnet.cx>
2025-03-12 22:45:33 +01:00
Erik Olof Gunnar Andersson
deaa291675
Revert "Refactor Stratum code for Seamless Failover (#717)" (#754)
This reverts commit 1eeb303672c876939d53328fd8395e3813a97dcf.
2025-03-10 13:30:31 +01:00
WantClue
d032f2da4a
feat: frequency transition (#747)
* feat: frequency transition

* remove floats that are unnecessary

* fix: callback of set_freq function

* refactor asic model code to asic.c

* fix: change namining scheme
2025-03-09 13:58:13 +01:00
Erik Olof Gunnar Andersson
1eeb303672
Refactor Stratum code for Seamless Failover (#717)
* Refactor stratum code

* No need to abandon work when switching connection

* Bump primary task priority slightly

* Reduce watchdog stack size

* Revert debug changes

* Removed unused code

* Removed unused unit test code

* Handle jobs more aggressively

* Fix merge conflict
2025-03-09 13:55:58 +01:00
Erik Olof Gunnar Andersson
6e1205f30a
Remove unit test workaround for qemu (#743) 2025-03-08 23:15:59 +01:00
WantClue
c267789dbd
fix: current not exposed to api (#749) 2025-03-08 23:12:14 +01:00
mutatrum
a0c9710a90
Show share reject reasons (#746)
* Show share reject reasons

Fixes #264

* Fix string assignment
2025-03-08 13:07:16 +01:00
w3irdrobot
60fba27826
add sorting switch to swarm page for hostname and ip (#733) 2025-02-27 07:18:42 +01:00
w3irdrobot
56731b5c63
Trim spaces from front and back of SSID on client side (#728) 2025-02-26 16:24:10 +01:00
mutatrum
b92f70d871
Show firmware updates on the display (#664) 2025-02-21 21:34:50 +01:00
Erik Olof Gunnar Andersson
b21cd50504
Fix stackoverflow when upgrading (#723) 2025-02-20 21:54:16 +01:00
WantClue
ca4e5dcc2a
fix: typo in .find (#724) 2025-02-20 07:04:11 +01:00
WantClue
b60fd3dfce
Remove hard code (#721) 2025-02-19 14:27:31 +01:00
WantClue
8bd8b88af9
feat: update readme (#720) 2025-02-18 21:58:00 +01:00
WantClue
4c76d17a4d
feat: unlock OC (#714) 2025-02-18 15:58:27 +01:00
WantClue
ac4ffbc2f2 add repobeats 2025-02-17 14:43:09 +01:00
Skot
6d504fe1a1
Revert "add Pro mode button (#712)" (#713)
This reverts commit fe78e056112ac31abd553889e25571b5384683f4.
2025-02-16 12:26:37 -05:00
WantClue
fe78e05611
add Pro mode button (#712)
* feat: add tooltip for pwm invert and flip screen

* feat: add Pro Mode Button
2025-02-16 12:11:51 +01:00
WantClue
91f302c744
feat: add tooltip for pwm invert and flip screen (#709) 2025-02-15 20:05:05 +01:00
mrv777
29f66b228e
fix: Move avg hash to card & add eff avg (#643)
* fix: Move avg hash to card & add eff avg

* fix: Try different layout

* fix: Move expected to under avg
2025-02-15 19:45:47 +01:00
mutatrum
ad5d1291b9
Remove undefined method headers (#704) 2025-02-15 19:40:09 +01:00
Erik Olof Gunnar Andersson
bec0863a82
Disable softap even if we don't have a valid model (#706) 2025-02-15 19:38:25 +01:00
Erik Olof Gunnar Andersson
b8c748be69
Restore Max support (#705) 2025-02-15 12:14:27 +01:00
mutatrum
9c0354653f
Don't show -1 temperature on screen (#703)
Follow-up of #692
2025-02-13 19:54:42 +01:00
Dustin Butler
0d02eb5eec
Init AxeOS AP mode (#624)
* Init AxeOS AP mode

* Use minimal layout with logo for AP mode

* apEnabled off
2025-02-13 19:53:52 +01:00
Steven Martins
59141357ff
fix(ui): display placeholder for unavailable ASIC temp (#692)
* fix(ui): display placeholder for unavailable ASIC temp
* fix(screen): update placeholders to match UI
2025-02-11 23:33:23 -05:00
Skot
7dcb69ebdc
GammaTurbo support and HW abstraction (#698)
* initial changes for the gammaturbo bringup
* added preliminary TPS546 changes
* added preliminary EMC2103 support
* ASIC temp seems to be maybe working.
* magically now fan seems to have the right polarity
* added in ideality and beta constants (currently unused). Fixed EMC2103_get_fan_speed()
* abstract fan and ASIC temp into thermal functions
* abstracted voltage regulator specifics out of tasks and into power.c and vcore.c functions
* add TPS546 support for multiple models
* move TPS40305/DS4432U vout setter to DS4432U.c
* move all ASIC specific functions to asic.c
* bad device_model nvs handling
* remove old code
* add workaround for TPS546 VIN_UV_WARN_LIMIT silicon bug.
2025-02-11 22:46:56 -05:00
mutatrum
080d0fe2cc
More Wi-Fi spelling fixes (#685) 2025-02-11 18:28:30 +01:00
Erik Olof Gunnar Andersson
1014a46a24
Updated confusing log connect message (#697) 2025-02-10 13:58:16 -05:00
Erik Olof Gunnar Andersson
678809a5f8
Improved pool fallback code (#693)
* Disconnect if no data received in more than 10 minutes

* Minor socket fix

* Removed unused code and minor nit fix
2025-02-06 18:48:04 +01:00
Luke Dashjr
2b958c0b94
Bugfix: Submit shares that are exactly equal to the target when rounded to a "diff" (#687) 2025-02-06 18:47:45 +01:00
WantClue
cbb02389ba
Wifi scan fix (#690)
* feature: wifi reconnect disable wifi connect

* fix: scanning flag to prevent reconnect attempts

* fix: add external bool, define globally

* fix: wifi scan on missing ssid

* fix: remove unused connected flag
2025-02-04 03:40:06 +01:00
mutatrum
548f91410b
Fix Wi-Fi spelling (#684)
* Fix Wi-Fi spelling

* Shorten label
2025-02-02 10:31:24 +01:00
WantClue
19ce1df337
fix: adjust wifi setup text speed (#682) 2025-02-01 21:40:51 +01:00
WantClue
980d213445
SSID WiFi lookup (#679)
* init

* fix: filter out poor networks
2025-02-01 18:19:30 +01:00
Brett Rowan
c98ac818c9
Grandma knows what Wifi means! (#623)
* Grandma knows what Wifi means!

Use Wifi instead of SSID on screen, and add short `(join for setup)` message instead of `Configuration SSID`.
This should be easier to understand, but does add 2 characters, which will fill the screen completely.

* Change NVS configs to init wifi with empty strings, and check for empty string when initializing wifi

* Change `WiFi` to `Wi-Fi` in `connect.c`

* Change what information shows on screen during inital setup and on wifi error

* fix: remove camelCase

remove Bitaxe camel case

---------

Co-authored-by: Upstream Data <brett@upstreamdata.ca>
Co-authored-by: WantClue <86001033+WantClue@users.noreply.github.com>
2025-02-01 18:19:06 +01:00
Erik Olof Gunnar Andersson
148d42b1c8
Update angular to 18 (#678)
* Update angular to 18

* Bump to Angular 18.2.13

* Fix security warnings
2025-02-01 18:17:10 +01:00
Erik Olof Gunnar Andersson
f40972ced2
Reduce invalid job found log from error to warning (#480)
* Reduce invalid job found from error to info

* Standarized on LOGW for Invalid job
2025-01-27 19:25:02 +01:00
adammwest
e7b037df10
use length rather than static 4 for hex2bin func of extranonce2_generate (#660) 2025-01-27 18:46:58 +01:00
Erik Olof Gunnar Andersson
1db16a52e1
Don't allow 0.0.0.0 (#665) 2025-01-27 18:43:51 +01:00
Erik Olof Gunnar Andersson
c8671cf69c
Enable Unit Test CI (#634)
* Enable Unit Test CI

* Remove non-functional entrypoint

* symlink CMakeLists.txt
2025-01-27 18:25:38 +01:00
WantClue
7e2d690c64
Pool rework menu (#676)
* feat: pool component

* fix: style Pool Configuration

* fix: add restart logic to pool settings
2025-01-27 18:23:32 +01:00
WantClue
aa540434be
Menu rework, adding menu Design (#675)
* feat: add new Design menu

* fix: remove theme from settings

* feat: add orange

* fix: remove old theme-config

* fix: add proper spacing

* fix: labeling
2025-01-26 21:26:19 +01:00
tdb3
e1a94fe7a7
refactor: make recovery page an embedded file (#649)
Makes the recovery page an embedded file rather
than a C header. This increases readability and
also serves as an example for Issue #308.
2025-01-26 20:03:25 +01:00
mrv777
e471d43e2d
fix: Show IP of bitaxe you are restarting on swarm (#646)
* fix: Show IP of bitaxe you are restarting on swarm

* fix: show edit uri if provided on toasts
2025-01-26 19:58:18 +01:00
mrv777
06867c474f
fix: Color swarm ips by model or count (#647)
* fix: Color swarm ips by model or count

* fix: Add legend at bottom of table
2025-01-26 19:55:55 +01:00
mrv777
8d8a01a2e4
fix: add mock data and cache to theme service (#654)
* fix: add mock data and cache to theme service

* chore: cleanup
2025-01-26 19:54:30 +01:00
terratec
0497b1104a
Keep old pool config synchronized until reboot (#543) 2025-01-26 16:50:22 +01:00
Erik Olof Gunnar Andersson
e77083507d
Is SPIRAM Available? (#626) 2025-01-21 21:14:32 +01:00
118 changed files with 6127 additions and 3419 deletions

28
.github/workflows/unittest.yml vendored Normal file
View File

@ -0,0 +1,28 @@
name: Unit Test
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
with:
submodules: 'recursive'
- name: esp-idf build
uses: espressif/esp-idf-ci-action@v1
with:
esp_idf_version: v5.4
target: esp32s3
command: GITHUB_ACTIONS="true" idf.py build
path: 'test-ci'
- name: Run tests and show result
uses: bitaxeorg/esp32-qemu-test-action@main
with:
path: 'test-ci'
- name: Inspect log
run: cat report.xml
- name: Publish Unit Test Results
uses: EnricoMi/publish-unit-test-result-action@v1
if: always()
with:
files: report.xml

View File

@ -2,7 +2,7 @@
We take security bugs in esp-miner seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/skot/esp-miner/security/advisories/new) tab.
To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/bitaxeorg/ESP-Miner/security/advisories/new) tab.
A esp-miner maintainer will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.

View File

@ -7,6 +7,8 @@ SRCS
"serial.c"
"crc.c"
"common.c"
"asic.c"
"frequency_transition_bmXX.c"
INCLUDE_DIRS
"include"

263
components/asic/asic.c Normal file
View File

@ -0,0 +1,263 @@
#include <string.h>
#include <esp_log.h>
#include "bm1397.h"
#include "bm1366.h"
#include "bm1368.h"
#include "bm1370.h"
#include "asic.h"
static const double NONCE_SPACE = 4294967296.0; // 2^32
static const char *TAG = "asic";
// .init_fn = BM1366_init,
uint8_t ASIC_init(GlobalState * GLOBAL_STATE) {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
return BM1397_init(GLOBAL_STATE->POWER_MANAGEMENT_MODULE.frequency_value, BITAXE_MAX_ASIC_COUNT);
case DEVICE_ULTRA:
return BM1366_init(GLOBAL_STATE->POWER_MANAGEMENT_MODULE.frequency_value, BITAXE_ULTRA_ASIC_COUNT);
case DEVICE_SUPRA:
return BM1368_init(GLOBAL_STATE->POWER_MANAGEMENT_MODULE.frequency_value, BITAXE_SUPRA_ASIC_COUNT);
case DEVICE_GAMMA:
return BM1370_init(GLOBAL_STATE->POWER_MANAGEMENT_MODULE.frequency_value, BITAXE_GAMMA_ASIC_COUNT);
case DEVICE_GAMMATURBO:
return BM1370_init(GLOBAL_STATE->POWER_MANAGEMENT_MODULE.frequency_value, BITAXE_GAMMATURBO_ASIC_COUNT);
default:
}
return ESP_OK;
}
uint8_t ASIC_get_asic_count(GlobalState * GLOBAL_STATE) {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
return BITAXE_MAX_ASIC_COUNT;
case DEVICE_ULTRA:
return BITAXE_ULTRA_ASIC_COUNT;
case DEVICE_SUPRA:
return BITAXE_SUPRA_ASIC_COUNT;
case DEVICE_GAMMA:
return BITAXE_GAMMA_ASIC_COUNT;
case DEVICE_GAMMATURBO:
return BITAXE_GAMMATURBO_ASIC_COUNT;
default:
}
return 0;
}
uint16_t ASIC_get_small_core_count(GlobalState * GLOBAL_STATE) {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
return BM1397_SMALL_CORE_COUNT;
case DEVICE_ULTRA:
return BM1366_SMALL_CORE_COUNT;
case DEVICE_SUPRA:
return BM1368_SMALL_CORE_COUNT;
case DEVICE_GAMMA:
return BM1370_SMALL_CORE_COUNT;
case DEVICE_GAMMATURBO:
return BM1370_SMALL_CORE_COUNT;
default:
}
return 0;
}
// .receive_result_fn = BM1366_process_work,
task_result * ASIC_process_work(GlobalState * GLOBAL_STATE) {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
return BM1397_process_work(GLOBAL_STATE);
case DEVICE_ULTRA:
return BM1366_process_work(GLOBAL_STATE);
case DEVICE_SUPRA:
return BM1368_process_work(GLOBAL_STATE);
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
return BM1370_process_work(GLOBAL_STATE);
default:
}
return NULL;
}
// .set_max_baud_fn = BM1366_set_max_baud,
int ASIC_set_max_baud(GlobalState * GLOBAL_STATE) {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
return BM1397_set_max_baud();
case DEVICE_ULTRA:
return BM1366_set_max_baud();
case DEVICE_SUPRA:
return BM1368_set_max_baud();
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
return BM1370_set_max_baud();
default:
return 0;
}
}
// .set_difficulty_mask_fn = BM1366_set_job_difficulty_mask,
void ASIC_set_job_difficulty_mask(GlobalState * GLOBAL_STATE, uint8_t mask) {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
BM1397_set_job_difficulty_mask(mask);
break;
case DEVICE_ULTRA:
BM1366_set_job_difficulty_mask(mask);
break;
case DEVICE_SUPRA:
BM1368_set_job_difficulty_mask(mask);
break;
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
BM1370_set_job_difficulty_mask(mask);
break;
default:
}
}
// .send_work_fn = BM1366_send_work,
void ASIC_send_work(GlobalState * GLOBAL_STATE, void * next_job) {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
BM1397_send_work(GLOBAL_STATE, next_job);
break;
case DEVICE_ULTRA:
BM1366_send_work(GLOBAL_STATE, next_job);
break;
case DEVICE_SUPRA:
BM1368_send_work(GLOBAL_STATE, next_job);
break;
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
BM1370_send_work(GLOBAL_STATE, next_job);
break;
default:
return;
}
}
// .set_version_mask = BM1366_set_version_mask
void ASIC_set_version_mask(GlobalState * GLOBAL_STATE, uint32_t mask) {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
BM1397_set_version_mask(mask);
break;
case DEVICE_ULTRA:
BM1366_set_version_mask(mask);
break;
case DEVICE_SUPRA:
BM1368_set_version_mask(mask);
break;
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
BM1370_set_version_mask(mask);
break;
default:
return;
}
}
bool ASIC_set_frequency(GlobalState * GLOBAL_STATE, float target_frequency) {
ESP_LOGI(TAG, "Setting ASIC frequency to %.2f MHz", target_frequency);
bool success = false;
switch (GLOBAL_STATE->asic_model) {
case ASIC_BM1366:
success = BM1366_set_frequency(target_frequency);
break;
case ASIC_BM1368:
success = BM1368_set_frequency(target_frequency);
break;
case ASIC_BM1370:
success = BM1370_set_frequency(target_frequency);
break;
case ASIC_BM1397:
// BM1397 doesn't have a set_frequency function yet
ESP_LOGE(TAG, "Frequency transition not implemented for BM1397");
success = false;
break;
default:
ESP_LOGE(TAG, "Unknown ASIC model, cannot set frequency");
success = false;
break;
}
if (success) {
ESP_LOGI(TAG, "Successfully transitioned to new ASIC frequency: %.2f MHz", target_frequency);
} else {
ESP_LOGE(TAG, "Failed to transition to new ASIC frequency: %.2f MHz", target_frequency);
}
return success;
}
esp_err_t ASIC_set_device_model(GlobalState * GLOBAL_STATE) {
if (GLOBAL_STATE->device_model_str == NULL) {
ESP_LOGE(TAG, "No device model string found");
return ESP_FAIL;
}
if (strcmp(GLOBAL_STATE->device_model_str, "max") == 0) {
GLOBAL_STATE->asic_model = ASIC_BM1397;
GLOBAL_STATE->valid_model = true;
GLOBAL_STATE->asic_job_frequency_ms = (NONCE_SPACE / (double) (GLOBAL_STATE->POWER_MANAGEMENT_MODULE.frequency_value * BM1397_SMALL_CORE_COUNT * 1000)) / (double) ASIC_get_asic_count(GLOBAL_STATE); // no version-rolling so same Nonce Space is splitted between Small Cores
GLOBAL_STATE->ASIC_difficulty = BM1397_ASIC_DIFFICULTY;
ESP_LOGI(TAG, "DEVICE: bitaxeMax");
ESP_LOGI(TAG, "ASIC: %dx BM1397 (%" PRIu64 " cores)", BITAXE_MAX_ASIC_COUNT, BM1397_CORE_COUNT);
GLOBAL_STATE->device_model = DEVICE_MAX;
} else if (strcmp(GLOBAL_STATE->device_model_str, "ultra") == 0) {
GLOBAL_STATE->asic_model = ASIC_BM1366;
GLOBAL_STATE->valid_model = true;
//GLOBAL_STATE.asic_job_frequency_ms = (NONCE_SPACE / (double) (GLOBAL_STATE.POWER_MANAGEMENT_MODULE.frequency_value * BM1366_CORE_COUNT * 1000)) / (double) BITAXE_ULTRA_ASIC_COUNT; // version-rolling so Small Cores have different Nonce Space
GLOBAL_STATE->asic_job_frequency_ms = 2000; //ms
GLOBAL_STATE->ASIC_difficulty = BM1366_ASIC_DIFFICULTY;
ESP_LOGI(TAG, "DEVICE: bitaxeUltra");
ESP_LOGI(TAG, "ASIC: %dx BM1366 (%" PRIu64 " cores)", BITAXE_ULTRA_ASIC_COUNT, BM1366_CORE_COUNT);
GLOBAL_STATE->device_model = DEVICE_ULTRA;
} else if (strcmp(GLOBAL_STATE->device_model_str, "supra") == 0) {
GLOBAL_STATE->asic_model = ASIC_BM1368;
GLOBAL_STATE->valid_model = true;
//GLOBAL_STATE.asic_job_frequency_ms = (NONCE_SPACE / (double) (GLOBAL_STATE.POWER_MANAGEMENT_MODULE.frequency_value * BM1368_CORE_COUNT * 1000)) / (double) BITAXE_SUPRA_ASIC_COUNT; // version-rolling so Small Cores have different Nonce Space
GLOBAL_STATE->asic_job_frequency_ms = 500; //ms
GLOBAL_STATE->ASIC_difficulty = BM1368_ASIC_DIFFICULTY;
ESP_LOGI(TAG, "DEVICE: bitaxeSupra");
ESP_LOGI(TAG, "ASIC: %dx BM1368 (%" PRIu64 " cores)", BITAXE_SUPRA_ASIC_COUNT, BM1368_CORE_COUNT);
GLOBAL_STATE->device_model = DEVICE_SUPRA;
} else if (strcmp(GLOBAL_STATE->device_model_str, "gamma") == 0) {
GLOBAL_STATE->asic_model = ASIC_BM1370;
GLOBAL_STATE->valid_model = true;
//GLOBAL_STATE.asic_job_frequency_ms = (NONCE_SPACE / (double) (GLOBAL_STATE.POWER_MANAGEMENT_MODULE.frequency_value * BM1370_CORE_COUNT * 1000)) / (double) BITAXE_GAMMA_ASIC_COUNT; // version-rolling so Small Cores have different Nonce Space
GLOBAL_STATE->asic_job_frequency_ms = 500; //ms
GLOBAL_STATE->ASIC_difficulty = BM1370_ASIC_DIFFICULTY;
ESP_LOGI(TAG, "DEVICE: bitaxeGamma");
ESP_LOGI(TAG, "ASIC: %dx BM1370 (%" PRIu64 " cores)", BITAXE_GAMMA_ASIC_COUNT, BM1370_CORE_COUNT);
GLOBAL_STATE->device_model = DEVICE_GAMMA;
} else if (strcmp(GLOBAL_STATE->device_model_str, "gammaturbo") == 0) {
GLOBAL_STATE->asic_model = ASIC_BM1370;
GLOBAL_STATE->valid_model = true;
//GLOBAL_STATE.asic_job_frequency_ms = (NONCE_SPACE / (double) (GLOBAL_STATE.POWER_MANAGEMENT_MODULE.frequency_value * BM1370_CORE_COUNT * 1000)) / (double) BITAXE_GAMMATURBO_ASIC_COUNT; // version-rolling so Small Cores have different Nonce Space
GLOBAL_STATE->asic_job_frequency_ms = 500; //ms
GLOBAL_STATE->ASIC_difficulty = BM1370_ASIC_DIFFICULTY;
ESP_LOGI(TAG, "DEVICE: bitaxeGammaTurbo");
ESP_LOGI(TAG, "ASIC: %dx BM1370 (%" PRIu64 " cores)", BITAXE_GAMMATURBO_ASIC_COUNT, BM1370_CORE_COUNT);
GLOBAL_STATE->device_model = DEVICE_GAMMATURBO;
} else {
ESP_LOGE(TAG, "Invalid DEVICE model");
// maybe should return here to now execute anything with a faulty device parameter !
// this stops crashes/reboots and allows dev testing without an asic
GLOBAL_STATE->device_model = DEVICE_UNKNOWN;
GLOBAL_STATE->valid_model = false;
return ESP_FAIL;
}
return ESP_OK;
}

View File

@ -8,14 +8,23 @@
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "frequency_transition_bmXX.h"
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#define BM1366_CHIP_ID 0x1366
#define BM1366_CHIP_ID_RESPONSE_LENGTH 11
#ifdef CONFIG_GPIO_ASIC_RESET
#define GPIO_ASIC_RESET CONFIG_GPIO_ASIC_RESET
#else
#define GPIO_ASIC_RESET 1
#endif
#define TYPE_JOB 0x20
#define TYPE_CMD 0x40
@ -45,23 +54,20 @@
#define TICKET_MASK 0x14
#define MISC_CONTROL 0x18
#define BM1366_TIMEOUT_MS 10000
#define BM1366_TIMEOUT_THRESHOLD 2
typedef struct __attribute__((__packed__))
{
uint8_t preamble[2];
uint16_t preamble;
uint32_t nonce;
uint8_t midstate_num;
uint8_t job_id;
uint16_t version;
uint8_t crc;
} asic_result;
} bm1366_asic_result_t;
static float current_frequency = 56.25;
static const char * TAG = "bm1366Module";
static uint8_t asic_response_buffer[SERIAL_BUF_SIZE];
static task_result result;
/// @brief
@ -197,38 +203,18 @@ void BM1366_send_hash_frequency(float target_freq)
}
static void do_frequency_ramp_up(float target_frequency) {
float step = 6.25;
float current = current_frequency;
float target = target_frequency;
ESP_LOGI(TAG, "Ramping up frequency from %.2f MHz to %.2f MHz", current_frequency, target_frequency);
do_frequency_transition(target_frequency, BM1366_send_hash_frequency, 1366);
}
float direction = (target > current) ? step : -step;
if (fmod(current, step) != 0) {
float next_dividable;
if (direction > 0) {
next_dividable = ceil(current / step) * step;
} else {
next_dividable = floor(current / step) * step;
}
current = next_dividable;
BM1366_send_hash_frequency(current);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
while ((direction > 0 && current < target) || (direction < 0 && current > target)) {
float next_step = fmin(fabs(direction), fabs(target - current));
current += direction > 0 ? next_step : -next_step;
BM1366_send_hash_frequency(current);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
BM1366_send_hash_frequency(target);
return;
// Add a public function for external use
bool BM1366_set_frequency(float target_freq) {
return do_frequency_transition(target_freq, BM1366_send_hash_frequency, 1366);
}
static uint8_t _send_init(uint64_t frequency, uint16_t asic_count)
{
// set version mask
for (int i = 0; i < 3; i++) {
BM1366_set_version_mask(STRATUM_DEFAULT_VERSION_MASK);
@ -238,15 +224,11 @@ static uint8_t _send_init(uint64_t frequency, uint16_t asic_count)
unsigned char init3[7] = {0x55, 0xAA, 0x52, 0x05, 0x00, 0x00, 0x0A};
_send_simple(init3, 7);
int chip_counter = 0;
while (true) {
if(SERIAL_rx(asic_response_buffer, 11, 1000) > 0) {
chip_counter++;
} else {
break;
}
int chip_counter = count_asic_chips(asic_count, BM1366_CHIP_ID, BM1366_CHIP_ID_RESPONSE_LENGTH);
if (chip_counter == 0) {
return 0;
}
ESP_LOGI(TAG, "%i chip(s) detected on the chain, expected %i", chip_counter, asic_count);
unsigned char init4[11] = {0x55, 0xAA, 0x51, 0x09, 0x00, 0xA8, 0x00, 0x07, 0x00, 0x00, 0x03};
_send_simple(init4, 11);
@ -301,7 +283,7 @@ static uint8_t _send_init(uint64_t frequency, uint16_t asic_count)
do_frequency_ramp_up((float)frequency);
//register 10 is still a bit of a mystery. discussion: https://github.com/skot/ESP-Miner/pull/167
//register 10 is still a bit of a mystery. discussion: https://github.com/bitaxeorg/ESP-Miner/pull/167
// unsigned char set_10_hash_counting[6] = {0x00, 0x10, 0x00, 0x00, 0x11, 0x5A}; //S19k Pro Default
// unsigned char set_10_hash_counting[6] = {0x00, 0x10, 0x00, 0x00, 0x14, 0x46}; //S19XP-Luxos Default
@ -342,8 +324,6 @@ uint8_t BM1366_init(uint64_t frequency, uint16_t asic_count)
{
ESP_LOGI(TAG, "Initializing BM1366");
memset(asic_response_buffer, 0, SERIAL_BUF_SIZE);
esp_rom_gpio_pad_select_gpio(GPIO_ASIC_RESET);
gpio_set_direction(GPIO_ASIC_RESET, GPIO_MODE_OUTPUT);
@ -437,77 +417,31 @@ void BM1366_send_work(void * pvParameters, bm_job * next_bm_job)
_send_BM1366((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), (uint8_t *)&job, sizeof(BM1366_job), BM1366_DEBUG_WORK);
}
asic_result * BM1366_receive_work(void)
task_result * BM1366_process_work(void * pvParameters)
{
// wait for a response
int received = SERIAL_rx(asic_response_buffer, 11, BM1366_TIMEOUT_MS);
bm1366_asic_result_t asic_result = {0};
bool uart_err = received < 0;
bool uart_timeout = received == 0;
uint8_t asic_timeout_counter = 0;
// handle response
if (uart_err) {
ESP_LOGI(TAG, "UART Error in serial RX");
return NULL;
} else if (uart_timeout) {
if (asic_timeout_counter >= BM1366_TIMEOUT_THRESHOLD) {
ESP_LOGE(TAG, "ASIC not sending data");
asic_timeout_counter = 0;
}
asic_timeout_counter++;
if (receive_work((uint8_t *)&asic_result, sizeof(asic_result)) == ESP_FAIL) {
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);
SERIAL_clear_buffer();
return NULL;
}
return (asic_result *) asic_response_buffer;
}
static uint16_t reverse_uint16(uint16_t num)
{
return (num >> 8) | (num << 8);
}
static uint32_t reverse_uint32(uint32_t val)
{
return ((val >> 24) & 0xff) | // Move byte 3 to byte 0
((val << 8) & 0xff0000) | // Move byte 1 to byte 2
((val >> 8) & 0xff00) | // Move byte 2 to byte 1
((val << 24) & 0xff000000); // Move byte 0 to byte 3
}
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 & 0xf8;
uint8_t core_id = (uint8_t)((reverse_uint32(asic_result->nonce) >> 25) & 0x7f); // BM1366 has 112 cores, so it should be coded on 7 bits
uint8_t small_core_id = asic_result->job_id & 0x07; // BM1366 has 8 small cores, so it should be coded on 3 bits
uint32_t version_bits = (reverse_uint16(asic_result->version) << 13); // shift the 16 bit value left 13
uint8_t job_id = asic_result.job_id & 0xf8;
uint8_t core_id = (uint8_t)((ntohl(asic_result.nonce) >> 25) & 0x7f); // BM1366 has 112 cores, so it should be coded on 7 bits
uint8_t small_core_id = asic_result.job_id & 0x07; // BM1366 has 8 small cores, so it should be coded on 3 bits
uint32_t version_bits = (ntohs(asic_result.version) << 13); // shift the 16 bit value left 13
ESP_LOGI(TAG, "Job ID: %02X, Core: %d/%d, Ver: %08" PRIX32, job_id, core_id, small_core_id, version_bits);
GlobalState * GLOBAL_STATE = (GlobalState *) pvParameters;
if (GLOBAL_STATE->valid_jobs[job_id] == 0) {
ESP_LOGE(TAG, "Invalid job found, 0x%02X", job_id);
ESP_LOGW(TAG, "Invalid job found, 0x%02X", job_id);
return NULL;
}
uint32_t rolled_version = GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->version | version_bits;
result.job_id = job_id;
result.nonce = asic_result->nonce;
result.nonce = asic_result.nonce;
result.rolled_version = rolled_version;
return &result;

View File

@ -8,14 +8,23 @@
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "frequency_transition_bmXX.h"
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#define BM1368_CHIP_ID 0x1368
#define BM1368_CHIP_ID_RESPONSE_LENGTH 11
#ifdef CONFIG_GPIO_ASIC_RESET
#define GPIO_ASIC_RESET CONFIG_GPIO_ASIC_RESET
#else
#define GPIO_ASIC_RESET 1
#endif
#define TYPE_JOB 0x20
#define TYPE_CMD 0x40
@ -45,21 +54,18 @@
#define TICKET_MASK 0x14
#define MISC_CONTROL 0x18
#define BM1368_TIMEOUT_MS 10000
#define BM1368_TIMEOUT_THRESHOLD 2
typedef struct __attribute__((__packed__))
{
uint8_t preamble[2];
uint16_t preamble;
uint32_t nonce;
uint8_t midstate_num;
uint8_t job_id;
uint16_t version;
uint8_t crc;
} asic_result;
} bm1368_asic_result_t;
static const char * TAG = "bm1368Module";
static uint8_t asic_response_buffer[CHUNK_SIZE];
static task_result result;
static float current_frequency = 56.25;
@ -128,7 +134,7 @@ static void _reset(void)
vTaskDelay(100 / portTICK_PERIOD_MS);
}
bool BM1368_send_hash_frequency(float target_freq) {
void BM1368_send_hash_frequency(float target_freq) {
float max_diff = 0.001;
uint8_t freqbuf[6] = {0x00, 0x08, 0x40, 0xA0, 0x02, 0x41};
uint8_t postdiv_min = 255;
@ -164,7 +170,7 @@ bool BM1368_send_hash_frequency(float target_freq) {
if (!found) {
ESP_LOGE(TAG, "Didn't find PLL settings for target frequency %.2f", target_freq);
return false;
return;
}
freqbuf[2] = (best_fbdiv * 25 / best_refdiv >= 2400) ? 0x50 : 0x40;
@ -176,73 +182,21 @@ bool BM1368_send_hash_frequency(float target_freq) {
ESP_LOGI(TAG, "Setting Frequency to %.2fMHz (%.2f)", target_freq, best_freq);
current_frequency = target_freq;
return true;
}
bool do_frequency_transition(float target_frequency) {
float step = 6.25;
float current = current_frequency;
float target = target_frequency;
float direction = (target > current) ? step : -step;
if (fmod(current, step) != 0) {
float next_dividable;
if (direction > 0) {
next_dividable = ceil(current / step) * step;
} else {
next_dividable = floor(current / step) * step;
}
current = next_dividable;
BM1368_send_hash_frequency(current);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
while ((direction > 0 && current < target) || (direction < 0 && current > target)) {
float next_step = fmin(fabs(direction), fabs(target - current));
current += direction > 0 ? next_step : -next_step;
BM1368_send_hash_frequency(current);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
BM1368_send_hash_frequency(target);
return true;
}
bool BM1368_set_frequency(float target_freq) {
return do_frequency_transition(target_freq);
return do_frequency_transition(target_freq, BM1368_send_hash_frequency, 1368);
}
static int count_asic_chips(void) {
_send_BM1368(TYPE_CMD | GROUP_ALL | CMD_READ, (uint8_t[]){0x00, 0x00}, 2, false);
int chip_counter = 0;
while (true) {
if (SERIAL_rx(asic_response_buffer, 11, 5000) <= 0) {
break;
}
if (memcmp(asic_response_buffer, "\xaa\x55\x13\x68\x00\x00", 6) == 0) {
chip_counter++;
}
}
_send_chain_inactive();
return chip_counter;
}
static void do_frequency_ramp_up(float target_frequency) {
ESP_LOGI(TAG, "Ramping up frequency from %.2f MHz to %.2f MHz", current_frequency, target_frequency);
do_frequency_transition(target_frequency);
do_frequency_transition(target_frequency, BM1368_send_hash_frequency, 1368);
}
uint8_t BM1368_init(uint64_t frequency, uint16_t asic_count)
{
ESP_LOGI(TAG, "Initializing BM1368");
memset(asic_response_buffer, 0, CHUNK_SIZE);
esp_rom_gpio_pad_select_gpio(GPIO_ASIC_RESET);
gpio_set_direction(GPIO_ASIC_RESET, GPIO_MODE_OUTPUT);
@ -253,13 +207,16 @@ uint8_t BM1368_init(uint64_t frequency, uint16_t asic_count)
BM1368_set_version_mask(STRATUM_DEFAULT_VERSION_MASK);
}
int chip_counter = count_asic_chips();
_send_BM1368(TYPE_CMD | GROUP_ALL | CMD_READ, (uint8_t[]){0x00, 0x00}, 2, false);
if (chip_counter != asic_count) {
ESP_LOGE(TAG, "Chip count mismatch. Expected: %d, Actual: %d", asic_count, chip_counter);
int chip_counter = count_asic_chips(asic_count, BM1368_CHIP_ID, BM1368_CHIP_ID_RESPONSE_LENGTH);
if (chip_counter == 0) {
return 0;
}
_send_chain_inactive();
uint8_t init_cmds[][6] = {
{0x00, 0xA8, 0x00, 0x07, 0x00, 0x00},
{0x00, 0x18, 0xFF, 0x0F, 0xC1, 0x00},
@ -301,7 +258,6 @@ uint8_t BM1368_init(uint64_t frequency, uint16_t asic_count)
_send_BM1368(TYPE_CMD | GROUP_ALL | CMD_WRITE, (uint8_t[]){0x00, 0x10, 0x00, 0x00, 0x15, 0xa4}, 6, false);
BM1368_set_version_mask(STRATUM_DEFAULT_VERSION_MASK);
ESP_LOGI(TAG, "%i chip(s) detected on the chain, expected %i", chip_counter, asic_count);
return chip_counter;
}
@ -371,76 +327,31 @@ void BM1368_send_work(void * pvParameters, bm_job * next_bm_job)
_send_BM1368((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), (uint8_t *)&job, sizeof(BM1368_job), BM1368_DEBUG_WORK);
}
asic_result * BM1368_receive_work(void)
task_result * BM1368_process_work(void * pvParameters)
{
// wait for a response
int received = SERIAL_rx(asic_response_buffer, 11, BM1368_TIMEOUT_MS);
bm1368_asic_result_t asic_result = {0};
bool uart_err = received < 0;
bool uart_timeout = received == 0;
uint8_t asic_timeout_counter = 0;
// handle response
if (uart_err) {
ESP_LOGI(TAG, "UART Error in serial RX");
return NULL;
} else if (uart_timeout) {
if (asic_timeout_counter >= BM1368_TIMEOUT_THRESHOLD) {
ESP_LOGE(TAG, "ASIC not sending data");
asic_timeout_counter = 0;
}
asic_timeout_counter++;
if (receive_work((uint8_t *)&asic_result, sizeof(asic_result)) == ESP_FAIL) {
return NULL;
}
if (received != 11 || asic_response_buffer[0] != 0xAA || asic_response_buffer[1] != 0x55) {
ESP_LOGE(TAG, "Serial RX invalid %i", received);
ESP_LOG_BUFFER_HEX(TAG, asic_response_buffer, received);
SERIAL_clear_buffer();
return NULL;
}
return (asic_result *) asic_response_buffer;
}
static uint16_t reverse_uint16(uint16_t num)
{
return (num >> 8) | (num << 8);
}
static uint32_t reverse_uint32(uint32_t val)
{
return ((val >> 24) & 0xff) |
((val << 8) & 0xff0000) |
((val >> 8) & 0xff00) |
((val << 24) & 0xff000000);
}
task_result * BM1368_proccess_work(void * pvParameters)
{
asic_result * asic_result = BM1368_receive_work();
if (asic_result == NULL) {
return NULL;
}
uint8_t job_id = (asic_result->job_id & 0xf0) >> 1;
uint8_t core_id = (uint8_t)((reverse_uint32(asic_result->nonce) >> 25) & 0x7f);
uint8_t small_core_id = asic_result->job_id & 0x0f;
uint32_t version_bits = (reverse_uint16(asic_result->version) << 13);
uint8_t job_id = (asic_result.job_id & 0xf0) >> 1;
uint8_t core_id = (uint8_t)((ntohl(asic_result.nonce) >> 25) & 0x7f);
uint8_t small_core_id = asic_result.job_id & 0x0f;
uint32_t version_bits = (ntohs(asic_result.version) << 13);
ESP_LOGI(TAG, "Job ID: %02X, Core: %d/%d, Ver: %08" PRIX32, job_id, core_id, small_core_id, version_bits);
GlobalState * GLOBAL_STATE = (GlobalState *) pvParameters;
if (GLOBAL_STATE->valid_jobs[job_id] == 0) {
ESP_LOGE(TAG, "Invalid job found, 0x%02X", job_id);
ESP_LOGW(TAG, "Invalid job found, 0x%02X", job_id);
return NULL;
}
uint32_t rolled_version = GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->version | version_bits;
result.job_id = job_id;
result.nonce = asic_result->nonce;
result.nonce = asic_result.nonce;
result.rolled_version = rolled_version;
return &result;

View File

@ -8,14 +8,23 @@
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "frequency_transition_bmXX.h"
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#define BM1370_CHIP_ID 0x1370
#define BM1370_CHIP_ID_RESPONSE_LENGTH 11
#ifdef CONFIG_GPIO_ASIC_RESET
#define GPIO_ASIC_RESET CONFIG_GPIO_ASIC_RESET
#else
#define GPIO_ASIC_RESET 1
#endif
#define TYPE_JOB 0x20
#define TYPE_CMD 0x40
@ -45,23 +54,18 @@
#define TICKET_MASK 0x14
#define MISC_CONTROL 0x18
#define BM1370_TIMEOUT_MS 10000
#define BM1370_TIMEOUT_THRESHOLD 2
typedef struct __attribute__((__packed__))
{
uint8_t preamble[2];
uint16_t preamble;
uint32_t nonce;
uint8_t midstate_num;
uint8_t job_id;
uint16_t version;
uint8_t crc;
} asic_result;
} bm1370_asic_result_t;
static const char * TAG = "bm1370Module";
static uint8_t asic_response_buffer[SERIAL_BUF_SIZE];
static task_result result;
/// @brief
@ -141,76 +145,76 @@ void BM1370_set_version_mask(uint32_t version_mask)
_send_BM1370(TYPE_CMD | GROUP_ALL | CMD_WRITE, version_cmd, 6, BM1370_SERIALTX_DEBUG);
}
void BM1370_send_hash_frequency(int id, float target_freq, float max_diff) {
uint8_t freqbuf[6] = {0x00, 0x08, 0x40, 0xA0, 0x02, 0x41};
uint8_t postdiv_min = 255;
uint8_t postdiv2_min = 255;
float best_freq = 0;
uint8_t best_refdiv = 0, best_fbdiv = 0, best_postdiv1 = 0, best_postdiv2 = 0;
void BM1370_send_hash_frequency(float target_freq) {
// default 200Mhz if it fails
unsigned char freqbuf[6] = {0x00, 0x08, 0x40, 0xA0, 0x02, 0x41}; // freqbuf - pll0_parameter
float newf = 200.0;
for (uint8_t refdiv = 2; refdiv > 0; refdiv--) {
for (uint8_t postdiv1 = 7; postdiv1 > 0; postdiv1--) {
for (uint8_t postdiv2 = 7; postdiv2 > 0; postdiv2--) {
uint16_t fb_divider = round(target_freq / 25.0 * (refdiv * postdiv2 * postdiv1));
float newf = 25.0 * fb_divider / (refdiv * postdiv2 * postdiv1);
uint8_t fb_divider = 0;
uint8_t post_divider1 = 0, post_divider2 = 0;
uint8_t ref_divider = 0;
float min_difference = 10;
float max_diff = 1.0;
if (fb_divider >= 0xa0 && fb_divider <= 0xef &&
fabs(target_freq - newf) < max_diff &&
postdiv1 >= postdiv2 &&
postdiv1 * postdiv2 < postdiv_min &&
postdiv2 <= postdiv2_min) {
// refdiver is 2 or 1
// postdivider 2 is 1 to 7
// postdivider 1 is 1 to 7 and greater than or equal to postdivider 2
// fbdiv is 0xa0 to 0xef
for (uint8_t refdiv_loop = 2; refdiv_loop > 0 && fb_divider == 0; refdiv_loop--) {
for (uint8_t postdiv1_loop = 7; postdiv1_loop > 0 && fb_divider == 0; postdiv1_loop--) {
for (uint8_t postdiv2_loop = 7; postdiv2_loop > 0 && fb_divider == 0; postdiv2_loop--) {
if (postdiv1_loop >= postdiv2_loop) {
int temp_fb_divider = round(((float) (postdiv1_loop * postdiv2_loop * target_freq * refdiv_loop) / 25.0));
postdiv2_min = postdiv2;
postdiv_min = postdiv1 * postdiv2;
best_freq = newf;
best_refdiv = refdiv;
best_fbdiv = fb_divider;
best_postdiv1 = postdiv1;
best_postdiv2 = postdiv2;
if (temp_fb_divider >= 0xa0 && temp_fb_divider <= 0xef) {
float temp_freq = 25.0 * (float) temp_fb_divider / (float) (refdiv_loop * postdiv2_loop * postdiv1_loop);
float freq_diff = fabs(target_freq - temp_freq);
if (freq_diff < min_difference && freq_diff < max_diff) {
fb_divider = temp_fb_divider;
post_divider1 = postdiv1_loop;
post_divider2 = postdiv2_loop;
ref_divider = refdiv_loop;
min_difference = freq_diff;
newf = temp_freq;
}
}
}
}
}
}
if (best_fbdiv == 0) {
if (fb_divider == 0) {
ESP_LOGE(TAG, "Failed to find PLL settings for target frequency %.2f", target_freq);
return;
}
freqbuf[2] = (best_fbdiv * 25 / best_refdiv >= 2400) ? 0x50 : 0x40;
freqbuf[3] = best_fbdiv;
freqbuf[4] = best_refdiv;
freqbuf[5] = (((best_postdiv1 - 1) & 0xf) << 4) | ((best_postdiv2 - 1) & 0xf);
freqbuf[3] = fb_divider;
freqbuf[4] = ref_divider;
freqbuf[5] = (((post_divider1 - 1) & 0xf) << 4) + ((post_divider2 - 1) & 0xf);
if (id != -1) {
freqbuf[0] = id * 2;
_send_BM1370(TYPE_CMD | GROUP_SINGLE | CMD_WRITE, freqbuf, 6, BM1370_SERIALTX_DEBUG);
} else {
_send_BM1370(TYPE_CMD | GROUP_ALL | CMD_WRITE, freqbuf, 6, BM1370_SERIALTX_DEBUG);
if (fb_divider * 25 / (float) ref_divider >= 2400) {
freqbuf[2] = 0x50;
}
ESP_LOGI(TAG, "Setting Frequency to %.2fMHz (%.2f)", target_freq, best_freq);
_send_BM1370(TYPE_CMD | GROUP_ALL | CMD_WRITE, freqbuf, 6, BM1370_SERIALTX_DEBUG);
ESP_LOGI(TAG, "Setting Frequency to %.2fMHz (%.2f)", target_freq, newf);
}
static void do_frequency_ramp_up(float target_frequency) {
float current = 56.25;
float step = 6.25;
if (target_frequency == 0) {
ESP_LOGI(TAG, "Skipping frequency ramp");
return;
}
ESP_LOGI(TAG, "Ramping up frequency from %.2f MHz to %.2f MHz with step %.2f MHz", current, target_frequency, step);
ESP_LOGI(TAG, "Ramping up frequency from 56.25 MHz to %.2f MHz", target_frequency);
do_frequency_transition(target_frequency, BM1370_send_hash_frequency, 1370);
}
BM1370_send_hash_frequency(-1, current, 0.001);
while (current < target_frequency) {
float next_step = fminf(step, target_frequency - current);
current += next_step;
BM1370_send_hash_frequency(-1, current, 0.001);
vTaskDelay(pdMS_TO_TICKS(100));
}
// Add a public function for external use
bool BM1370_set_frequency(float target_freq) {
return do_frequency_transition(target_freq, BM1370_send_hash_frequency, 1370);
}
static uint8_t _send_init(uint64_t frequency, uint16_t asic_count)
@ -224,15 +228,11 @@ static uint8_t _send_init(uint64_t frequency, uint16_t asic_count)
unsigned char init3[7] = {0x55, 0xAA, 0x52, 0x05, 0x00, 0x00, 0x0A};
_send_simple(init3, 7);
int chip_counter = 0;
while (true) {
if (SERIAL_rx(asic_response_buffer, 11, 1000) > 0) {
chip_counter++;
} else {
break;
}
int chip_counter = count_asic_chips(asic_count, BM1370_CHIP_ID, BM1370_CHIP_ID_RESPONSE_LENGTH);
if (chip_counter == 0) {
return 0;
}
ESP_LOGI(TAG, "%i chip(s) detected on the chain, expected %i", chip_counter, asic_count);
// set version mask
BM1370_set_version_mask(STRATUM_DEFAULT_VERSION_MASK);
@ -313,7 +313,7 @@ static uint8_t _send_init(uint64_t frequency, uint16_t asic_count)
//ramp up the hash frequency
do_frequency_ramp_up(frequency);
//register 10 is still a bit of a mystery. discussion: https://github.com/skot/ESP-Miner/pull/167
//register 10 is still a bit of a mystery. discussion: https://github.com/bitaxeorg/ESP-Miner/pull/167
// unsigned char set_10_hash_counting[6] = {0x00, 0x10, 0x00, 0x00, 0x11, 0x5A}; //S19k Pro Default
// unsigned char set_10_hash_counting[6] = {0x00, 0x10, 0x00, 0x00, 0x14, 0x46}; //S19XP-Luxos Default
@ -353,8 +353,6 @@ uint8_t BM1370_init(uint64_t frequency, uint16_t asic_count)
{
ESP_LOGI(TAG, "Initializing BM1370");
memset(asic_response_buffer, 0, SERIAL_BUF_SIZE);
esp_rom_gpio_pad_select_gpio(GPIO_ASIC_RESET);
gpio_set_direction(GPIO_ASIC_RESET, GPIO_MODE_OUTPUT);
@ -449,84 +447,38 @@ void BM1370_send_work(void * pvParameters, bm_job * next_bm_job)
_send_BM1370((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), (uint8_t *)&job, sizeof(BM1370_job), BM1370_DEBUG_WORK);
}
asic_result * BM1370_receive_work(void)
task_result * BM1370_process_work(void * pvParameters)
{
// wait for a response
int received = SERIAL_rx(asic_response_buffer, 11, BM1370_TIMEOUT_MS);
bm1370_asic_result_t asic_result = {0};
bool uart_err = received < 0;
bool uart_timeout = received == 0;
uint8_t asic_timeout_counter = 0;
// handle response
if (uart_err) {
ESP_LOGI(TAG, "UART Error in serial RX");
return NULL;
} else if (uart_timeout) {
if (asic_timeout_counter >= BM1370_TIMEOUT_THRESHOLD) {
ESP_LOGE(TAG, "ASIC not sending data");
asic_timeout_counter = 0;
}
asic_timeout_counter++;
if (receive_work((uint8_t *)&asic_result, sizeof(asic_result)) == ESP_FAIL) {
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);
SERIAL_clear_buffer();
return NULL;
}
return (asic_result *) asic_response_buffer;
}
static uint16_t reverse_uint16(uint16_t num)
{
return (num >> 8) | (num << 8);
}
static uint32_t reverse_uint32(uint32_t val)
{
return ((val >> 24) & 0xff) | // Move byte 3 to byte 0
((val << 8) & 0xff0000) | // Move byte 1 to byte 2
((val >> 8) & 0xff00) | // Move byte 2 to byte 1
((val << 24) & 0xff000000); // Move byte 0 to byte 3
}
task_result * BM1370_proccess_work(void * pvParameters)
{
asic_result * asic_result = BM1370_receive_work();
if (asic_result == NULL) {
return NULL;
}
// uint8_t job_id = asic_result->job_id;
// uint8_t job_id = asic_result.job_id;
// uint8_t rx_job_id = ((int8_t)job_id & 0xf0) >> 1;
// ESP_LOGI(TAG, "Job ID: %02X, RX: %02X", job_id, rx_job_id);
// uint8_t job_id = asic_result->job_id & 0xf8;
// ESP_LOGI(TAG, "Job ID: %02X, Core: %01X", job_id, asic_result->job_id & 0x07);
// uint8_t job_id = asic_result.job_id & 0xf8;
// ESP_LOGI(TAG, "Job ID: %02X, Core: %01X", job_id, asic_result.job_id & 0x07);
uint8_t job_id = (asic_result->job_id & 0xf0) >> 1;
uint8_t core_id = (uint8_t)((reverse_uint32(asic_result->nonce) >> 25) & 0x7f); // BM1370 has 80 cores, so it should be coded on 7 bits
uint8_t small_core_id = asic_result->job_id & 0x0f; // BM1370 has 16 small cores, so it should be coded on 4 bits
uint32_t version_bits = (reverse_uint16(asic_result->version) << 13); // shift the 16 bit value left 13
uint8_t job_id = (asic_result.job_id & 0xf0) >> 1;
uint8_t core_id = (uint8_t)((ntohl(asic_result.nonce) >> 25) & 0x7f); // BM1370 has 80 cores, so it should be coded on 7 bits
uint8_t small_core_id = asic_result.job_id & 0x0f; // BM1370 has 16 small cores, so it should be coded on 4 bits
uint32_t version_bits = (ntohs(asic_result.version) << 13); // shift the 16 bit value left 13
ESP_LOGI(TAG, "Job ID: %02X, Core: %d/%d, Ver: %08" PRIX32, job_id, core_id, small_core_id, version_bits);
GlobalState * GLOBAL_STATE = (GlobalState *) pvParameters;
if (GLOBAL_STATE->valid_jobs[job_id] == 0) {
ESP_LOGE(TAG, "Invalid job nonce found, 0x%02X", job_id);
ESP_LOGW(TAG, "Invalid job nonce found, 0x%02X", job_id);
return NULL;
}
uint32_t rolled_version = GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->version | version_bits;
result.job_id = job_id;
result.nonce = asic_result->nonce;
result.nonce = asic_result.nonce;
result.rolled_version = rolled_version;
return &result;

View File

@ -3,6 +3,7 @@
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <arpa/inet.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@ -15,7 +16,14 @@
#include "mining.h"
#include "global_state.h"
#define BM1397_CHIP_ID 0x1397
#define BM1397_CHIP_ID_RESPONSE_LENGTH 9
#ifdef CONFIG_GPIO_ASIC_RESET
#define GPIO_ASIC_RESET CONFIG_GPIO_ASIC_RESET
#else
#define GPIO_ASIC_RESET 1
#endif
#define TYPE_JOB 0x20
#define TYPE_CMD 0x40
@ -45,21 +53,17 @@
#define TICKET_MASK 0x14
#define MISC_CONTROL 0x18
#define BM1397_TIMEOUT_MS 10000
#define BM1397_TIMEOUT_THRESHOLD 2
typedef struct __attribute__((__packed__))
{
uint8_t preamble[2];
uint16_t preamble;
uint32_t nonce;
uint8_t midstate_num;
uint8_t job_id;
uint8_t crc;
} asic_result;
} bm1397_asic_result_t;
static const char *TAG = "bm1397Module";
static uint8_t asic_response_buffer[SERIAL_BUF_SIZE];
static uint32_t prev_nonce = 0;
static task_result result;
@ -137,7 +141,6 @@ void BM1397_set_version_mask(uint32_t version_mask) {
// borrowed from cgminer driver-gekko.c calc_gsf_freq()
void BM1397_send_hash_frequency(float frequency)
{
unsigned char prefreq1[9] = {0x00, 0x70, 0x0F, 0x0F, 0x0F, 0x00}; // prefreq - pll0_divider
// default 200Mhz if it fails
@ -229,15 +232,11 @@ static uint8_t _send_init(uint64_t frequency, uint16_t asic_count)
// send the init command
_send_read_address();
int chip_counter = 0;
while (true) {
if (SERIAL_rx(asic_response_buffer, 11, 1000) > 0) {
chip_counter++;
} else {
break;
}
int chip_counter = count_asic_chips(asic_count, BM1397_CHIP_ID, BM1397_CHIP_ID_RESPONSE_LENGTH);
if (chip_counter == 0) {
return 0;
}
ESP_LOGI(TAG, "%i chip(s) detected on the chain, expected %i", chip_counter, asic_count);
// send serial data
vTaskDelay(SLEEP_TIME / portTICK_PERIOD_MS);
@ -294,8 +293,6 @@ uint8_t BM1397_init(uint64_t frequency, uint16_t asic_count)
{
ESP_LOGI(TAG, "Initializing BM1397");
memset(asic_response_buffer, 0, SERIAL_BUF_SIZE);
esp_rom_gpio_pad_select_gpio(GPIO_ASIC_RESET);
gpio_set_direction(GPIO_ASIC_RESET, GPIO_MODE_OUTPUT);
@ -358,7 +355,6 @@ static uint8_t id = 0;
void BM1397_send_work(void *pvParameters, bm_job *next_bm_job)
{
GlobalState *GLOBAL_STATE = (GlobalState *)pvParameters;
job_packet job;
@ -400,61 +396,24 @@ void BM1397_send_work(void *pvParameters, bm_job *next_bm_job)
_send_BM1397((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), (uint8_t *)&job, sizeof(job_packet), BM1397_DEBUG_WORK);
}
asic_result *BM1397_receive_work(void)
task_result *BM1397_process_work(void *pvParameters)
{
bm1397_asic_result_t asic_result = {0};
// wait for a response
int received = SERIAL_rx(asic_response_buffer, 9, BM1397_TIMEOUT_MS);
bool uart_err = received < 0;
bool uart_timeout = received == 0;
uint8_t asic_timeout_counter = 0;
// handle response
if (uart_err) {
ESP_LOGI(TAG, "UART Error in serial RX");
return NULL;
} else if (uart_timeout) {
if (asic_timeout_counter >= BM1397_TIMEOUT_THRESHOLD) {
ESP_LOGE(TAG, "ASIC not sending data");
asic_timeout_counter = 0;
}
asic_timeout_counter++;
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);
SERIAL_clear_buffer();
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");
if (receive_work((uint8_t *)&asic_result, sizeof(asic_result)) == ESP_FAIL) {
return NULL;
}
uint8_t nonce_found = 0;
uint32_t first_nonce = 0;
uint8_t rx_job_id = asic_result->job_id & 0xfc;
uint8_t rx_midstate_index = asic_result->job_id & 0x03;
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);
ESP_LOGW(TAG, "Invalid job nonce found, id=%d", rx_job_id);
return NULL;
}
@ -469,26 +428,26 @@ task_result *BM1397_proccess_work(void *pvParameters)
// most of the time it behavies however
if (nonce_found == 0)
{
first_nonce = asic_result->nonce;
first_nonce = asic_result.nonce;
nonce_found = 1;
}
else if (asic_result->nonce == first_nonce)
else if (asic_result.nonce == first_nonce)
{
// stop if we've already seen this nonce
return NULL;
}
if (asic_result->nonce == prev_nonce)
if (asic_result.nonce == prev_nonce)
{
return NULL;
}
else
{
prev_nonce = asic_result->nonce;
prev_nonce = asic_result.nonce;
}
result.job_id = rx_job_id;
result.nonce = asic_result->nonce;
result.nonce = asic_result.nonce;
result.rolled_version = rolled_version;
return &result;

View File

@ -1,4 +1,14 @@
#include <string.h>
#include <stdbool.h>
#include "common.h"
#include "serial.h"
#include "esp_log.h"
#include "crc.h"
#define PREAMBLE 0xAA55
static const char * TAG = "common";
unsigned char _reverse_bits(unsigned char num)
{
@ -25,3 +35,94 @@ int _largest_power_of_two(int num)
return 1 << power;
}
int count_asic_chips(uint16_t asic_count, uint16_t chip_id, int chip_id_response_length)
{
uint8_t buffer[11] = {0};
int chip_counter = 0;
while (true) {
int received = SERIAL_rx(buffer, chip_id_response_length, 1000);
if (received == 0) break;
if (received == -1) {
ESP_LOGE(TAG, "Error reading CHIP_ID");
break;
}
if (received != chip_id_response_length) {
ESP_LOGE(TAG, "Invalid CHIP_ID response length: expected %d, got %d", chip_id_response_length, received);
ESP_LOG_BUFFER_HEX(TAG, buffer, received);
break;
}
uint16_t received_preamble = (buffer[0] << 8) | buffer[1];
if (received_preamble != PREAMBLE) {
ESP_LOGW(TAG, "Preamble mismatch: expected 0x%04x, got 0x%04x", PREAMBLE, received_preamble);
ESP_LOG_BUFFER_HEX(TAG, buffer, received);
continue;
}
uint16_t received_chip_id = (buffer[2] << 8) | buffer[3];
if (received_chip_id != chip_id) {
ESP_LOGW(TAG, "CHIP_ID response mismatch: expected 0x%04x, got 0x%04x", chip_id, received_chip_id);
ESP_LOG_BUFFER_HEX(TAG, buffer, received);
continue;
}
if (crc5(buffer + 2, received - 2) != 0) {
ESP_LOGW(TAG, "Checksum failed on CHIP_ID response");
ESP_LOG_BUFFER_HEX(TAG, buffer, received);
continue;
}
ESP_LOGI(TAG, "Chip %d detected: CORE_NUM: 0x%02x ADDR: 0x%02x", chip_counter, buffer[4], buffer[5]);
chip_counter++;
}
if (chip_counter != asic_count) {
ESP_LOGW(TAG, "%i chip(s) detected on the chain, expected %i", chip_counter, asic_count);
}
return chip_counter;
}
esp_err_t receive_work(uint8_t * buffer, int buffer_size)
{
int received = SERIAL_rx(buffer, buffer_size, 10000);
if (received < 0) {
ESP_LOGE(TAG, "UART error in serial RX");
return ESP_FAIL;
}
if (received == 0) {
ESP_LOGD(TAG, "UART timeout in serial RX");
return ESP_FAIL;
}
if (received != buffer_size) {
ESP_LOGE(TAG, "Invalid response length %i", received);
ESP_LOG_BUFFER_HEX(TAG, buffer, received);
SERIAL_clear_buffer();
return ESP_FAIL;
}
uint16_t received_preamble = (buffer[0] << 8) | buffer[1];
if (received_preamble != PREAMBLE) {
ESP_LOGE(TAG, "Preamble mismatch: got 0x%04x, expected 0x%04x", received_preamble, PREAMBLE);
ESP_LOG_BUFFER_HEX(TAG, buffer, received);
SERIAL_clear_buffer();
return ESP_FAIL;
}
if (crc5(buffer + 2, buffer_size - 2) != 0) {
ESP_LOGE(TAG, "Checksum failed on response");
ESP_LOG_BUFFER_HEX(TAG, buffer, received);
SERIAL_clear_buffer();
return ESP_FAIL;
}
return ESP_OK;
}

View File

@ -2,7 +2,7 @@
#include <stdint.h>
#include <string.h>
#include "bm1397.h"
#define CRC5_MASK 0x1F
/* compute crc5 over given number of bytes */
// adapted from https://mightydevices.com/index.php/2018/02/reverse-engineering-antminer-s1/

View File

@ -0,0 +1,56 @@
#include "frequency_transition_bmXX.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <math.h>
const char *FREQUENCY_TRANSITION_TAG = "frequency_transition";
static float current_frequency = 56.25;
bool do_frequency_transition(float target_frequency, set_hash_frequency_fn set_frequency_fn, int asic_type) {
if (set_frequency_fn == NULL) {
ESP_LOGE(FREQUENCY_TRANSITION_TAG, "Invalid function pointer provided");
return false;
}
float step = 6.25;
float current = current_frequency;
float target = target_frequency;
float direction = (target > current) ? step : -step;
// If current frequency is not a multiple of step, adjust to the nearest multiple
if (fmod(current, step) != 0) {
float next_dividable;
if (direction > 0) {
next_dividable = ceil(current / step) * step;
} else {
next_dividable = floor(current / step) * step;
}
current = next_dividable;
// Call the provided hash frequency function
set_frequency_fn(current);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
// Gradually adjust frequency in steps until target is reached
while ((direction > 0 && current < target) || (direction < 0 && current > target)) {
float next_step = fmin(fabs(direction), fabs(target - current));
current += direction > 0 ? next_step : -next_step;
// Call the provided hash frequency function
set_frequency_fn(current);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
// Set the final target frequency
set_frequency_fn(target);
current_frequency = target;
ESP_LOGI(FREQUENCY_TRANSITION_TAG, "Successfully transitioned ASIC type %d to %.2f MHz", asic_type, target);
return true;
}

View File

@ -0,0 +1,25 @@
#ifndef ASIC_H
#define ASIC_H
#include <esp_err.h>
#include "global_state.h"
#include "common.h"
#define BITAXE_MAX_ASIC_COUNT 1
#define BITAXE_ULTRA_ASIC_COUNT 1
#define BITAXE_SUPRA_ASIC_COUNT 1
#define BITAXE_GAMMA_ASIC_COUNT 1
#define BITAXE_GAMMATURBO_ASIC_COUNT 2
uint8_t ASIC_init(GlobalState * GLOBAL_STATE);
uint8_t ASIC_get_asic_count(GlobalState * GLOBAL_STATE);
uint16_t ASIC_get_small_core_count(GlobalState * GLOBAL_STATE);
task_result * ASIC_process_work(GlobalState * GLOBAL_STATE);
int ASIC_set_max_baud(GlobalState * GLOBAL_STATE);
void ASIC_set_job_difficulty_mask(GlobalState * GLOBAL_STATE, uint8_t mask);
void ASIC_send_work(GlobalState * GLOBAL_STATE, void * next_job);
void ASIC_set_version_mask(GlobalState * GLOBAL_STATE, uint32_t mask);
bool ASIC_set_frequency(GlobalState * GLOBAL_STATE, float target_frequency);
esp_err_t ASIC_set_device_model(GlobalState * GLOBAL_STATE);
#endif // ASIC_H

View File

@ -7,7 +7,6 @@
#define ASIC_BM1366_JOB_FREQUENCY_MS 2000
#define CRC5_MASK 0x1F
#define BM1366_ASIC_DIFFICULTY 256
#define BM1366_SERIALTX_DEBUG false
@ -36,14 +35,13 @@ typedef struct __attribute__((__packed__))
} BM1366_job;
uint8_t BM1366_init(uint64_t frequency, uint16_t asic_count);
void BM1366_send_init(void);
void BM1366_send_work(void * GLOBAL_STATE, bm_job * next_bm_job);
void BM1366_set_job_difficulty_mask(int);
void BM1366_set_version_mask(uint32_t version_mask);
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);
bool BM1366_set_frequency(float target_freq);
task_result * BM1366_process_work(void * GLOBAL_STATE);
#endif /* BM1366_H_ */

View File

@ -7,7 +7,6 @@
#define ASIC_BM1368_JOB_FREQUENCY_MS 500
#define CRC5_MASK 0x1F
#define BM1368_ASIC_DIFFICULTY 256
#define BM1368_SERIALTX_DEBUG false
@ -36,15 +35,13 @@ typedef struct __attribute__((__packed__))
} BM1368_job;
uint8_t BM1368_init(uint64_t frequency, uint16_t asic_count);
uint8_t BM1368_send_init(void);
void BM1368_send_work(void * GLOBAL_STATE, bm_job * next_bm_job);
void BM1368_set_job_difficulty_mask(int);
void BM1368_set_version_mask(uint32_t version_mask);
int BM1368_set_max_baud(void);
int BM1368_set_default_baud(void);
bool BM1368_send_hash_frequency(float frequency);
bool do_frequency_transition(float target_frequency);
task_result * BM1368_proccess_work(void * GLOBAL_STATE);
void BM1368_send_hash_frequency(float frequency);
bool BM1368_set_frequency(float target_freq);
task_result * BM1368_process_work(void * GLOBAL_STATE);
#endif /* BM1368_H_ */

View File

@ -7,7 +7,6 @@
#define ASIC_BM1370_JOB_FREQUENCY_MS 500
#define CRC5_MASK 0x1F
#define BM1370_ASIC_DIFFICULTY 256
#define BM1370_SERIALTX_DEBUG true
@ -36,14 +35,13 @@ typedef struct __attribute__((__packed__))
} BM1370_job;
uint8_t BM1370_init(uint64_t frequency, uint16_t asic_count);
uint8_t BM1370_send_init(void);
void BM1370_send_work(void * GLOBAL_STATE, bm_job * next_bm_job);
void BM1370_set_job_difficulty_mask(int);
void BM1370_set_version_mask(uint32_t version_mask);
int BM1370_set_max_baud(void);
int BM1370_set_default_baud(void);
void BM1370_send_hash_frequency(int, float, float);
task_result * BM1370_proccess_work(void * GLOBAL_STATE);
void BM1370_send_hash_frequency(float frequency);
bool BM1370_set_frequency(float target_freq);
task_result * BM1370_process_work(void * GLOBAL_STATE);
#endif /* BM1370_H_ */

View File

@ -7,10 +7,9 @@
#define ASIC_BM1397_JOB_FREQUENCY_MS 20 //not currently used
#define CRC5_MASK 0x1F
#define BM1397_ASIC_DIFFICULTY 256
#define BM1937_SERIALTX_DEBUG false
#define BM1937_SERIALTX_DEBUG true
#define BM1937_SERIALRX_DEBUG false
#define BM1397_DEBUG_WORK false //causes insane amount of debug output
#define BM1397_DEBUG_JOBS false //causes insane amount of debug output
@ -50,13 +49,12 @@ typedef struct __attribute__((__packed__))
} job_packet;
uint8_t BM1397_init(uint64_t frequency, uint16_t asic_count);
void BM1397_send_work(void * GLOBAL_STATE, bm_job * next_bm_job);
void BM1397_set_job_difficulty_mask(int);
void BM1397_set_version_mask(uint32_t version_mask);
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);
task_result * BM1397_process_work(void * GLOBAL_STATE);
#endif /* BM1397_H_ */

View File

@ -2,6 +2,7 @@
#define COMMON_H_
#include <stdint.h>
#include "esp_err.h"
typedef struct __attribute__((__packed__))
{
@ -13,4 +14,7 @@ typedef struct __attribute__((__packed__))
unsigned char _reverse_bits(unsigned char num);
int _largest_power_of_two(int num);
#endif
int count_asic_chips(uint16_t asic_count, uint16_t chip_id, int chip_id_response_length);
esp_err_t receive_work(uint8_t * buffer, int buffer_size);
#endif /* COMMON_H_ */

View File

@ -0,0 +1,31 @@
#ifndef FREQUENCY_TRANSITION_H
#define FREQUENCY_TRANSITION_H
#include <stdbool.h>
extern const char *FREQUENCY_TRANSITION_TAG;
/**
* @brief Function pointer type for ASIC hash frequency setting functions
*
* This type defines the signature for functions that set the hash frequency
* for different ASIC types.
*
* @param frequency The frequency to set in MHz
*/
typedef void (*set_hash_frequency_fn)(float frequency);
/**
* @brief Transition the ASIC frequency to a target value
*
* This function gradually adjusts the ASIC frequency to reach the target value,
* stepping up or down in increments to ensure stability.
*
* @param target_frequency The target frequency in MHz
* @param set_frequency_fn Function pointer to the appropriate ASIC's set_hash_frequency function
* @param asic_type The type of ASIC chip (for logging purposes only)
* @return bool True if the transition was successful, false otherwise
*/
bool do_frequency_transition(float target_frequency, set_hash_frequency_fn set_frequency_fn, int asic_type);
#endif // FREQUENCY_TRANSITION_H

View File

@ -1,8 +1,7 @@
#ifndef SERIAL_H_
#define SERIAL_H_
#define SERIAL_BUF_SIZE 16
#define CHUNK_SIZE 1024
#include "esp_err.h"
int SERIAL_send(uint8_t *, int, bool);
esp_err_t SERIAL_init(void);

View File

@ -15,6 +15,9 @@
#include "connect.h"
#include "main.h"
// Maximum number of access points to scan
#define MAX_AP_COUNT 20
#if CONFIG_ESP_WPA3_SAE_PWE_HUNT_AND_PECK
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HUNT_AND_PECK
#define EXAMPLE_H2E_IDENTIFIER ""
@ -51,34 +54,114 @@ static EventGroupHandle_t s_wifi_event_group;
static const char * TAG = "wifi_station";
static bool is_scanning = false;
static uint16_t ap_number = 0;
static wifi_ap_record_t ap_info[MAX_AP_COUNT];
// Function to scan for available WiFi networks
esp_err_t wifi_scan(wifi_ap_record_simple_t *ap_records, uint16_t *ap_count)
{
if (is_scanning) {
ESP_LOGW(TAG, "Scan already in progress");
return ESP_ERR_INVALID_STATE;
}
ESP_LOGI(TAG, "Starting Wi-Fi scan!");
is_scanning = true;
wifi_ap_record_t current_ap_info;
if (esp_wifi_sta_get_ap_info(&current_ap_info) != ESP_OK) {
ESP_LOGI(TAG, "Forcing disconnect so that we can scan!");
esp_wifi_disconnect();
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
wifi_scan_config_t scan_config = {
.ssid = 0,
.bssid = 0,
.channel = 0,
.show_hidden = false
};
esp_err_t err = esp_wifi_scan_start(&scan_config, false);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Wi-Fi scan start failed with error: %s", esp_err_to_name(err));
is_scanning = false;
return err;
}
uint16_t retries_remaining = 10;
while (is_scanning) {
retries_remaining--;
if (retries_remaining == 0) {
is_scanning = false;
return ESP_FAIL;
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
ESP_LOGD(TAG, "Wi-Fi networks found: %d", ap_number);
if (ap_number == 0) {
ESP_LOGW(TAG, "No Wi-Fi networks found");
}
*ap_count = ap_number;
memset(ap_records, 0, (*ap_count) * sizeof(wifi_ap_record_simple_t));
for (int i = 0; i < ap_number; i++) {
memcpy(ap_records[i].ssid, ap_info[i].ssid, sizeof(ap_records[i].ssid));
ap_records[i].rssi = ap_info[i].rssi;
ap_records[i].authmode = ap_info[i].authmode;
}
ESP_LOGD(TAG, "Finished Wi-Fi scan!");
return ESP_OK;
}
static int s_retry_num = 0;
static char * _ip_addr_str;
static void event_handler(void * arg, esp_event_base_t event_base, int32_t event_id, void * event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
MINER_set_wifi_status(WIFI_CONNECTING, 0, 0);
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
//lookup the exact reason code
wifi_event_sta_disconnected_t* event = (wifi_event_sta_disconnected_t*) event_data;
if (event->reason == WIFI_REASON_ROAMING) {
ESP_LOGI(TAG, "We are roaming, nothing to do");
if (event_base == WIFI_EVENT)
{
if (event_id == WIFI_EVENT_SCAN_DONE) {
esp_wifi_scan_get_ap_num(&ap_number);
ESP_LOGI(TAG, "Wi-Fi Scan Done");
if (esp_wifi_scan_get_ap_records(&ap_number, ap_info) != ESP_OK) {
ESP_LOGI(TAG, "Failed esp_wifi_scan_get_ap_records");
}
is_scanning = false;
}
if (is_scanning) {
ESP_LOGI(TAG, "Still scanning, ignore wifi event.");
return;
}
ESP_LOGI(TAG, "Could not connect to '%s' [rssi %d]: reason %d", event->ssid, event->rssi, event->reason);
if (event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
MINER_set_wifi_status(WIFI_CONNECTING, 0, 0);
} else if (event_id == WIFI_EVENT_STA_DISCONNECTED) {
wifi_event_sta_disconnected_t* event = (wifi_event_sta_disconnected_t*) event_data;
if (event->reason == WIFI_REASON_ROAMING) {
ESP_LOGI(TAG, "We are roaming, nothing to do");
return;
}
// Wait a little
vTaskDelay(2500 / portTICK_PERIOD_MS);
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "Retrying WiFi connection...");
MINER_set_wifi_status(WIFI_RETRYING, s_retry_num, event->reason);
ESP_LOGI(TAG, "Could not connect to '%s' [rssi %d]: reason %d", event->ssid, event->rssi, event->reason);
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
// Wait a little
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "Retrying Wi-Fi connection...");
MINER_set_wifi_status(WIFI_RETRYING, s_retry_num, event->reason);
vTaskDelay(5000 / portTICK_PERIOD_MS);
}
}
if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t * event = (ip_event_got_ip_t *) event_data;
snprintf(_ip_addr_str, IP4ADDR_STRLEN_MAX, IPSTR, IP2STR(&event->ip_info.ip));
@ -160,10 +243,10 @@ esp_netif_t * wifi_init_sta(const char * wifi_ssid, const char * wifi_pass)
wifi_auth_mode_t authmode;
if (strlen(wifi_pass) == 0) {
ESP_LOGI(TAG, "No WiFi password provided, using open network");
ESP_LOGI(TAG, "No Wi-Fi password provided, using open network");
authmode = WIFI_AUTH_OPEN;
} else {
ESP_LOGI(TAG, "WiFi Password provided, using WPA2");
ESP_LOGI(TAG, "Wi-Fi Password provided, using WPA2");
authmode = WIFI_AUTH_WPA2_PSK;
}
@ -214,7 +297,7 @@ void wifi_init(const char * wifi_ssid, const char * wifi_pass, const char * host
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
/*Initialize WiFi */
/* Initialize Wi-Fi */
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
@ -224,27 +307,41 @@ void wifi_init(const char * wifi_ssid, const char * wifi_pass, const char * host
ESP_LOGI(TAG, "ESP_WIFI Access Point On");
wifi_init_softap();
/* Initialize STA */
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
esp_netif_t * esp_netif_sta = wifi_init_sta(wifi_ssid, wifi_pass);
/* Start WiFi */
ESP_ERROR_CHECK(esp_wifi_start());
/* Skip connection if SSID is null */
if (strlen(wifi_ssid) == 0) {
ESP_LOGI(TAG, "No WiFi SSID provided, skipping connection");
/* Disable power savings for best performance */
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
/* Start WiFi */
ESP_ERROR_CHECK(esp_wifi_start());
/* Set Hostname */
esp_err_t err = esp_netif_set_hostname(esp_netif_sta, hostname);
if (err != ERR_OK) {
ESP_LOGW(TAG, "esp_netif_set_hostname failed: %s", esp_err_to_name(err));
/* Disable power savings for best performance */
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
return;
} else {
ESP_LOGI(TAG, "ESP_WIFI setting hostname to: %s", hostname);
/* Initialize STA */
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
esp_netif_t * esp_netif_sta = wifi_init_sta(wifi_ssid, wifi_pass);
/* Start Wi-Fi */
ESP_ERROR_CHECK(esp_wifi_start());
/* Disable power savings for best performance */
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
/* Set Hostname */
esp_err_t err = esp_netif_set_hostname(esp_netif_sta, hostname);
if (err != ERR_OK) {
ESP_LOGW(TAG, "esp_netif_set_hostname failed: %s", esp_err_to_name(err));
} else {
ESP_LOGI(TAG, "ESP_WIFI setting hostname to: %s", hostname);
}
ESP_LOGI(TAG, "wifi_init_sta finished.");
return;
}
ESP_LOGI(TAG, "wifi_init_sta finished.");
return;
}
EventBits_t wifi_connect(void)

View File

@ -5,6 +5,14 @@
#include <lwip/netdb.h>
#include "freertos/event_groups.h"
#include "esp_wifi_types.h"
// Structure to hold WiFi scan results
typedef struct {
char ssid[33]; // 32 chars + null terminator
int8_t rssi;
wifi_auth_mode_t authmode;
} wifi_ap_record_simple_t;
#define WIFI_SSID CONFIG_ESP_WIFI_SSID
#define WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
@ -32,3 +40,4 @@ void wifi_softap_off(void);
void wifi_init(const char * wifi_ssid, const char * wifi_pass, const char * hostname, char * ip_addr_str);
EventBits_t wifi_connect(void);
void generate_ssid(char * ssid);
esp_err_t wifi_scan(wifi_ap_record_simple_t *ap_records, uint16_t *ap_count);

View File

@ -62,25 +62,23 @@ typedef struct
char * error_str;
} StratumApiV1Message;
void STRATUM_V1_reset_uid();
void STRATUM_V1_initialize_buffer();
char *STRATUM_V1_receive_jsonrpc_line(int sockfd);
int STRATUM_V1_subscribe(int socket, char * model);
int STRATUM_V1_subscribe(int socket, int send_uid, char * model);
void STRATUM_V1_parse(StratumApiV1Message *message, const char *stratum_json);
void STRATUM_V1_free_mining_notify(mining_notify *params);
int STRATUM_V1_authenticate(int socket, const char *username, const char *pass);
int STRATUM_V1_authenticate(int socket, int send_uid, const char *username, const char *pass);
int STRATUM_V1_configure_version_rolling(int socket, uint32_t * version_mask);
int STRATUM_V1_configure_version_rolling(int socket, int send_uid, uint32_t * version_mask);
int STRATUM_V1_suggest_difficulty(int socket, uint32_t difficulty);
int STRATUM_V1_suggest_difficulty(int socket, int send_uid, uint32_t difficulty);
int STRATUM_V1_submit_share(int socket, const char *username, const char *jobid,
int STRATUM_V1_submit_share(int socket, int send_uid, const char *username, const char *jobid,
const char *extranonce_2, const uint32_t ntime, const uint32_t nonce,
const uint32_t version);

View File

@ -115,7 +115,7 @@ char *extranonce_2_generate(uint32_t extranonce_2, uint32_t length)
char *extranonce_2_str = malloc(length * 2 + 1);
memset(extranonce_2_str, '0', length * 2);
extranonce_2_str[length * 2] = '\0';
bin2hex((uint8_t *)&extranonce_2, sizeof(extranonce_2), extranonce_2_str, length * 2 + 1);
bin2hex((uint8_t *)&extranonce_2, length, extranonce_2_str, length * 2 + 1);
if (length > 4)
{
extranonce_2_str[8] = '0';

View File

@ -19,20 +19,9 @@ static const char * TAG = "stratum_api";
static char * json_rpc_buffer = NULL;
static size_t json_rpc_buffer_size = 0;
// A message ID that must be unique per request that expects a response.
// For requests not expecting a response (called notifications), this is null.
static int send_uid = 1;
static void debug_stratum_tx(const char *);
int _parse_stratum_subscribe_result_message(const char * result_json_str, char ** extranonce, int * extranonce2_len);
void STRATUM_V1_reset_uid()
{
ESP_LOGI(TAG, "Resetting stratum uid");
send_uid = 1;
}
void STRATUM_V1_initialize_buffer()
{
json_rpc_buffer = malloc(BUFFER_SIZE);
@ -148,12 +137,15 @@ void STRATUM_V1_parse(StratumApiV1Message * message, const char * stratum_json)
cJSON * error_json = cJSON_GetObjectItem(json, "error");
cJSON * reject_reason_json = cJSON_GetObjectItem(json, "reject-reason");
//if the result is null, then it's a fail
// if the result is null, then it's a fail
if (result_json == NULL) {
message->response_success = false;
message->error_str = strdup("unknown");
//if it's an error, then it's a fail
// if it's an error, then it's a fail
} else if (!cJSON_IsNull(error_json)) {
message->response_success = false;
message->error_str = strdup("unknown");
if (parsed_id < 5) {
result = STRATUM_RESULT_SETUP;
} else {
@ -168,9 +160,8 @@ void STRATUM_V1_parse(StratumApiV1Message * message, const char * stratum_json)
}
}
}
message->response_success = false;
//if the result is a boolean, then parse it
// if the result is a boolean, then parse it
} else if (cJSON_IsBool(result_json)) {
if (parsed_id < 5) {
result = STRATUM_RESULT_SETUP;
@ -181,6 +172,7 @@ void STRATUM_V1_parse(StratumApiV1Message * message, const char * stratum_json)
message->response_success = true;
} else {
message->response_success = false;
message->error_str = strdup("unknown");
if (cJSON_IsString(reject_reason_json)) {
message->error_str = strdup(cJSON_GetStringValue(reject_reason_json));
}
@ -319,31 +311,31 @@ int _parse_stratum_subscribe_result_message(const char * result_json_str, char *
return 0;
}
int STRATUM_V1_subscribe(int socket, char * model)
int STRATUM_V1_subscribe(int socket, int send_uid, char * model)
{
// Subscribe
char subscribe_msg[BUFFER_SIZE];
const esp_app_desc_t *app_desc = esp_app_get_description();
const char *version = app_desc->version;
sprintf(subscribe_msg, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": [\"bitaxe/%s/%s\"]}\n", send_uid++, model, version);
sprintf(subscribe_msg, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": [\"bitaxe/%s/%s\"]}\n", send_uid, model, version);
debug_stratum_tx(subscribe_msg);
return write(socket, subscribe_msg, strlen(subscribe_msg));
}
int STRATUM_V1_suggest_difficulty(int socket, uint32_t difficulty)
int STRATUM_V1_suggest_difficulty(int socket, int send_uid, uint32_t difficulty)
{
char difficulty_msg[BUFFER_SIZE];
sprintf(difficulty_msg, "{\"id\": %d, \"method\": \"mining.suggest_difficulty\", \"params\": [%ld]}\n", send_uid++, difficulty);
sprintf(difficulty_msg, "{\"id\": %d, \"method\": \"mining.suggest_difficulty\", \"params\": [%ld]}\n", send_uid, difficulty);
debug_stratum_tx(difficulty_msg);
return write(socket, difficulty_msg, strlen(difficulty_msg));
}
int STRATUM_V1_authenticate(int socket, const char * username, const char * pass)
int STRATUM_V1_authenticate(int socket, int send_uid, const char * username, const char * pass)
{
char authorize_msg[BUFFER_SIZE];
sprintf(authorize_msg, "{\"id\": %d, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}\n", send_uid++, username,
sprintf(authorize_msg, "{\"id\": %d, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}\n", send_uid, username,
pass);
debug_stratum_tx(authorize_msg);
@ -356,25 +348,26 @@ int STRATUM_V1_authenticate(int socket, const char * username, const char * pass
/// @param ntime The hex-encoded time value use in the block header.
/// @param extranonce_2 The hex-encoded value of extra nonce 2.
/// @param nonce The hex-encoded nonce value to use in the block header.
int STRATUM_V1_submit_share(int socket, const char * username, const char * jobid, const char * extranonce_2, const uint32_t ntime,
const uint32_t nonce, const uint32_t version)
int STRATUM_V1_submit_share(int socket, int send_uid, const char * username, const char * jobid,
const char * extranonce_2, const uint32_t ntime,
const uint32_t nonce, const uint32_t version)
{
char submit_msg[BUFFER_SIZE];
sprintf(submit_msg,
"{\"id\": %d, \"method\": \"mining.submit\", \"params\": [\"%s\", \"%s\", \"%s\", \"%08lx\", \"%08lx\", \"%08lx\"]}\n",
send_uid++, username, jobid, extranonce_2, ntime, nonce, version);
send_uid, username, jobid, extranonce_2, ntime, nonce, version);
debug_stratum_tx(submit_msg);
return write(socket, submit_msg, strlen(submit_msg));
}
int STRATUM_V1_configure_version_rolling(int socket, uint32_t * version_mask)
int STRATUM_V1_configure_version_rolling(int socket, int send_uid, uint32_t * version_mask)
{
char configure_msg[BUFFER_SIZE * 2];
sprintf(configure_msg,
"{\"id\": %d, \"method\": \"mining.configure\", \"params\": [[\"version-rolling\"], {\"version-rolling.mask\": "
"\"ffffffff\"}]}\n",
send_uid++);
send_uid);
debug_stratum_tx(configure_msg);
return write(socket, configure_msg, strlen(configure_msg));

View File

@ -138,7 +138,7 @@ TEST_CASE("Test extranonce 2 generation", "[mining extranonce2]")
free(fifth);
}
TEST_CASE("Test nonce diff checking", "[mining test_nonce]")
TEST_CASE("Test nonce diff checking", "[mining test_nonce][not-on-qemu]")
{
mining_notify notify_message;
notify_message.prev_block_hash = "d02b10fc0d4711eae1a805af50a8a83312a2215e00017f2b0000000000000000";
@ -153,7 +153,7 @@ TEST_CASE("Test nonce diff checking", "[mining test_nonce]")
TEST_ASSERT_EQUAL_INT(18, (int)diff);
}
TEST_CASE("Test nonce diff checking 2", "[mining test_nonce]")
TEST_CASE("Test nonce diff checking 2", "[mining test_nonce][not-on-qemu]")
{
mining_notify notify_message;
notify_message.prev_block_hash = "0c859545a3498373a57452fac22eb7113df2a465000543520000000000000000";

View File

@ -222,7 +222,7 @@ void midstate_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t *de
mbedtls_sha256_update(&midstate, data, 64);
// memcpy(dest, midstate.state, 32);
flip32bytes(dest, midstate.state);
flip32bytes(dest, midstate.state);
}
void swap_endian_words(const char *hex_words, uint8_t *output)

View File

@ -1,8 +1,8 @@
key,type,encoding,value
main,namespace,,
hostname,data,string,bitaxe
wifissid,data,string,myssid
wifipass,data,string,password
wifissid,data,string,
wifipass,data,string,
stratumurl,data,string,public-pool.io
stratumport,data,u16,21496
stratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe

View File

@ -1,8 +1,8 @@
key,type,encoding,value
main,namespace,,
hostname,data,string,bitaxe
wifissid,data,string,myssid
wifipass,data,string,password
wifissid,data,string,
wifipass,data,string,
stratumurl,data,string,public-pool.io
stratumport,data,u16,21496
stratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe

View File

@ -1,8 +1,8 @@
key,type,encoding,value
main,namespace,,
hostname,data,string,bitaxe
wifissid,data,string,myssid
wifipass,data,string,password
wifissid,data,string,
wifipass,data,string,
stratumurl,data,string,public-pool.io
stratumport,data,u16,21496
stratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe

View File

@ -1,8 +1,8 @@
key,type,encoding,value
main,namespace,,
hostname,data,string,bitaxe
wifissid,data,string,myssid
wifipass,data,string,password
wifissid,data,string,
wifipass,data,string,
stratumurl,data,string,public-pool.io
stratumport,data,u16,21496
stratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe

View File

@ -1,8 +1,8 @@
key,type,encoding,value
main,namespace,,
hostname,data,string,bitaxe
wifissid,data,string,myssid
wifipass,data,string,password
wifissid,data,string,
wifipass,data,string,
stratumurl,data,string,public-pool.io
stratumport,data,u16,21496
stratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe

View File

@ -1,8 +1,8 @@
key,type,encoding,value
main,namespace,,
hostname,data,string,bitaxe
wifissid,data,string,myssid
wifipass,data,string,password
wifissid,data,string,
wifipass,data,string,
stratumurl,data,string,public-pool.io
stratumport,data,u16,21496
stratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe

View File

@ -1,8 +1,8 @@
key,type,encoding,value
main,namespace,,
hostname,data,string,bitaxe
wifissid,data,string,myssid
wifipass,data,string,password
wifissid,data,string,
wifipass,data,string,
stratumurl,data,string,public-pool.io
stratumport,data,u16,21496
stratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe

View File

@ -1,8 +1,8 @@
key,type,encoding,value
main,namespace,,
hostname,data,string,bitaxe
wifissid,data,string,myssid
wifipass,data,string,password
wifissid,data,string,
wifipass,data,string,
stratumurl,data,string,public-pool.io
stratumport,data,u16,21496
stratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe

View File

@ -1,8 +1,8 @@
key,type,encoding,value
main,namespace,,
hostname,data,string,bitaxe
wifissid,data,string,myssid
wifipass,data,string,password
wifissid,data,string,
wifipass,data,string,
stratumurl,data,string,public-pool.io
stratumport,data,u16,21496
stratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe

View File

@ -1,8 +1,8 @@
key,type,encoding,value
main,namespace,,
hostname,data,string,bitaxe
wifissid,data,string,myssid
wifipass,data,string,password
wifissid,data,string,
wifipass,data,string,
stratumurl,data,string,public-pool.io
stratumport,data,u16,21496
stratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe

24
config-800x.cvs Normal file
View File

@ -0,0 +1,24 @@
key,type,encoding,value
main,namespace,,
hostname,data,string,bitaxe
wifissid,data,string,myssid
wifipass,data,string,password
stratumurl,data,string,public-pool.io
stratumport,data,u16,21496
stratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe
stratumpass,data,string,x
fbstratumurl,data,string,solo.ckpool.org
fbstratumport,data,u16,3333
fbstratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe
fbstratumpass,data,string,x
asicfrequency,data,u16,525
asicvoltage,data,u16,1150
asicmodel,data,string,BM1370
devicemodel,data,string,gammaturbo
boardversion,data,string,800
flipscreen,data,u16,1
invertfanpol,data,u16,1
autofanspeed,data,u16,1
fanspeed,data,u16,100
selftest,data,u16,0
overheat_mode,data,u16,0

View File

@ -1,5 +1,5 @@
## Flashing Factory Image
You can flash [factory images](https://github.com/skot/ESP-Miner/releases) to your Bitaxe using generic ESP32 flashing tools such as the [esptool-js website](https://espressif.github.io/esptool-js/)
You can flash [factory images](https://github.com/bitaxeorg/ESP-Miner/releases) to your Bitaxe using generic ESP32 flashing tools such as the [esptool-js website](https://espressif.github.io/esptool-js/)
- Power up your bitaxe via the barrel connector
- attach your bitaxe USB to your computer
@ -11,7 +11,7 @@ You can flash [factory images](https://github.com/skot/ESP-Miner/releases) to yo
- on PC it will prolly be one of those COM ports. Good luck.
- Select the proper serial port and then click connect
- Once the ESP Tool has connected to your Bitaxe over serial, Set the Flash Address to `0x0`
- Under File click "Choose File" and select the [factory image](https://github.com/skot/ESP-Miner/releases) you want to flash. it's called something like `esp-miner-factory-400-v2.1.5d.bin` Be sure to use the image with the same version number as your Bitaxe (400 in this case)
- Under File click "Choose File" and select the [factory image](https://github.com/bitaxeorg/ESP-Miner/releases) you want to flash. it's called something like `esp-miner-factory-400-v2.1.5.bin` Be sure to use the image with the same version number as your Bitaxe (400 in this case)
- Down below click the "Program" button
- Wait paitiently.
- Keep waiting until the console on ESP Tool says "Leaving..."

View File

@ -1,18 +1,13 @@
idf_component_register(
SRCS
"adc.c"
"DS4432U.c"
"EMC2101.c"
"i2c_bitaxe.c"
"INA260.c"
"main.c"
"nvs_config.c"
"display.c"
"screen.c"
"input.c"
"system.c"
"TPS546.c"
"vcore.c"
"work_queue.c"
"nvs_device.c"
"lv_font_portfolio-6x8.c"
@ -25,6 +20,15 @@ SRCS
"./tasks/asic_task.c"
"./tasks/asic_result_task.c"
"./tasks/power_management_task.c"
"./thermal/EMC2101.c"
"./thermal/EMC2103.c"
"./thermal/TMP1075.c"
"./thermal/thermal.c"
"./power/TPS546.c"
"./power/DS4432U.c"
"./power/INA260.c"
"./power/power.c"
"./power/vcore.c"
INCLUDE_DIRS
"."
@ -35,6 +39,8 @@ INCLUDE_DIRS
"../components/connect/include"
"../components/dns_server/include"
"../components/stratum/include"
"thermal"
"power"
PRIV_REQUIRES
"app_update"
@ -52,6 +58,8 @@ PRIV_REQUIRES
"spiffs"
"vfs"
"esp_driver_i2c"
EMBED_FILES "http_server/recovery_page.html"
)
idf_build_set_property(COMPILE_OPTIONS "-DLV_CONF_INCLUDE_SIMPLE=1" APPEND)

View File

@ -27,6 +27,7 @@ typedef enum
DEVICE_ULTRA,
DEVICE_SUPRA,
DEVICE_GAMMA,
DEVICE_GAMMATURBO,
} DeviceModel;
typedef enum
@ -38,15 +39,20 @@ typedef enum
ASIC_BM1370,
} AsicModel;
typedef struct
{
uint8_t (*init_fn)(uint64_t, uint16_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);
void (*set_version_mask)(uint32_t);
} AsicFunctions;
// typedef struct
// {
// uint8_t (*init_fn)(uint64_t, uint16_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);
// void (*set_version_mask)(uint32_t);
// } AsicFunctions;
typedef struct {
char message[64];
uint32_t count;
} RejectedReasonStat;
typedef struct
{
@ -59,6 +65,8 @@ typedef struct
int64_t start_time;
uint64_t shares_accepted;
uint64_t shares_rejected;
RejectedReasonStat rejected_reason_stats[10];
int rejected_reason_stats_count;
int screen_page;
uint64_t best_nonce_diff;
char best_diff_string[DIFF_STRING_SIZE];
@ -74,10 +82,17 @@ typedef struct
char * fallback_pool_url;
uint16_t pool_port;
uint16_t fallback_pool_port;
char * pool_user;
char * fallback_pool_user;
char * pool_pass;
char * fallback_pool_pass;
bool is_using_fallback;
uint16_t overheat_mode;
uint32_t lastClockSync;
bool is_screen_active;
bool is_firmware_update;
char firmware_update_filename[20];
char firmware_update_status[20];
} SystemModule;
typedef struct
@ -94,10 +109,8 @@ typedef struct
char * device_model_str;
int board_version;
AsicModel asic_model;
bool valid_model;
char * asic_model_str;
uint16_t asic_count;
uint16_t voltage_domain;
AsicFunctions ASIC_functions;
double asic_job_frequency_ms;
uint32_t ASIC_difficulty;
@ -122,7 +135,13 @@ typedef struct
bool new_stratum_version_rolling_msg;
int sock;
// A message ID that must be unique per request that expects a response.
// For requests not expecting a response (called notifications), this is null.
int send_uid;
bool ASIC_initalized;
bool psram_is_available;
} GlobalState;
#endif /* GLOBAL_STATE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,9 @@
{
"name": "axe-os",
"version": "0.0.0",
"engines": {
"node": ">=22.0.0"
},
"scripts": {
"ng": "ng",
"start": "ng serve",
@ -11,31 +14,32 @@
},
"private": true,
"dependencies": {
"@angular/animations": "17.3.12",
"@angular/common": "17.3.12",
"@angular/compiler": "17.3.12",
"@angular/core": "17.3.12",
"@angular/forms": "17.3.12",
"@angular/platform-browser": "17.3.12",
"@angular/platform-browser-dynamic": "17.3.12",
"@angular/router": "17.3.12",
"@angular/animations": "18.2.13",
"@angular/common": "18.2.13",
"@angular/compiler": "18.2.13",
"@angular/core": "18.2.13",
"@angular/forms": "18.2.13",
"@angular/platform-browser": "18.2.13",
"@angular/platform-browser-dynamic": "18.2.13",
"@angular/router": "18.2.13",
"@xterm/xterm": "^5.5.0",
"chart.js": "^4.4.7",
"chartjs-adapter-moment": "^1.0.1",
"moment": "^2.30.1",
"ngx-toastr": "^17.0.2",
"ngx-toastr": "^19.0.0",
"primeflex": "^3.3.1",
"primeicons": "^7.0.0",
"primeng": "^17.18.15",
"rxjs": "~7.8.1",
"tslib": "^2.8.1",
"xterm": "^5.3.0",
"zone.js": "~0.14.10"
},
"devDependencies": {
"@angular-devkit/build-angular": "^17.3.11",
"@angular/cli": "17.3.11",
"@angular/compiler-cli": "17.3.12",
"@angular-devkit/build-angular": "^18.2.14",
"@angular/cli": "18.2.14",
"@angular/compiler-cli": "18.2.13",
"@types/jasmine": "~5.1.5",
"chokidar": "^3.6.0",
"gzipper": "^8.2.0",
"jasmine-core": "~5.5.0",
"karma": "~6.4.4",
@ -43,7 +47,7 @@
"karma-coverage": "~2.2.1",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.4.5",
"typescript": "~5.5.4",
"webpack-bundle-analyzer": "^4.10.2"
}
}

View File

@ -6,12 +6,26 @@ import { LogsComponent } from './components/logs/logs.component';
import { SettingsComponent } from './components/settings/settings.component';
import { NetworkComponent } from './components/network/network.component';
import { SwarmComponent } from './components/swarm/swarm.component';
import { DesignComponent } from './components/design/design.component';
import { PoolComponent } from './components/pool/pool.component';
import { AppLayoutComponent } from './layout/app.layout.component';
import { ApModeGuard } from './guards/ap-mode.guard';
const routes: Routes = [
{
path: 'ap',
component: AppLayoutComponent,
children: [
{
path: '',
component: NetworkComponent
}
]
},
{
path: '',
component: AppLayoutComponent,
canActivate: [ApModeGuard],
children: [
{
path: '',
@ -32,6 +46,14 @@ const routes: Routes = [
{
path: 'swarm',
component: SwarmComponent
},
{
path: 'design',
component: DesignComponent
},
{
path: 'pool',
component: PoolComponent
}
]
},

View File

@ -11,6 +11,7 @@ import { ToastrModule } from 'ngx-toastr';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { EditComponent } from './components/edit/edit.component';
import { PoolComponent } from './components/pool/pool.component';
import { NetworkEditComponent } from './components/network-edit/network.edit.component';
import { HomeComponent } from './components/home/home.component';
import { LoadingComponent } from './components/loading/loading.component';
@ -18,7 +19,8 @@ import { LogsComponent } from './components/logs/logs.component';
import { NetworkComponent } from './components/network/network.component';
import { SettingsComponent } from './components/settings/settings.component';
import { SwarmComponent } from './components/swarm/swarm.component';
import { ThemeConfigComponent } from './components/settings/theme-config.component';
import { ThemeConfigComponent } from './components/design/theme-config.component';
import { DesignComponent } from './components/design/design.component';
import { AppLayoutModule } from './layout/app.layout.module';
import { ANSIPipe } from './pipes/ansi.pipe';
import { DateAgoPipe } from './pipes/date-ago.pipe';
@ -26,6 +28,9 @@ import { HashSuffixPipe } from './pipes/hash-suffix.pipe';
import { PrimeNGModule } from './prime-ng.module';
import { MessageModule } from 'primeng/message';
import { TooltipModule } from 'primeng/tooltip';
import { DialogModule } from 'primeng/dialog';
import { DynamicDialogModule, DialogService as PrimeDialogService } from 'primeng/dynamicdialog';
import { DialogService, DialogListComponent } from './services/dialog.service';
const components = [
AppComponent,
@ -35,7 +40,8 @@ const components = [
LoadingComponent,
NetworkComponent,
SettingsComponent,
LogsComponent
LogsComponent,
PoolComponent
];
@NgModule({
@ -47,7 +53,10 @@ const components = [
SwarmComponent,
SettingsComponent,
HashSuffixPipe,
ThemeConfigComponent
ThemeConfigComponent,
DesignComponent,
PoolComponent,
DialogListComponent
],
imports: [
BrowserModule,
@ -63,10 +72,14 @@ const components = [
PrimeNGModule,
AppLayoutModule,
MessageModule,
TooltipModule
TooltipModule,
DialogModule,
DynamicDialogModule
],
providers: [
{ provide: LocationStrategy, useClass: HashLocationStrategy },
DialogService,
PrimeDialogService
],
bootstrap: [AppComponent]
})

View File

@ -0,0 +1,4 @@
<div class="card">
<h2>Design</h2>
<app-theme-config></app-theme-config>
</div>

View File

@ -0,0 +1,9 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-design',
templateUrl: './design.component.html',
})
export class DesignComponent {
constructor() { }
}

View File

@ -34,8 +34,8 @@ interface ThemeOption {
<div class="col-12">
<h6>Theme Colors</h6>
<div class="grid">
<div *ngFor="let theme of themes" class="col-3">
<div class="grid gap-2">
<div *ngFor="let theme of themes" class="col-2">
<button pButton [class]="'p-button-rounded p-button-text color-dot'"
[style.backgroundColor]="theme.primaryColor"
style="width: 2rem; height: 2rem; border: none;"
@ -52,6 +52,38 @@ interface ThemeOption {
export class ThemeConfigComponent implements OnInit {
selectedScheme: string;
themes: ThemeOption[] = [
{
name: 'Orange',
primaryColor: '#F7931A',
accentColors: {
'--primary-color': '#F7931A',
'--primary-color-text': '#ffffff',
'--highlight-bg': '#F7931A',
'--highlight-text-color': '#ffffff',
'--focus-ring': '0 0 0 0.2rem rgba(247,147,26,0.2)',
// PrimeNG Slider
'--slider-bg': '#dee2e6',
'--slider-range-bg': '#F7931A',
'--slider-handle-bg': '#F7931A',
// Progress Bar
'--progressbar-bg': '#dee2e6',
'--progressbar-value-bg': '#F7931A',
// PrimeNG Checkbox
'--checkbox-border': '#F7931A',
'--checkbox-bg': '#F7931A',
'--checkbox-hover-bg': '#e58617',
// PrimeNG Button
'--button-bg': '#F7931A',
'--button-hover-bg': '#e58617',
'--button-focus-shadow': '0 0 0 2px #ffffff, 0 0 0 4px #F7931A',
// Toggle button
'--togglebutton-bg': '#F7931A',
'--togglebutton-border': '1px solid #F7931A',
'--togglebutton-hover-bg': '#e58617',
'--togglebutton-hover-border': '1px solid #e58617',
'--togglebutton-text-color': '#ffffff'
}
},
{
name: 'Red',
primaryColor: '#F80421',

View File

@ -1,73 +1,11 @@
<ng-container *ngIf="form != null">
<form [formGroup]="form">
<div class="field grid p-fluid">
<label htmlFor="stratumURL" class="col-12 mb-2 md:col-2 md:mb-0">Stratum Host:</label>
<div class="col-12 md:col-10">
<input pInputText id="stratumURL" type="text" formControlName="stratumURL"
formControlName="stratumURL" />
<div>
<small>Do not include 'stratum+tcp://' or port.</small>
</div>
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="stratumPort" class="col-12 mb-2 md:col-2 md:mb-0">Stratum Port:</label>
<div class="col-12 md:col-10">
<input pInputText id="stratumPort" formControlName="stratumPort" type="number" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="stratumUser" class="col-12 mb-2 md:col-2 md:mb-0">Stratum User:</label>
<div class="col-12 md:col-10">
<input pInputText id="stratumUser" formControlName="stratumUser" type="text" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="stratumPassword" class="col-12 mb-2 md:col-2 md:mb-0">Stratum Password:</label>
<div class="col-12 md:col-10 p-input-icon-right">
<i *ngIf="form.get('stratumPassword')?.dirty" class="pi"
[ngClass]="{'pi-eye': !showStratumPassword, 'pi-eye-slash': showStratumPassword}"
(click)="toggleStratumPasswordVisibility()" style="cursor: pointer;"></i>
<input pInputText id="stratumPassword" formControlName="stratumPassword"
[type]="showStratumPassword ? 'text' : 'password'"
placeholder="Enter stratum password" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="stratumURL" class="col-12 mb-2 md:col-2 md:mb-0">Fallback Stratum Host:</label>
<div class="col-12 md:col-10">
<input pInputText id="fallbackStratumURL" type="text" formControlName="fallbackStratumURL"
formControlName="fallbackStratumURL" />
<div>
<small>Do not include 'stratum+tcp://' or port.</small>
</div>
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="fallbackStratumPort" class="col-12 mb-2 md:col-2 md:mb-0">Fallback Stratum Port:</label>
<div class="col-12 md:col-10">
<input pInputText id="fallbackStratumPort" formControlName="fallbackStratumPort" type="number" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="fallbackStratumUser" class="col-12 mb-2 md:col-2 md:mb-0">Fallback Stratum User:</label>
<div class="col-12 md:col-10">
<input pInputText id="fallbackStratumUser" formControlName="fallbackStratumUser" type="text" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="fallbackStratumPassword" class="col-12 mb-2 md:col-2 md:mb-0">Fallback Stratum Password:</label>
<div class="col-12 md:col-10 p-input-icon-right">
<i *ngIf="form.get('fallbackStratumPassword')?.dirty" class="pi"
[ngClass]="{'pi-eye': !showFallbackStratumPassword, 'pi-eye-slash': showFallbackStratumPassword}"
(click)="toggleFallbackStratumPasswordVisibility()" style="cursor: pointer;"></i>
<input pInputText id="fallbackStratumPassword" formControlName="fallbackStratumPassword"
[type]="showFallbackStratumPassword ? 'text' : 'password'"
placeholder="Enter fallback stratum password" />
</div>
</div>
<ng-container *ngIf="!devToolsOpen && [eASICModel.BM1366, eASICModel.BM1368, eASICModel.BM1370, eASICModel.BM1397].includes(ASICModel)">
<p-message *ngIf="settingsUnlocked" severity="warn" styleClass="w-full mb-3 py-4 border-round-xl"
text="Custom settings can cause damage & system instability. Only modify these settings if you understand the risks of running outside designed parameters.">
</p-message>
<ng-container *ngIf="!settingsUnlocked && restrictedModels.includes(ASICModel)">
<div class="field grid p-fluid">
<label class="col-12 mb-2 md:col-2 md:mb-0" htmlFor="frequency">Frequency</label>
<div class="col-12 md:col-10">
@ -83,7 +21,7 @@
</div>
</ng-container>
<ng-container *ngIf="devToolsOpen === true">
<ng-container *ngIf="settingsUnlocked === true">
<div class="field grid p-fluid">
<label htmlFor="frequency" class="col-12 mb-2 md:col-2 md:mb-0">Frequency</label>
@ -115,7 +53,7 @@
<div class="field-checkbox">
<p-checkbox name="flipscreen" formControlName="flipscreen" inputId="flipscreen"
[binary]="true"></p-checkbox>
<label for="flipscreen">Flip Screen</label>
<label for="flipscreen">Flip Screen <i class="pi pi-info-circle" style="font-size: 0.8rem; margin-left: 0.2rem;" pTooltip="Rotates the LCD screen by 180 degrees"></i></label>
</div>
</div>
@ -123,7 +61,7 @@
<div class="field-checkbox">
<p-checkbox name="invertfanpolarity" formControlName="invertfanpolarity" inputId="invertfanpolarity"
[binary]="true"></p-checkbox>
<label for="invertfanpolarity">Invert Fan Polarity</label>
<label for="invertfanpolarity">Invert Fan Polarity <i class="pi pi-info-circle" style="font-size: 0.8rem; margin-left: 0.2rem;" pTooltip="Inverting the polarity of the fan PWM signal"></i></label>
</div>
</div>
<div class="col-12">
@ -153,6 +91,11 @@
<div class="mt-2">
<button pButton [disabled]="!savedChanges" (click)="restart()">Restart</button>
<button *ngIf="settingsUnlocked" pButton pButton="p-button-danger" (click)="toggleOverclockMode(false)"
class="p-button-danger" pTooltip="Return to safe preset values only">
Disable Overclock Mode
</button>
</div>

View File

@ -6,6 +6,7 @@ import { startWith, Subject, takeUntil } from 'rxjs';
import { LoadingService } from 'src/app/services/loading.service';
import { SystemService } from 'src/app/services/system.service';
import { eASICModel } from 'src/models/enum/eASICModel';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-edit',
@ -20,9 +21,11 @@ export class EditComponent implements OnInit, OnDestroy {
public websiteUpdateProgress: number | null = null;
public savedChanges: boolean = false;
public devToolsOpen: boolean = false;
public settingsUnlocked: boolean = false;
public eASICModel = eASICModel;
public ASICModel!: eASICModel;
public restrictedModels: eASICModel[] = Object.values(eASICModel)
.filter((v): v is eASICModel => typeof v === 'string');
@Input() uri = '';
@ -122,10 +125,44 @@ export class EditComponent implements OnInit, OnDestroy {
private fb: FormBuilder,
private systemService: SystemService,
private toastr: ToastrService,
private loadingService: LoadingService
private loadingService: LoadingService,
private route: ActivatedRoute,
) {
window.addEventListener('resize', this.checkDevTools.bind(this));
this.checkDevTools();
// Check URL parameter for settings unlock
this.route.queryParams.subscribe(params => {
const urlOcParam = params['oc'] !== undefined;
if (urlOcParam) {
// If ?oc is in URL, enable overclock and save to NVS
this.settingsUnlocked = true;
this.saveOverclockSetting(1);
console.log(
'🎉 The ancient seals have been broken!\n' +
'⚡ Unlimited power flows through your miner...\n' +
'🔧 You can now set custom frequency and voltage values.\n' +
'⚠️ Remember: with great power comes great responsibility!'
);
} else {
// If ?oc is not in URL, check NVS setting (will be loaded in ngOnInit)
console.log('🔒 Here be dragons! Advanced settings are locked for your protection. \n' +
'Only the bravest miners dare to venture forth... \n' +
'If you wish to unlock dangerous overclocking powers, add: %c?oc',
'color: #ff4400; text-decoration: underline; cursor: pointer; font-weight: bold;',
'to the current URL'
);
}
});
}
private saveOverclockSetting(enabled: number) {
this.systemService.updateSystem(this.uri, { overclockEnabled: enabled })
.subscribe({
next: () => {
console.log(`Overclock setting saved: ${enabled === 1 ? 'enabled' : 'disabled'}`);
},
error: (err) => {
console.error(`Failed to save overclock setting: ${err.message}`);
}
});
}
ngOnInit(): void {
@ -136,33 +173,19 @@ export class EditComponent implements OnInit, OnDestroy {
)
.subscribe(info => {
this.ASICModel = info.ASICModel;
// Check if overclock is enabled in NVS
if (info.overclockEnabled === 1) {
this.settingsUnlocked = true;
console.log(
'🎉 Overclock mode is enabled from NVS settings!\n' +
'⚡ Custom frequency and voltage values are available.'
);
}
this.form = this.fb.group({
flipscreen: [info.flipscreen == 1],
invertscreen: [info.invertscreen == 1],
stratumURL: [info.stratumURL, [
Validators.required,
Validators.pattern(/^(?!.*stratum\+tcp:\/\/).*$/),
Validators.pattern(/^[^:]*$/),
]],
stratumPort: [info.stratumPort, [
Validators.required,
Validators.pattern(/^[^:]*$/),
Validators.min(0),
Validators.max(65353)
]],
fallbackStratumURL: [info.fallbackStratumURL, [
Validators.pattern(/^(?!.*stratum\+tcp:\/\/).*$/),
]],
fallbackStratumPort: [info.fallbackStratumPort, [
Validators.required,
Validators.pattern(/^[^:]*$/),
Validators.min(0),
Validators.max(65353)
]],
stratumUser: [info.stratumUser, [Validators.required]],
stratumPassword: ['*****', [Validators.required]],
fallbackStratumUser: [info.fallbackStratumUser, [Validators.required]],
fallbackStratumPassword: ['password', [Validators.required]],
coreVoltage: [info.coreVoltage, [Validators.required]],
frequency: [info.frequency, [Validators.required]],
autofanspeed: [info.autofanspeed == 1, [Validators.required]],
@ -185,22 +208,10 @@ export class EditComponent implements OnInit, OnDestroy {
}
ngOnDestroy(): void {
window.removeEventListener('resize', this.checkDevTools.bind(this));
this.destroy$.next();
this.destroy$.complete();
}
private checkDevTools(): void {
if (
window.outerWidth - window.innerWidth > 160 ||
window.outerHeight - window.innerHeight > 160
) {
this.devToolsOpen = true;
} else {
this.devToolsOpen = false;
}
}
public updateSystem() {
const form = this.form.getRawValue();
@ -213,21 +224,18 @@ export class EditComponent implements OnInit, OnDestroy {
.pipe(this.loadingService.lockUIUntilComplete())
.subscribe({
next: () => {
this.toastr.success('Success!', 'Saved.');
const successMessage = this.uri ? `Saved settings for ${this.uri}` : 'Saved settings';
this.toastr.success(successMessage, 'Success!');
this.savedChanges = true;
},
error: (err: HttpErrorResponse) => {
this.toastr.error('Error.', `Could not save. ${err.message}`);
const errorMessage = this.uri ? `Could not save settings for ${this.uri}. ${err.message}` : `Could not save settings. ${err.message}`;
this.toastr.error(errorMessage, 'Error');
this.savedChanges = false;
}
});
}
showStratumPassword: boolean = false;
toggleStratumPasswordVisibility() {
this.showStratumPassword = !this.showStratumPassword;
}
showWifiPassword: boolean = false;
toggleWifiPasswordVisibility() {
this.showWifiPassword = !this.showWifiPassword;
@ -238,9 +246,18 @@ export class EditComponent implements OnInit, OnDestroy {
this.updateSystem();
}
showFallbackStratumPassword: boolean = false;
toggleFallbackStratumPasswordVisibility() {
this.showFallbackStratumPassword = !this.showFallbackStratumPassword;
toggleOverclockMode(enable: boolean) {
this.settingsUnlocked = enable;
this.saveOverclockSetting(enable ? 1 : 0);
if (enable) {
console.log(
'🎉 Overclock mode enabled!\n' +
'⚡ Custom frequency and voltage values are now available.'
);
} else {
console.log('🔒 Overclock mode disabled. Using safe preset values only.');
}
}
public restart() {
@ -248,10 +265,12 @@ export class EditComponent implements OnInit, OnDestroy {
.pipe(this.loadingService.lockUIUntilComplete())
.subscribe({
next: () => {
this.toastr.success('Success!', 'Bitaxe restarted');
const successMessage = this.uri ? `Bitaxe at ${this.uri} restarted` : 'Bitaxe restarted';
this.toastr.success(successMessage, 'Success');
},
error: (err: HttpErrorResponse) => {
this.toastr.error('Error', `Could not restart. ${err.message}`);
const errorMessage = this.uri ? `Failed to restart device at ${this.uri}. ${err.message}` : `Failed to restart device. ${err.message}`;
this.toastr.error(errorMessage, 'Error');
}
});
}

View File

@ -19,15 +19,24 @@
<div class="flex justify-content-between mb-3">
<div>
<span class="block text-500 font-medium mb-3">Hash Rate</span>
<div class="text-900 font-medium text-xl">{{info.hashRate * 1000000000 | hashSuffix}}
<div class="text-900 font-medium text-2xl flex align-items-center gap-2">
<span>
{{info.hashRate * 1000000000 | hashSuffix}}
</span>
</div>
</div>
</div>
<ng-container *ngIf="expectedHashRate$ | async as expectedHashRate">
<span class="text-green-500 font-medium">{{expectedHashRate * 1000000000 |
hashSuffix}}</span>
<span class="text-500"> expected</span>
<ng-container>
Average:
<span class="text-green-500 font-medium">
{{calculateAverage(hashrateData) | hashSuffix}}
</span>
</ng-container>
<div class="text-500 text-xs" *ngIf="expectedHashRate$ | async as expectedHashRate">
Expected: {{expectedHashRate * 1000000000 | hashSuffix}}
</div>
</div>
</div>
<div class="col-12 md:col-6 xl:col-3">
@ -35,20 +44,24 @@
<div class="flex justify-content-between mb-3">
<div>
<span class="block text-500 font-medium mb-3">Efficiency</span>
<div class="text-900 font-medium text-xl">
<td>{{info.power / (info.hashRate/1000) | number: '1.2-2'}} <small>J/TH</small>
</td>
<div class="text-900 font-medium text-2xl flex align-items-center gap-2">
<span>
{{info.power / (info.hashRate/1000) | number: '1.2-2'}} <small>J/TH</small>
</span>
</div>
</div>
</div>
<ng-container *ngIf="expectedHashRate$ | async as expectedHashRate">
<span class="text-green-500 font-medium">{{info.power / (expectedHashRate/1000) | number:
'1.2-2'}} <small>J/TH</small>
<ng-container>
Average:
<span class="text-green-500 font-medium">
{{calculateEfficiencyAverage(hashrateData, powerData) | number: '1.2-2'}} <small>J/TH</small>
</span>
<span class="text-500"> expected</span>
</ng-container>
<!-- <span class="text-green-500 font-medium">%52+ </span>
<span class="text-500">since last week</span> -->
<div class="text-500 text-xs " *ngIf="expectedHashRate$ | async as expectedHashRate" >
Expected: {{info.power / (expectedHashRate/1000) | number: '1.2-2'}} J/TH
</div>
</div>
</div>
<div class="col-12 md:col-6 xl:col-3">
@ -56,12 +69,21 @@
<div class="flex justify-content-between mb-3">
<div>
<span class="block text-500 font-medium mb-3">Shares</span>
<div class="text-900 font-medium text-xl">{{info.sharesAccepted | number: '1.0-0'}}
<div class="text-900 font-medium text-2xl">{{info.sharesAccepted | number: '1.0-0'}}
</div>
</div>
</div>
<span class="text-red-500 font-medium">{{info.sharesRejected | number: '1.0-0'}} </span>
<span class="text-500">rejected</span> <span class="font-medium"> ({{(info.sharesRejected / (info.sharesAccepted + info.sharesRejected) * 100) | number: '1.2-2'}}%)</span>
<div *ngIf="info.sharesRejected === 0">
<span class="text-red-500 font-medium">0 </span>
<span class="text-500">rejected</span>
</div>
<div *ngIf="info.sharesRejected > 0">
<div *ngFor="let sharesRejectedReason of info.sharesRejectedReasons">
<span class="text-red-500 font-medium">{{sharesRejectedReason.count | number: '1.0-0'}} </span>
<span class="text-500">{{sharesRejectedReason.message}}</span>
({{(sharesRejectedReason.count / (info.sharesAccepted + info.sharesRejected) * 100) | number: '1.2-2'}}%)
</div>
</div>
</div>
</div>
@ -70,8 +92,8 @@
<div class="flex justify-content-between mb-3">
<div>
<span class="block text-500 font-medium mb-3">Best Difficulty</span>
<div class="text-900 font-medium text-xl">{{info.bestDiff}}
<span class="text-500">all-time best</span>
<div class="text-900 font-medium text-2xl">{{info.bestDiff}}
<span class="text-500 text-lg">all-time best</span>
</div>
</div>
</div>
@ -146,7 +168,14 @@
<div class="grid">
<div class="col-12">
<h6>ASIC Temperature <span style="float: right;">{{info.temp}}&deg;C</span></h6>
<h6>ASIC Temperature
<span style="float: right;">
<ng-template #noTemp>--</ng-template>
<ng-container *ngIf="info.temp > 0; else noTemp">
{{info.temp}}&deg;C
</ng-container>
</span>
</h6>
<p-progressBar [value]="(info.temp / maxTemp) * 100" [style]="{ height: '6px' }" >
<ng-template pTemplate="content" let-value></ng-template>
</p-progressBar>

View File

@ -23,7 +23,7 @@ export class HomeComponent {
public dataLabel: number[] = [];
public hashrateData: number[] = [];
public temperatureData: number[] = [];
public dataDataAverage: number[] = [];
public powerData: number[] = [];
public chartData?: any;
public maxPower: number = 50;
@ -97,19 +97,6 @@ export class HomeComponent {
yAxisID: 'y',
fill: true,
},
{
type: 'line',
label: 'Average Hashrate',
data: [],
fill: false,
backgroundColor: primaryColor + '30',
borderColor: primaryColor + '60',
tension: 0,
pointRadius: 0,
borderWidth: 2,
borderDash: [5, 5],
yAxisID: 'y',
},
{
type: 'line',
label: 'ASIC Temp',
@ -203,21 +190,20 @@ export class HomeComponent {
tap(info => {
this.hashrateData.push(info.hashRate * 1000000000);
this.temperatureData.push(info.temp);
this.powerData.push(info.power);
this.dataLabel.push(new Date().getTime());
if (this.hashrateData.length >= 720) {
this.hashrateData.shift();
this.temperatureData.shift();
this.powerData.shift();
this.dataLabel.shift();
}
this.chartData.labels = this.dataLabel;
this.chartData.datasets[0].data = this.hashrateData;
this.chartData.datasets[2].data = this.temperatureData;
// Calculate average hashrate and fill the array with the same value for the average line
const averageHashrate = this.calculateAverage(this.hashrateData);
this.chartData.datasets[1].data = Array(this.hashrateData.length).fill(averageHashrate);
this.chartData.datasets[1].data = this.temperatureData;
this.chartData = {
...this.chartData
@ -255,7 +241,7 @@ export class HomeComponent {
}
private calculateAverage(data: number[]): number {
public calculateAverage(data: number[]): number {
if (data.length === 0) return 0;
const sum = data.reduce((sum, value) => sum + value, 0);
return sum / data.length;
@ -283,4 +269,16 @@ export class HomeComponent {
}
return stratumURL.startsWith('http') ? stratumURL : `http://${stratumURL}`;
}
public calculateEfficiencyAverage(hashrateData: number[], powerData: number[]): number {
if (hashrateData.length === 0 || powerData.length === 0) return 0;
// Calculate efficiency for each data point and average them
const efficiencies = hashrateData.map((hashrate, index) => {
const power = powerData[index] || 0;
return power / (hashrate/1000000000000); // Convert to J/TH
});
return this.calculateAverage(efficiencies);
}
}

View File

@ -12,7 +12,7 @@
<td>{{info.uptimeSeconds | dateAgo}}</td>
</tr>
<tr>
<td>WiFi Status:</td>
<td>Wi-Fi Status:</td>
<td>{{info.wifiStatus}}</td>
</tr>
<tr>

View File

@ -8,20 +8,21 @@
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="ssid" class="col-12 mb-2 md:col-2 md:mb-0">WiFi SSID:</label>
<div class="col-12 md:col-10">
<label htmlFor="ssid" class="col-12 mb-2 md:col-2 md:mb-0">Wi-Fi SSID:</label>
<div class="col-12 md:col-10 p-inputgroup">
<input pInputText id="ssid" type="text" formControlName="ssid" />
<button pButton type="button" icon="pi pi-search" (click)="scanWifi()" [loading]="scanning"></button>
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="wifiPass" class="col-12 mb-2 md:col-2 md:mb-0">WiFi Password:</label>
<label htmlFor="wifiPass" class="col-12 mb-2 md:col-2 md:mb-0">Wi-Fi Password:</label>
<div class="col-12 md:col-10 p-input-icon-right">
<i *ngIf="form.get('wifiPass')?.dirty" class="pi"
[ngClass]="{'pi-eye': !showWifiPassword, 'pi-eye-slash': showWifiPassword}"
(click)="toggleWifiPasswordVisibility()" style="cursor: pointer;"></i>
<input pInputText id="wifiPass" formControlName="wifiPass"
[type]="showWifiPassword ? 'text' : 'password'"
placeholder="Enter WiFi password" />
placeholder="Enter Wi-Fi password" />
</div>
</div>

View File

@ -1,11 +1,18 @@
import { HttpErrorResponse } from '@angular/common/http';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';
import { startWith } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { DialogService } from 'src/app/services/dialog.service';
import { LoadingService } from 'src/app/services/loading.service';
import { SystemService } from 'src/app/services/system.service';
interface WifiNetwork {
ssid: string;
rssi: number;
authmode: number;
}
@Component({
selector: 'app-network-edit',
templateUrl: './network.edit.component.html',
@ -15,6 +22,7 @@ export class NetworkEditComponent implements OnInit {
public form!: FormGroup;
public savedChanges: boolean = false;
public scanning: boolean = false;
@Input() uri = '';
@ -23,7 +31,9 @@ export class NetworkEditComponent implements OnInit {
private systemService: SystemService,
private toastr: ToastrService,
private toastrService: ToastrService,
private loadingService: LoadingService
private loadingService: LoadingService,
private http: HttpClient,
private dialogService: DialogService
) {
}
@ -52,6 +62,11 @@ export class NetworkEditComponent implements OnInit {
delete form.wifiPass;
}
// Trim SSID to remove any leading/trailing whitespace
if (form.ssid) {
form.ssid = form.ssid.trim();
}
this.systemService.updateSystem(this.uri, form)
.pipe(this.loadingService.lockUIUntilComplete())
.subscribe({
@ -71,6 +86,52 @@ export class NetworkEditComponent implements OnInit {
this.showWifiPassword = !this.showWifiPassword;
}
public scanWifi() {
this.scanning = true;
this.http.get<{networks: WifiNetwork[]}>('/api/system/wifi/scan')
.pipe(
finalize(() => this.scanning = false)
)
.subscribe({
next: (response) => {
// Sort networks by signal strength (highest first)
const networks = response.networks.sort((a, b) => b.rssi - a.rssi);
// filter out poor wifi connections
const poorNetworks = networks.filter(network => network.rssi >= -80);
// Remove duplicate Network Names and show highest signal strength only
const uniqueNetworks = poorNetworks.reduce((acc, network) => {
if (!acc[network.ssid] || acc[network.ssid].rssi < network.rssi) {
acc[network.ssid] = network;
}
return acc;
}, {} as { [key: string]: WifiNetwork });
// Convert the object back to an array
const filteredNetworks = Object.values(uniqueNetworks);
// Create dialog data
const dialogData = filteredNetworks.map(n => ({
label: `${n.ssid} (${n.rssi}dBm)`,
value: n.ssid
}));
// Show dialog with network list
this.dialogService.open('Select WiFi Network', dialogData)
.subscribe((selectedSsid: string) => {
if (selectedSsid) {
this.form.patchValue({ ssid: selectedSsid });
this.form.markAsDirty();
}
});
},
error: (err) => {
this.toastr.error('Failed to scan WiFi networks', 'Error');
}
});
}
public restart() {
this.systemService.restart()
.pipe(this.loadingService.lockUIUntilComplete())

View File

@ -0,0 +1,83 @@
<div class="grid">
<div class="col-12">
<div class="card">
<h5>Pool Configuration</h5>
<form [formGroup]="form" *ngIf="form != null">
<div class="field grid p-fluid">
<label htmlFor="stratumURL" class="col-12 mb-2 md:col-2 md:mb-0">Stratum Host:</label>
<div class="col-12 md:col-10">
<input pInputText id="stratumURL" type="text" formControlName="stratumURL" />
<div>
<small>Do not include 'stratum+tcp://' or port.</small>
</div>
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="stratumPort" class="col-12 mb-2 md:col-2 md:mb-0">Stratum Port:</label>
<div class="col-12 md:col-10">
<input pInputText id="stratumPort" formControlName="stratumPort" type="number" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="stratumUser" class="col-12 mb-2 md:col-2 md:mb-0">Stratum User:</label>
<div class="col-12 md:col-10">
<input pInputText id="stratumUser" formControlName="stratumUser" type="text" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="stratumPassword" class="col-12 mb-2 md:col-2 md:mb-0">Stratum Password:</label>
<div class="col-12 md:col-10 p-input-icon-right">
<i *ngIf="form.get('stratumPassword')?.dirty" class="pi"
[ngClass]="{'pi-eye': !showStratumPassword, 'pi-eye-slash': showStratumPassword}"
(click)="toggleStratumPasswordVisibility()" style="cursor: pointer;"></i>
<input pInputText id="stratumPassword" formControlName="stratumPassword"
[type]="showStratumPassword ? 'text' : 'password'"
placeholder="Enter stratum password" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="fallbackStratumURL" class="col-12 mb-2 md:col-2 md:mb-0">Fallback Stratum Host:</label>
<div class="col-12 md:col-10">
<input pInputText id="fallbackStratumURL" type="text" formControlName="fallbackStratumURL" />
<div>
<small>Do not include 'stratum+tcp://' or port.</small>
</div>
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="fallbackStratumPort" class="col-12 mb-2 md:col-2 md:mb-0">Fallback Stratum Port:</label>
<div class="col-12 md:col-10">
<input pInputText id="fallbackStratumPort" formControlName="fallbackStratumPort" type="number" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="fallbackStratumUser" class="col-12 mb-2 md:col-2 md:mb-0">Fallback Stratum User:</label>
<div class="col-12 md:col-10">
<input pInputText id="fallbackStratumUser" formControlName="fallbackStratumUser" type="text" />
</div>
</div>
<div class="field grid p-fluid">
<label htmlFor="fallbackStratumPassword" class="col-12 mb-2 md:col-2 md:mb-0">Fallback Stratum Password:</label>
<div class="col-12 md:col-10 p-input-icon-right">
<i *ngIf="form.get('fallbackStratumPassword')?.dirty" class="pi"
[ngClass]="{'pi-eye': !showFallbackStratumPassword, 'pi-eye-slash': showFallbackStratumPassword}"
(click)="toggleFallbackStratumPasswordVisibility()" style="cursor: pointer;"></i>
<input pInputText id="fallbackStratumPassword" formControlName="fallbackStratumPassword"
[type]="showFallbackStratumPassword ? 'text' : 'password'"
placeholder="Enter fallback stratum password" />
</div>
</div>
<div class="mt-2">
<button pButton [disabled]="!form.dirty || form.invalid" (click)="updateSystem()"
class="btn btn-primary mr-2">Save</button>
<b style="line-height: 34px;">You must restart this device after saving for changes to take effect.</b>
</div>
<div class="mt-2">
<button pButton [disabled]="!savedChanges" (click)="restart()">Restart</button>
</div>
</form>
</div>
</div>
</div>

View File

@ -0,0 +1,5 @@
.pi {
right: 1rem;
font-size: 1.5rem;
top: 1rem;
}

View File

@ -0,0 +1,108 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';
import { LoadingService } from 'src/app/services/loading.service';
import { SystemService } from 'src/app/services/system.service';
@Component({
selector: 'app-pool',
templateUrl: './pool.component.html',
styleUrls: ['./pool.component.scss']
})
export class PoolComponent implements OnInit {
public form!: FormGroup;
public savedChanges: boolean = false;
@Input() uri = '';
constructor(
private fb: FormBuilder,
private systemService: SystemService,
private toastr: ToastrService,
private loadingService: LoadingService
) {}
ngOnInit(): void {
this.systemService.getInfo(this.uri)
.pipe(
this.loadingService.lockUIUntilComplete()
)
.subscribe(info => {
this.form = this.fb.group({
stratumURL: [info.stratumURL, [
Validators.required,
Validators.pattern(/^(?!.*stratum\+tcp:\/\/).*$/),
Validators.pattern(/^[^:]*$/),
]],
stratumPort: [info.stratumPort, [
Validators.required,
Validators.pattern(/^[^:]*$/),
Validators.min(0),
Validators.max(65353)
]],
fallbackStratumURL: [info.fallbackStratumURL, [
Validators.pattern(/^(?!.*stratum\+tcp:\/\/).*$/),
]],
fallbackStratumPort: [info.fallbackStratumPort, [
Validators.required,
Validators.pattern(/^[^:]*$/),
Validators.min(0),
Validators.max(65353)
]],
stratumUser: [info.stratumUser, [Validators.required]],
stratumPassword: ['*****', [Validators.required]],
fallbackStratumUser: [info.fallbackStratumUser, [Validators.required]],
fallbackStratumPassword: ['password', [Validators.required]]
});
});
}
public updateSystem() {
const form = this.form.getRawValue();
if (form.stratumPassword === '*****') {
delete form.stratumPassword;
}
this.systemService.updateSystem(this.uri, form)
.pipe(this.loadingService.lockUIUntilComplete())
.subscribe({
next: () => {
const successMessage = this.uri ? `Saved pool settings for ${this.uri}` : 'Saved pool settings';
this.toastr.success(successMessage, 'Success!');
this.savedChanges = true;
},
error: (err: HttpErrorResponse) => {
const errorMessage = this.uri ? `Could not save pool settings for ${this.uri}. ${err.message}` : `Could not save pool settings. ${err.message}`;
this.toastr.error(errorMessage, 'Error');
this.savedChanges = false;
}
});
}
showStratumPassword: boolean = false;
toggleStratumPasswordVisibility() {
this.showStratumPassword = !this.showStratumPassword;
}
showFallbackStratumPassword: boolean = false;
toggleFallbackStratumPasswordVisibility() {
this.showFallbackStratumPassword = !this.showFallbackStratumPassword;
}
public restart() {
this.systemService.restart(this.uri)
.pipe(this.loadingService.lockUIUntilComplete())
.subscribe({
next: () => {
const successMessage = this.uri ? `Bitaxe at ${this.uri} restarted` : 'Bitaxe restarted';
this.toastr.success(successMessage, 'Success');
},
error: (err: HttpErrorResponse) => {
const errorMessage = this.uri ? `Failed to restart device at ${this.uri}. ${err.message}` : `Failed to restart device. ${err.message}`;
this.toastr.error(errorMessage, 'Error');
}
});
}
}

View File

@ -3,12 +3,6 @@
<app-edit></app-edit>
</div>
<div class="grid">
<div class="col-12">
<app-theme-config></app-theme-config>
</div>
</div>
<div class="grid">
<div class="col-12 lg:col-6 xl:col-4">
<div class="card" *ngIf="checkLatestRelease == false">
@ -34,6 +28,16 @@
</ng-container>
</div>
</div>
<div class="col-12 lg:col-12 xl:col-4">
<div class="card">
<h2>Update Website <span *ngIf="websiteUpdateProgress != null">{{websiteUpdateProgress}}%</span></h2>
<p-fileUpload #websiteUpload [customUpload]="true" mode="basic" accept=".bin" (uploadHandler)="otaWWWUpdate($event)"
[auto]="true" chooseLabel="Browse"></p-fileUpload>
<small>(www.bin)</small>
</div>
</div>
<div class="col-12 lg:col-6 xl:col-4">
<div class="card">
<h2>Update Firmware <span *ngIf="firmwareUpdateProgress != null">{{firmwareUpdateProgress}}%</span></h2>
@ -45,14 +49,4 @@
</div>
</div>
<div class="col-12 lg:col-12 xl:col-4">
<div class="card">
<h2>Update Website <span *ngIf="websiteUpdateProgress != null">{{websiteUpdateProgress}}%</span></h2>
<p-fileUpload #websiteUpload [customUpload]="true" mode="basic" accept=".bin" (uploadHandler)="otaWWWUpdate($event)"
[auto]="true" chooseLabel="Browse"></p-fileUpload>
<small>(www.bin)</small>
</div>
</div>
</div>

View File

@ -22,7 +22,6 @@ export class SettingsComponent {
public websiteUpdateProgress: number | null = null;
public devToolsOpen: boolean = false;
public eASICModel = eASICModel;
public ASICModel!: eASICModel;
@ -45,9 +44,6 @@ export class SettingsComponent {
window.addEventListener('resize', this.checkDevTools);
this.checkDevTools();
this.latestRelease$ = this.githubUpdateService.getReleases().pipe(map(releases => {
return releases[0];
}));
@ -93,17 +89,6 @@ export class SettingsComponent {
});
}
private checkDevTools = () => {
if (
window.outerWidth - window.innerWidth > 160 ||
window.outerHeight - window.innerHeight > 160
) {
this.devToolsOpen = true;
} else {
this.devToolsOpen = false;
}
};
public updateSystem() {
const form = this.form.getRawValue();

View File

@ -48,7 +48,26 @@
<div class="table-container">
<table cellspacing="0" cellpadding="0" class="text-sm md:text-base">
<tr>
<th>IP</th>
<th>
<div class="flex items-center cursor-pointer select-none h-full" (click)="sortBy('IP')">
<span class="flex-1">IP</span>
<i class="pi text-xs flex items-center" [ngClass]="{
'pi-sort-alt': sortField !== 'IP',
'pi-sort-amount-up-alt': sortField === 'IP' && sortDirection === 'asc',
'pi-sort-amount-down': sortField === 'IP' && sortDirection === 'desc'
}"></i>
</div>
</th>
<th>
<div class="flex items-center cursor-pointer select-none h-full" (click)="sortBy('hostname')">
<span class="flex-1">Hostname</span>
<i class="pi text-xs flex items-center" [ngClass]="{
'pi-sort-alt': sortField !== 'hostname',
'pi-sort-amount-up-alt': sortField === 'hostname' && sortDirection === 'asc',
'pi-sort-amount-down': sortField === 'hostname' && sortDirection === 'desc'
}"></i>
</div>
</th>
<th>Hash Rate</th>
<th>Uptime</th>
<th>Shares</th>
@ -63,9 +82,21 @@
<ng-container *ngFor="let axe of swarm">
<tr>
<td>
<a class="text-primary" [href]="'http://'+axe.IP" target="_blank">{{axe.IP}}</a>
<div class="text-sm">{{axe.hostname}}</div>
<a
[ngClass]="[
axe.asicCount > 1 ? 'text-orange-500' :
axe.ASICModel === 'BM1397' ? 'text-red-500' :
axe.ASICModel === 'BM1366' ? 'text-purple-500' :
axe.ASICModel === 'BM1368' ? 'text-blue-500' :
axe.ASICModel === 'BM1370' ? 'text-green-500' :
''
]"
[href]="'http://'+axe.IP"
target="_blank"
[pTooltip]="axe.ASICModel"
tooltipPosition="top">{{axe.IP}}</a>
</td>
<td>{{axe.hostname}}</td>
<td>{{axe.hashRate * 1000000000 | hashSuffix}}</td>
<td>{{axe.uptimeSeconds | dateAgo: {intervals: 2} }}</td>
<td>
@ -102,12 +133,36 @@
</div>
</td>
<td>{{axe.version}}</td>
<td><p-button icon="pi pi-pencil" pp-button (click)="edit(axe)"></p-button></td>
<td><p-button icon="pi pi-pencil" pp-button (click)="edit(axe)"></p-button></td>
<td><p-button icon="pi pi-sync" pp-button severity="danger" (click)="restart(axe)"></p-button></td>
<td><p-button icon="pi pi-trash" pp-button severity="secondary" (click)="remove(axe)"></p-button></td>
</tr>
</ng-container>
</table>
<div class="flex flex-wrap gap-2 mt-3 text-sm justify-content-center">
<div class="flex align-items-center gap-1" [style.opacity]="hasModel('BM1397')">
<span class="text-red-500"></span>
<span>BM1397 (Max)</span>
</div>
<div class="flex align-items-center gap-1" [style.opacity]="hasModel('BM1366')">
<span class="text-purple-500"></span>
<span>BM1366 (Ultra)</span>
</div>
<div class="flex align-items-center gap-1" [style.opacity]="hasModel('BM1368')">
<span class="text-blue-500"></span>
<span>BM1368 (Supra)</span>
</div>
<div class="flex align-items-center gap-1" [style.opacity]="hasModel('BM1370')">
<span class="text-green-500"></span>
<span>BM1370 (Gamma)</span>
</div>
<div class="flex align-items-center gap-1" [style.opacity]="hasMultipleChips()">
<span class="text-orange-500"></span>
<span>Multiple Chip Device</span>
</div>
</div>
</div>
<div class="modal-backdrop" *ngIf="showEdit" (click)="showEdit = false"></div>

View File

@ -6,15 +6,40 @@ table {
th {
text-align: left;
background-color: #1f2d40;
}
padding: 0;
> div {
height: 100%;
padding: 0.5rem 1rem;
gap: 0.75rem;
}
.pi {
opacity: 0.7;
height: 1em;
line-height: 1;
&.pi-sort-amount-up-alt,
&.pi-sort-amount-down {
opacity: 1;
}
}
}
th,
td {
padding: 1rem 1rem;
border-bottom: 1px solid #304562;
}
td {
padding: 1rem;
}
th > div {
min-width: 100px;
padding-right: 0.5rem;
}
a {
color: white;
}

View File

@ -33,6 +33,9 @@ export class SwarmComponent implements OnInit, OnDestroy {
public refreshIntervalControl: FormControl;
public sortField: string = '';
public sortDirection: 'asc' | 'desc' = 'asc';
constructor(
private fb: FormBuilder,
private systemService: SystemService,
@ -169,12 +172,12 @@ export class SwarmComponent implements OnInit, OnDestroy {
public restart(axe: any) {
this.systemService.restart(`http://${axe.IP}`).pipe(
catchError(error => {
this.toastr.error('Failed to restart device', 'Error');
this.toastr.error(`Failed to restart device at ${axe.IP}`, 'Error');
return of(null);
})
).subscribe(res => {
if (res !== null) {
this.toastr.success('Bitaxe restarted', 'Success');
this.toastr.success(`Bitaxe at ${axe.IP} restarted`, 'Success');
}
});
}
@ -242,6 +245,35 @@ export class SwarmComponent implements OnInit, OnDestroy {
return this.ipToInt(a.IP) - this.ipToInt(b.IP);
}
sortBy(field: string) {
// If clicking the same field, toggle direction
if (this.sortField === field) {
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
} else {
// New field, set to ascending by default
this.sortField = field;
this.sortDirection = 'asc';
}
this.swarm.sort((a, b) => {
let comparison = 0;
if (field === 'IP') {
// Split IP into octets and compare numerically
const aOctets = a[field].split('.').map(Number);
const bOctets = b[field].split('.').map(Number);
for (let i = 0; i < 4; i++) {
if (aOctets[i] !== bOctets[i]) {
comparison = aOctets[i] - bOctets[i];
break;
}
}
} else {
comparison = a[field].localeCompare(b[field], undefined, { numeric: true });
}
return this.sortDirection === 'asc' ? comparison : -comparison;
});
}
private convertBestDiffToNumber(bestDiff: string): number {
if (!bestDiff) return 0;
const value = parseFloat(bestDiff);
@ -270,4 +302,12 @@ export class SwarmComponent implements OnInit, OnDestroy {
this.totals.bestDiff = this.formatBestDiff(maxDiff);
}
hasModel(model: string): string {
return this.swarm.some(axe => axe.ASICModel === model) ? '1' : '0.5';
}
hasMultipleChips(): string {
return this.swarm.some(axe => axe.asicCount > 1) ? '1' : '0.5';
}
}

View File

@ -0,0 +1,20 @@
import { CanActivateFn, Router } from '@angular/router';
import { inject } from '@angular/core';
import { Observable, map, catchError, of } from 'rxjs';
import { SystemService } from '../services/system.service';
export const ApModeGuard: CanActivateFn = (): Observable<boolean> => {
const systemService = inject(SystemService);
const router = inject(Router);
return systemService.getInfo().pipe(
map(info => {
if (info.apEnabled) {
router.navigate(['/ap']);
return false;
}
return true;
}),
catchError(() => of(true))
);
};

View File

@ -1,6 +1,6 @@
<div class="layout-wrapper" [ngClass]="containerClass">
<app-topbar></app-topbar>
<div class="layout-sidebar">
<app-topbar [isAPMode]="isAPMode"></app-topbar>
<div class="layout-sidebar" *ngIf="!isAPMode">
<app-sidebar></app-sidebar>
</div>
<div class="layout-main-container">

View File

@ -109,6 +109,10 @@ export class AppLayoutComponent implements OnDestroy {
}
}
get isAPMode(): boolean {
return this.router.url.startsWith('/ap');
}
ngOnDestroy() {
if (this.overlayMenuOpenSubscription) {
this.overlayMenuOpenSubscription.unsubscribe();

View File

@ -25,6 +25,8 @@ export class AppMenuComponent implements OnInit {
{ label: 'Dashboard', icon: 'pi pi-fw pi-home', routerLink: ['/'] },
{ label: 'Swarm', icon: 'pi pi-fw pi-share-alt', routerLink: ['swarm'] },
{ label: 'Network', icon: 'pi pi-fw pi-wifi', routerLink: ['network'] },
{ label: 'Pool Settings', icon: 'pi pi-fw pi-server', routerLink: ['pool'] },
{ label: 'Customization', icon: 'pi pi-fw pi-palette', routerLink: ['design'] },
{ label: 'Settings', icon: 'pi pi-fw pi-cog', routerLink: ['settings'] },
{ label: 'Logs', icon: 'pi pi-fw pi-list', routerLink: ['logs'] },
]

View File

@ -3,7 +3,7 @@
<div [routerLink]="['/']" class="header-text"><span style="font-family: Angel Wish; font-size: 4rem;">Axe</span><span class="os" style=" font-size: 3rem;">OS</span></div>
</a>
<button #menubutton class="p-link layout-menu-button layout-topbar-button" (click)="layoutService.onMenuToggle()">
<button *ngIf="!isAPMode" #menubutton class="p-link layout-menu-button layout-topbar-button" (click)="layoutService.onMenuToggle()">
<i class="pi pi-bars"></i>
</button>

View File

@ -1,4 +1,4 @@
import { Component, ElementRef, ViewChild } from '@angular/core';
import { Component, ElementRef, Input, ViewChild } from '@angular/core';
import { MenuItem } from 'primeng/api';
import { LayoutService } from './service/app.layout.service';
@ -11,6 +11,8 @@ export class AppTopBarComponent {
items!: MenuItem[];
@Input() isAPMode: boolean = false;
@ViewChild('menubutton') menuButton!: ElementRef;
@ViewChild('topbarmenubutton') topbarMenuButton!: ElementRef;

View File

@ -0,0 +1,58 @@
import { Component, Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { DialogService as PrimeDialogService, DynamicDialogConfig } from 'primeng/dynamicdialog';
interface DialogOption {
label: string;
value: string;
}
@Injectable({
providedIn: 'root'
})
export class DialogService {
constructor(private primeDialogService: PrimeDialogService) {}
open(title: string, options: DialogOption[]): Observable<string> {
const result = new Subject<string>();
const ref = this.primeDialogService.open(DialogListComponent, {
header: title,
width: '400px',
data: {
options: options,
onSelect: (value: string) => {
result.next(value);
ref.close();
}
}
});
ref.onClose.subscribe(() => {
result.complete();
});
return result.asObservable();
}
}
@Component({
template: `
<style>
::ng-deep .p-button:focus {
box-shadow: none !important;
background-color: var(--primary-color) !important;
}
</style>
<div class="flex flex-column gap-2">
<p-button *ngFor="let option of config.data.options"
[label]="option.label"
(onClick)="config.data.onSelect(option.value)"
styleClass="w-full text-left"
></p-button>
</div>
`
})
export class DialogListComponent {
constructor(public config: DynamicDialogConfig) {}
}

View File

@ -23,7 +23,7 @@ export class GithubUpdateService {
public getReleases(): Observable<GithubRelease[]> {
return this.httpClient.get<GithubRelease[]>(
'https://api.github.com/repos/skot/esp-miner/releases'
'https://api.github.com/repos/bitaxeorg/esp-miner/releases'
).pipe(
map((releases: GithubRelease[]) => releases.filter((release: GithubRelease) => !release.prerelease))
);

View File

@ -37,8 +37,10 @@ export class SystemService {
ssid: "default",
wifiPass: "password",
wifiStatus: "Connected!",
apEnabled: 0,
sharesAccepted: 1,
sharesRejected: 0,
sharesRejectedReasons: [],
uptimeSeconds: 38,
asicCount: 1,
smallCoreCount: 672,

View File

@ -1,6 +1,9 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../../environments/environment';
import { of } from 'rxjs';
import { catchError, shareReplay } from 'rxjs/operators';
export interface ThemeSettings {
colorScheme: string;
@ -14,15 +17,64 @@ export interface ThemeSettings {
providedIn: 'root'
})
export class ThemeService {
private themeSettings$ = this.http.get<ThemeSettings>('/api/theme').pipe(
catchError(() => of(this.mockSettings)),
shareReplay({
bufferSize: 1,
refCount: true,
windowTime: 1000 // 1 second cache
})
);
private readonly mockSettings: ThemeSettings = {
colorScheme: 'dark',
theme: 'dark',
accentColors: {
'--primary-color': '#F80421',
'--primary-color-text': '#ffffff',
'--highlight-bg': '#F80421',
'--highlight-text-color': '#ffffff',
'--focus-ring': '0 0 0 0.2rem rgba(255,64,50,0.2)',
// PrimeNG Slider
'--slider-bg': '#dee2e6',
'--slider-range-bg': '#F80421',
'--slider-handle-bg': '#F80421',
// Progress Bar
'--progressbar-bg': '#dee2e6',
'--progressbar-value-bg': '#F80421',
// PrimeNG Checkbox
'--checkbox-border': '#F80421',
'--checkbox-bg': '#F80421',
'--checkbox-hover-bg': '#e63c2e',
// PrimeNG Button
'--button-bg': '#F80421',
'--button-hover-bg': '#e63c2e',
'--button-focus-shadow': '0 0 0 2px #ffffff, 0 0 0 4px #F80421',
// Toggle button
'--togglebutton-bg': '#F80421',
'--togglebutton-border': '1px solid #F80421',
'--togglebutton-hover-bg': '#e63c2e',
'--togglebutton-hover-border': '1px solid #e63c2e',
'--togglebutton-text-color': '#ffffff'
}
};
constructor(private http: HttpClient) {}
// Get theme settings from NVS storage
getThemeSettings(): Observable<ThemeSettings> {
return this.http.get<ThemeSettings>('/api/theme');
if (!environment.production) {
return of(this.mockSettings);
}
return this.themeSettings$;
}
// Save theme settings to NVS storage
saveThemeSettings(settings: ThemeSettings): Observable<void> {
return this.http.post<void>('/api/theme', settings);
if (environment.production) {
return this.http.post<void>('/api/theme', settings);
} else {
return of(void 0);
}
}
}

View File

@ -1,5 +1,10 @@
import { eASICModel } from './enum/eASICModel';
interface ISharesRejectedStat {
message: string;
count: number;
}
export interface ISystemInfo {
flipscreen: number;
@ -18,8 +23,10 @@ export interface ISystemInfo {
macAddr: string,
ssid: string,
wifiStatus: string,
apEnabled: number,
sharesAccepted: number,
sharesRejected: number,
sharesRejectedReasons: ISharesRejectedStat[];
uptimeSeconds: number,
asicCount: number,
smallCoreCount: number,
@ -43,5 +50,6 @@ export interface ISystemInfo {
boardtemp1?: number,
boardtemp2?: number,
overheat_mode: number
overheat_mode: number,
overclockEnabled?: number
}

View File

@ -1,5 +1,4 @@
#include "http_server.h"
#include "recovery_page.h"
#include "theme_api.h" // Add theme API include
#include "cJSON.h"
#include "esp_chip_info.h"
@ -16,6 +15,8 @@
#include "global_state.h"
#include "nvs_config.h"
#include "vcore.h"
#include "power.h"
#include "connect.h"
#include <fcntl.h>
#include <string.h>
#include <sys/param.h>
@ -32,10 +33,51 @@
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <pthread.h>
#include "connect.h"
#include "asic.h"
static const char * TAG = "http_server";
static const char * CORS_TAG = "CORS";
/* Handler for WiFi scan endpoint */
static esp_err_t GET_wifi_scan(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Give some time for the connected flag to take effect
vTaskDelay(100 / portTICK_PERIOD_MS);
wifi_ap_record_simple_t ap_records[20];
uint16_t ap_count = 0;
esp_err_t err = wifi_scan(ap_records, &ap_count);
if (err != ESP_OK) {
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "WiFi scan failed");
return ESP_OK;
}
cJSON *root = cJSON_CreateObject();
cJSON *networks = cJSON_CreateArray();
for (int i = 0; i < ap_count; i++) {
cJSON *network = cJSON_CreateObject();
cJSON_AddStringToObject(network, "ssid", (char *)ap_records[i].ssid);
cJSON_AddNumberToObject(network, "rssi", ap_records[i].rssi);
cJSON_AddNumberToObject(network, "authmode", ap_records[i].authmode);
cJSON_AddItemToArray(networks, network);
}
cJSON_AddItemToObject(root, "networks", networks);
const char *response = cJSON_Print(root);
httpd_resp_sendstr(req, response);
free((void *)response);
cJSON_Delete(root);
return ESP_OK;
}
static GlobalState * GLOBAL_STATE;
static httpd_handle_t server = NULL;
QueueHandle_t log_queue = NULL;
@ -83,19 +125,11 @@ static esp_err_t ip_in_private_range(uint32_t address) {
return ESP_FAIL;
}
static uint32_t extract_origin_ip_addr(httpd_req_t *req)
static uint32_t extract_origin_ip_addr(char *origin)
{
char origin[128];
char ip_str[16];
uint32_t origin_ip_addr = 0;
// Attempt to get the Origin header.
if (httpd_req_get_hdr_value_str(req, "Origin", origin, sizeof(origin)) != ESP_OK) {
ESP_LOGD(CORS_TAG, "No origin header found.");
return 0;
}
ESP_LOGD(CORS_TAG, "Origin header: %s", origin);
// Find the start of the IP address in the Origin header
const char *prefix = "http://";
char *ip_start = strstr(origin, prefix);
@ -149,8 +183,14 @@ static esp_err_t is_network_allowed(httpd_req_t * req)
// Convert to IPv4 string
inet_ntop(AF_INET, &request_ip_addr, ipstr, sizeof(ipstr));
uint32_t origin_ip_addr = extract_origin_ip_addr(req);
if (origin_ip_addr == 0) {
// Attempt to get the Origin header.
char origin[128];
uint32_t origin_ip_addr;
if (httpd_req_get_hdr_value_str(req, "Origin", origin, sizeof(origin)) == ESP_OK) {
ESP_LOGD(CORS_TAG, "Origin header: %s", origin);
origin_ip_addr = extract_origin_ip_addr(origin);
} else {
ESP_LOGD(CORS_TAG, "No origin header found.");
origin_ip_addr = request_ip_addr;
}
@ -247,7 +287,11 @@ static esp_err_t rest_recovery_handler(httpd_req_t * req)
return httpd_resp_send_err(req, HTTPD_401_UNAUTHORIZED, "Unauthorized");
}
httpd_resp_send(req, recovery_page, HTTPD_RESP_USE_STRLEN);
extern const unsigned char recovery_page_start[] asm("_binary_recovery_page_html_start");
extern const unsigned char recovery_page_end[] asm("_binary_recovery_page_html_end");
const size_t recovery_page_size = (recovery_page_end - recovery_page_start);
httpd_resp_send_chunk(req, (const char*)recovery_page_start, recovery_page_size);
httpd_resp_send_chunk(req, NULL, 0);
return ESP_OK;
}
@ -371,22 +415,22 @@ static esp_err_t PATCH_update_settings(httpd_req_t * req)
return ESP_OK;
}
if ((item = cJSON_GetObjectItem(root, "stratumURL")) != NULL) {
if (cJSON_IsString(item = cJSON_GetObjectItem(root, "stratumURL"))) {
nvs_config_set_string(NVS_CONFIG_STRATUM_URL, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "fallbackStratumURL")) != NULL) {
if (cJSON_IsString(item = cJSON_GetObjectItem(root, "fallbackStratumURL"))) {
nvs_config_set_string(NVS_CONFIG_FALLBACK_STRATUM_URL, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "stratumUser")) != NULL) {
if (cJSON_IsString(item = cJSON_GetObjectItem(root, "stratumUser"))) {
nvs_config_set_string(NVS_CONFIG_STRATUM_USER, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "stratumPassword")) != NULL) {
if (cJSON_IsString(item = cJSON_GetObjectItem(root, "stratumPassword"))) {
nvs_config_set_string(NVS_CONFIG_STRATUM_PASS, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "fallbackStratumUser")) != NULL) {
if (cJSON_IsString(item = cJSON_GetObjectItem(root, "fallbackStratumUser"))) {
nvs_config_set_string(NVS_CONFIG_FALLBACK_STRATUM_USER, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "fallbackStratumPassword")) != NULL) {
if (cJSON_IsString(item = cJSON_GetObjectItem(root, "fallbackStratumPassword"))) {
nvs_config_set_string(NVS_CONFIG_FALLBACK_STRATUM_PASS, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "stratumPort")) != NULL) {
@ -395,13 +439,13 @@ static esp_err_t PATCH_update_settings(httpd_req_t * req)
if ((item = cJSON_GetObjectItem(root, "fallbackStratumPort")) != NULL) {
nvs_config_set_u16(NVS_CONFIG_FALLBACK_STRATUM_PORT, item->valueint);
}
if ((item = cJSON_GetObjectItem(root, "ssid")) != NULL) {
if (cJSON_IsString(item = cJSON_GetObjectItem(root, "ssid"))) {
nvs_config_set_string(NVS_CONFIG_WIFI_SSID, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "wifiPass")) != NULL) {
if (cJSON_IsString(item = cJSON_GetObjectItem(root, "wifiPass"))) {
nvs_config_set_string(NVS_CONFIG_WIFI_PASS, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "hostname")) != NULL) {
if (cJSON_IsString(item = cJSON_GetObjectItem(root, "hostname"))) {
nvs_config_set_string(NVS_CONFIG_HOSTNAME, item->valuestring);
}
if ((item = cJSON_GetObjectItem(root, "coreVoltage")) != NULL && item->valueint > 0) {
@ -428,6 +472,9 @@ static esp_err_t PATCH_update_settings(httpd_req_t * req)
if ((item = cJSON_GetObjectItem(root, "fanspeed")) != NULL) {
nvs_config_set_u16(NVS_CONFIG_FAN_SPEED, item->valueint);
}
if ((item = cJSON_GetObjectItem(root, "overclockEnabled")) != NULL) {
nvs_config_set_u16(NVS_CONFIG_OVERCLOCK_ENABLED, item->valueint);
}
cJSON_Delete(root);
httpd_resp_send_chunk(req, NULL, 0);
@ -487,6 +534,8 @@ static esp_err_t GET_system_info(httpd_req_t * req)
char * stratumUser = nvs_config_get_string(NVS_CONFIG_STRATUM_USER, CONFIG_STRATUM_USER);
char * fallbackStratumUser = nvs_config_get_string(NVS_CONFIG_FALLBACK_STRATUM_USER, CONFIG_FALLBACK_STRATUM_USER);
char * board_version = nvs_config_get_string(NVS_CONFIG_BOARD_VERSION, "unknown");
uint16_t freq = nvs_config_get_u16(NVS_CONFIG_ASIC_FREQ, CONFIG_ASIC_FREQUENCY);
float expected_hashrate = freq * ((ASIC_get_small_core_count(GLOBAL_STATE) * ASIC_get_asic_count(GLOBAL_STATE)) / 1000.0);
esp_wifi_get_mac(WIFI_IF_STA, mac);
snprintf(formattedMac, 18, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
@ -494,48 +543,44 @@ static esp_err_t GET_system_info(httpd_req_t * req)
cJSON * root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "power", GLOBAL_STATE->POWER_MANAGEMENT_MODULE.power);
cJSON_AddNumberToObject(root, "voltage", GLOBAL_STATE->POWER_MANAGEMENT_MODULE.voltage);
cJSON_AddNumberToObject(root, "current", GLOBAL_STATE->POWER_MANAGEMENT_MODULE.current);
cJSON_AddNumberToObject(root, "current", Power_get_current(GLOBAL_STATE));
cJSON_AddNumberToObject(root, "temp", GLOBAL_STATE->POWER_MANAGEMENT_MODULE.chip_temp_avg);
cJSON_AddNumberToObject(root, "vrTemp", GLOBAL_STATE->POWER_MANAGEMENT_MODULE.vr_temp);
cJSON_AddNumberToObject(root, "hashRate", GLOBAL_STATE->SYSTEM_MODULE.current_hashrate);
cJSON_AddNumberToObject(root, "expectedHashrate", expected_hashrate);
cJSON_AddStringToObject(root, "bestDiff", GLOBAL_STATE->SYSTEM_MODULE.best_diff_string);
cJSON_AddStringToObject(root, "bestSessionDiff", GLOBAL_STATE->SYSTEM_MODULE.best_session_diff_string);
cJSON_AddNumberToObject(root, "stratumDiff", GLOBAL_STATE->stratum_difficulty);
cJSON_AddNumberToObject(root, "isUsingFallbackStratum", GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback);
cJSON_AddNumberToObject(root, "isPSRAMAvailable", GLOBAL_STATE->psram_is_available);
cJSON_AddNumberToObject(root, "freeHeap", esp_get_free_heap_size());
cJSON_AddNumberToObject(root, "coreVoltage", nvs_config_get_u16(NVS_CONFIG_ASIC_VOLTAGE, CONFIG_ASIC_VOLTAGE));
cJSON_AddNumberToObject(root, "coreVoltageActual", VCORE_get_voltage_mv(GLOBAL_STATE));
cJSON_AddNumberToObject(root, "frequency", nvs_config_get_u16(NVS_CONFIG_ASIC_FREQ, CONFIG_ASIC_FREQUENCY));
cJSON_AddNumberToObject(root, "frequency", freq);
cJSON_AddStringToObject(root, "ssid", ssid);
cJSON_AddStringToObject(root, "macAddr", formattedMac);
cJSON_AddStringToObject(root, "hostname", hostname);
cJSON_AddStringToObject(root, "wifiStatus", GLOBAL_STATE->SYSTEM_MODULE.wifi_status);
cJSON_AddNumberToObject(root, "apEnabled", GLOBAL_STATE->SYSTEM_MODULE.ap_enabled);
cJSON_AddNumberToObject(root, "sharesAccepted", GLOBAL_STATE->SYSTEM_MODULE.shares_accepted);
cJSON_AddNumberToObject(root, "sharesRejected", GLOBAL_STATE->SYSTEM_MODULE.shares_rejected);
cJSON_AddNumberToObject(root, "uptimeSeconds", (esp_timer_get_time() - GLOBAL_STATE->SYSTEM_MODULE.start_time) / 1000000);
cJSON_AddNumberToObject(root, "asicCount", GLOBAL_STATE->asic_count);
uint16_t small_core_count = 0;
switch (GLOBAL_STATE->asic_model){
case ASIC_BM1397:
small_core_count = BM1397_SMALL_CORE_COUNT;
break;
case ASIC_BM1366:
small_core_count = BM1366_SMALL_CORE_COUNT;
break;
case ASIC_BM1368:
small_core_count = BM1368_SMALL_CORE_COUNT;
break;
case ASIC_BM1370:
small_core_count = BM1370_SMALL_CORE_COUNT;
break;
case ASIC_UNKNOWN:
default:
small_core_count = -1;
break;
cJSON *error_array = cJSON_CreateArray();
cJSON_AddItemToObject(root, "sharesRejectedReasons", error_array);
for (int i = 0; i < GLOBAL_STATE->SYSTEM_MODULE.rejected_reason_stats_count; i++) {
cJSON *error_obj = cJSON_CreateObject();
cJSON_AddStringToObject(error_obj, "message", GLOBAL_STATE->SYSTEM_MODULE.rejected_reason_stats[i].message);
cJSON_AddNumberToObject(error_obj, "count", GLOBAL_STATE->SYSTEM_MODULE.rejected_reason_stats[i].count);
cJSON_AddItemToArray(error_array, error_obj);
}
cJSON_AddNumberToObject(root, "smallCoreCount", small_core_count);
cJSON_AddNumberToObject(root, "uptimeSeconds", (esp_timer_get_time() - GLOBAL_STATE->SYSTEM_MODULE.start_time) / 1000000);
cJSON_AddNumberToObject(root, "asicCount", ASIC_get_asic_count(GLOBAL_STATE));
cJSON_AddNumberToObject(root, "smallCoreCount", ASIC_get_small_core_count(GLOBAL_STATE));
cJSON_AddStringToObject(root, "ASICModel", GLOBAL_STATE->asic_model_str);
cJSON_AddStringToObject(root, "stratumURL", stratumURL);
cJSON_AddStringToObject(root, "fallbackStratumURL", fallbackStratumURL);
@ -551,6 +596,7 @@ static esp_err_t GET_system_info(httpd_req_t * req)
cJSON_AddNumberToObject(root, "flipscreen", nvs_config_get_u16(NVS_CONFIG_FLIP_SCREEN, 1));
cJSON_AddNumberToObject(root, "overheat_mode", nvs_config_get_u16(NVS_CONFIG_OVERHEAT_MODE, 0));
cJSON_AddNumberToObject(root, "overclockEnabled", nvs_config_get_u16(NVS_CONFIG_OVERCLOCK_ENABLED, 0));
cJSON_AddNumberToObject(root, "invertscreen", nvs_config_get_u16(NVS_CONFIG_INVERT_SCREEN, 0));
cJSON_AddNumberToObject(root, "invertfanpolarity", nvs_config_get_u16(NVS_CONFIG_INVERT_FAN_POLARITY, 1));
@ -588,6 +634,10 @@ esp_err_t POST_WWW_update(httpd_req_t * req)
return ESP_OK;
}
GLOBAL_STATE->SYSTEM_MODULE.is_firmware_update = true;
snprintf(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_filename, 20, "www.bin");
snprintf(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_status, 20, "Starting...");
char buf[1000];
int remaining = req->content_len;
@ -613,19 +663,30 @@ esp_err_t POST_WWW_update(httpd_req_t * req)
if (recv_len == HTTPD_SOCK_ERR_TIMEOUT) {
continue;
} else if (recv_len <= 0) {
snprintf(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_status, 20, "Protocol Error");
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Protocol Error");
return ESP_OK;
}
if (esp_partition_write(www_partition, www_partition->size - remaining, (const void *) buf, recv_len) != ESP_OK) {
snprintf(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_status, 20, "Write Error");
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Write Error");
return ESP_OK;
}
uint8_t percentage = 100 - ((remaining * 100 / req->content_len));
snprintf(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_status, 20, "Working (%d%%)", percentage);
remaining -= recv_len;
}
httpd_resp_sendstr(req, "WWW update complete\n");
snprintf(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_status, 20, "Finished...");
vTaskDelay(1000 / portTICK_PERIOD_MS);
GLOBAL_STATE->SYSTEM_MODULE.is_firmware_update = false;
return ESP_OK;
}
@ -646,6 +707,10 @@ esp_err_t POST_OTA_update(httpd_req_t * req)
return ESP_OK;
}
GLOBAL_STATE->SYSTEM_MODULE.is_firmware_update = true;
snprintf(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_filename, 20, "esp-miner.bin");
snprintf(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_status, 20, "Starting...");
char buf[1000];
esp_ota_handle_t ota_handle;
int remaining = req->content_len;
@ -662,6 +727,7 @@ esp_err_t POST_OTA_update(httpd_req_t * req)
// Serious Error: Abort OTA
} else if (recv_len <= 0) {
snprintf(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_status, 20, "Protocol Error");
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Protocol Error");
return ESP_OK;
}
@ -669,19 +735,27 @@ esp_err_t POST_OTA_update(httpd_req_t * req)
// Successful Upload: Flash firmware chunk
if (esp_ota_write(ota_handle, (const void *) buf, recv_len) != ESP_OK) {
esp_ota_abort(ota_handle);
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Flash Error");
snprintf(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_status, 20, "Write Error");
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Write Error");
return ESP_OK;
}
uint8_t percentage = 100 - ((remaining * 100 / req->content_len));
snprintf(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_status, 20, "Working (%d%%)", percentage);
remaining -= recv_len;
}
// Validate and switch to new OTA image and reboot
if (esp_ota_end(ota_handle) != ESP_OK || esp_ota_set_boot_partition(ota_partition) != ESP_OK) {
snprintf(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_status, 20, "Validation Error");
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Validation / Activation Error");
return ESP_OK;
}
snprintf(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_status, 20, "Rebooting...");
httpd_resp_sendstr(req, "Firmware update complete, rebooting now!\n");
ESP_LOGI(TAG, "Restarting System because of Firmware update complete");
vTaskDelay(1000 / portTICK_PERIOD_MS);
@ -828,6 +902,7 @@ esp_err_t start_rest_server(void * pvParameters)
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.uri_match_fn = httpd_uri_match_wildcard;
config.stack_size = 8192;
config.max_open_sockets = 10;
config.max_uri_handlers = 20;
@ -854,6 +929,15 @@ esp_err_t start_rest_server(void * pvParameters)
};
httpd_register_uri_handler(server, &system_info_get_uri);
/* URI handler for WiFi scan */
httpd_uri_t wifi_scan_get_uri = {
.uri = "/api/system/wifi/scan",
.method = HTTP_GET,
.handler = GET_wifi_scan,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &wifi_scan_get_uri);
httpd_uri_t swarm_options_uri = {
.uri = "/api/swarm",
.method = HTTP_OPTIONS,

View File

@ -1,79 +0,0 @@
#ifndef RECOVERY_PAGE
#define RECOVERY_PAGE
const char recovery_page[] = "<html>"
"<style>"
"body {"
" background-color: #000;"
" color: #00ff00;"
" font-family: courier new;"
"}"
"</style>"
"<head>"
"<title>AxeOS Recovery</title>"
"</head>"
"<body>"
"<pre>"
" ____ _____\n"
" /\\ / __ \\ / ____|\n"
" / \\ __ _____| | | | (___\n"
" / /\\ \\ \\ \\/ / _ \\ | | |\\___ \\\n"
" / ____ \\ > < __/ |__| |____) |\n"
" /_/___ \\_\\/_/\\_\\___|\\____/|_____/\n"
" | __ \\\n"
" | |__) |___ ___ _____ _____ _ __ _ _\n"
" | _ // _ \\/ __/ _ \\ \\ / / _ \\ '__| | | |\n"
" | | \\ \\ __/ (_| (_) \\ V / __/ | | |_| |\n"
" |_| \\_\\___|\\___\\___/ \\_/ \\___|_| \\__, |\n"
" __/ |\n"
" |___/\n"
"</pre>"
"<p>Please upload www.bin to recover AxeOS</p>"
"<p>After clicking upload, please wait 60 seconds<br>"
"DO NOT restart the device until response is received</p>"
"<input type=\"file\" id=\"wwwfile\" name=\"wwwfile\"><br>"
"<button id=\"upload\">Upload</button>"
"<small id=\"status\"></small>"
"<br><button id=\"restart\">Restart</button>"
"<br><br>Response:<br>"
"<small id=\"response\"></small>"
"<script>"
"document.getElementById('upload').addEventListener('click', handleUpload);"
"statusMsg = document.getElementById('status');"
"responseMsg = document.getElementById('response');"
"function handleUpload() {"
" const fileInput = document.getElementById('wwwfile');"
" const file = fileInput.files[0];"
" const uploadUrl = '/api/system/OTAWWW';"
" const upload_xhr = new XMLHttpRequest();"
" upload_xhr.open('POST', uploadUrl, true);"
" upload_xhr.setRequestHeader('Content-Type', 'application/octet-stream');"
" upload_xhr.onload = function() {"
" const responseBody = upload_xhr.responseText;"
" if (upload_xhr.status === 200) {"
" statusMsg.innerHTML = 'Upload successful!';"
" } else {"
" statusMsg.innerHTML='Error uploading!';"
" }"
" responseMsg.innerHTML = responseBody;"
" };"
" statusMsg.innerHTML = 'uploading...';"
" upload_xhr.send(file);"
"}"
"document.getElementById('restart').addEventListener('click', handleRestart);"
"function handleRestart() {"
" const restartUrl = '/api/system/restart';"
" const restart_xhr = new XMLHttpRequest();"
" restart_xhr.open('POST', restartUrl, true);"
" restart_xhr.setRequestHeader('Content-Type', '');"
" restart_xhr.onload = function() {"
" const responseBody = restart_xhr.responseText;"
" responseMsg.innerHTML = responseBody;"
" };"
" restart_xhr.send(null);"
"}"
"</script>"
"</body>"
"</html>";
#endif

View File

@ -0,0 +1,74 @@
<html>
<style>
body {
background-color: #000;
color: #00ff00;
font-family: courier new;
}
</style>
<head>
<title>AxeOS Recovery</title>
</head>
<body>
<pre>
____ _____
/\ / __ \ / ____|
/ \ __ _____| | | | (___
/ /\ \ \ \/ / _ \ | | |\___ \
/ ____ \ > < __/ |__| |____) |
/_/___ \_\/_/\_\___|\____/|_____/
| __ \
| |__) |___ ___ _____ _____ _ __ _ _
| _ // _ \/ __/ _ \ \ / / _ \ '__| | | |
| | \ \ __/ (_| (_) \ V / __/ | | |_| |
|_| \_\___|\___\___/ \_/ \___|_| \__, |
__/ |
|___/
</pre>
<p>Please upload www.bin to recover AxeOS</p>
<p>After clicking upload, please wait 60 seconds<br>
DO NOT restart the device until response is received</p>
<input type="file" id="wwwfile" name="wwwfile"><br>
<button id="upload">Upload</button>
<small id="status"></small>
<br><button id="restart">Restart</button>
<br><br>Response:<br>
<small id="response"></small>
<script>
document.getElementById('upload').addEventListener('click', handleUpload);
statusMsg = document.getElementById('status');
responseMsg = document.getElementById('response');
function handleUpload() {
const fileInput = document.getElementById('wwwfile');
const file = fileInput.files[0];
const uploadUrl = '/api/system/OTAWWW';
const upload_xhr = new XMLHttpRequest();
upload_xhr.open('POST', uploadUrl, true);
upload_xhr.setRequestHeader('Content-Type', 'application/octet-stream');
upload_xhr.onload = function() {
const responseBody = upload_xhr.responseText;
if (upload_xhr.status === 200) {
statusMsg.innerHTML = 'Upload successful!';
} else {
statusMsg.innerHTML='Error uploading!';
}
responseMsg.innerHTML = responseBody;
};
statusMsg.innerHTML = 'uploading...';
upload_xhr.send(file);
}
document.getElementById('restart').addEventListener('click', handleRestart);
function handleRestart() {
const restartUrl = '/api/system/restart';
const restart_xhr = new XMLHttpRequest();
restart_xhr.open('POST', restartUrl, true);
restart_xhr.setRequestHeader('Content-Type', '');
restart_xhr.onload = function() {
const responseBody = restart_xhr.responseText;
responseMsg.innerHTML = responseBody;
};
restart_xhr.send(null);
}
</script>
</body>
</html>

View File

@ -114,6 +114,18 @@ esp_err_t i2c_bitaxe_register_read(i2c_master_dev_handle_t dev_handle, uint8_t r
return log_on_error(i2c_master_transmit_receive(dev_handle, &reg_addr, 1, read_buf, len, I2C_DEFAULT_TIMEOUT), dev_handle);
}
/**
* @brief Just write a register address to the I2C device
*
* @param dev_handle
* @param reg_addr
* @return esp_err_t
*/
esp_err_t i2c_bitaxe_register_write_addr(i2c_master_dev_handle_t dev_handle, uint8_t reg_addr)
{
return log_on_error(i2c_master_transmit(dev_handle, &reg_addr, 1, I2C_DEFAULT_TIMEOUT), dev_handle);
}
/**
* @brief Write a byte to a I2C register
* @param dev_handle The I2C device handle

View File

@ -10,6 +10,7 @@ esp_err_t i2c_bitaxe_add_device(uint8_t device_address, i2c_master_dev_handle_t
esp_err_t i2c_bitaxe_get_master_bus_handle(i2c_master_bus_handle_t * dev_handle);
esp_err_t i2c_bitaxe_register_read(i2c_master_dev_handle_t dev_handle, uint8_t reg_addr, uint8_t * read_buf, size_t len);
esp_err_t i2c_bitaxe_register_write_addr(i2c_master_dev_handle_t dev_handle, uint8_t reg_addr);
esp_err_t i2c_bitaxe_register_write_byte(i2c_master_dev_handle_t dev_handle, uint8_t reg_addr, uint8_t data);
esp_err_t i2c_bitaxe_register_write_bytes(i2c_master_dev_handle_t dev_handle, uint8_t * data, uint8_t len);
esp_err_t i2c_bitaxe_register_write_word(i2c_master_dev_handle_t dev_handle, uint8_t reg_addr, uint16_t data);

View File

@ -1,6 +1,7 @@
#include "esp_event.h"
#include "esp_log.h"
#include "esp_psram.h"
#include "nvs_flash.h"
// #include "protocol_examples_common.h"
@ -19,6 +20,7 @@
#include "adc.h"
#include "nvs_device.h"
#include "self_test.h"
#include "asic.h"
static GlobalState GLOBAL_STATE = {
.extranonce_str = NULL,
@ -32,7 +34,14 @@ static const char * TAG = "bitaxe";
void app_main(void)
{
ESP_LOGI(TAG, "Welcome to the bitaxe - hack the planet!");
ESP_LOGI(TAG, "Welcome to the bitaxe - FOSS || GTFO!");
if (!esp_psram_is_initialized()) {
ESP_LOGE(TAG, "No PSRAM available on ESP32 device!");
GLOBAL_STATE.psram_is_available = false;
} else {
GLOBAL_STATE.psram_is_available = true;
}
// Init I2C
ESP_ERROR_CHECK(i2c_bitaxe_init());
@ -75,7 +84,7 @@ void app_main(void)
strncpy(GLOBAL_STATE.SYSTEM_MODULE.ssid, wifi_ssid, sizeof(GLOBAL_STATE.SYSTEM_MODULE.ssid));
GLOBAL_STATE.SYSTEM_MODULE.ssid[sizeof(GLOBAL_STATE.SYSTEM_MODULE.ssid)-1] = 0;
// init and connect to wifi
// init AP and connect to wifi
wifi_init(wifi_ssid, wifi_pass, hostname, GLOBAL_STATE.SYSTEM_MODULE.ip_addr_str);
generate_ssid(GLOBAL_STATE.SYSTEM_MODULE.ap_ssid);
@ -116,15 +125,15 @@ void app_main(void)
GLOBAL_STATE.new_stratum_version_rolling_msg = false;
if (GLOBAL_STATE.ASIC_functions.init_fn != NULL) {
wifi_softap_off();
wifi_softap_off();
if (GLOBAL_STATE.valid_model) {
queue_init(&GLOBAL_STATE.stratum_queue);
queue_init(&GLOBAL_STATE.ASIC_jobs_queue);
SERIAL_init();
(*GLOBAL_STATE.ASIC_functions.init_fn)(GLOBAL_STATE.POWER_MANAGEMENT_MODULE.frequency_value, GLOBAL_STATE.asic_count);
SERIAL_set_baud((*GLOBAL_STATE.ASIC_functions.set_max_baud_fn)());
ASIC_init(&GLOBAL_STATE);
SERIAL_set_baud(ASIC_set_max_baud(&GLOBAL_STATE));
SERIAL_clear_buffer();
GLOBAL_STATE.ASIC_initalized = true;

View File

@ -29,6 +29,7 @@
#define NVS_CONFIG_BEST_DIFF "bestdiff"
#define NVS_CONFIG_SELF_TEST "selftest"
#define NVS_CONFIG_OVERHEAT_MODE "overheat_mode"
#define NVS_CONFIG_OVERCLOCK_ENABLED "oc_enabled"
#define NVS_CONFIG_SWARM "swarmconfig"
// Theme configuration

View File

@ -1,16 +1,17 @@
#include <string.h>
#include "esp_event.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_check.h"
#include "nvs_flash.h"
#include "nvs_config.h"
#include "nvs_device.h"
#include "connect.h"
#include "global_state.h"
#include "asic.h"
static const char * TAG = "nvs_device";
static const double NONCE_SPACE = 4294967296.0; // 2^32
esp_err_t NVSDevice_init(void) {
esp_err_t err = nvs_flash_init();
@ -39,109 +40,15 @@ esp_err_t NVSDevice_parse_config(GlobalState * GLOBAL_STATE) {
GLOBAL_STATE->POWER_MANAGEMENT_MODULE.frequency_value = nvs_config_get_u16(NVS_CONFIG_ASIC_FREQ, CONFIG_ASIC_FREQUENCY);
ESP_LOGI(TAG, "NVS_CONFIG_ASIC_FREQ %f", (float)GLOBAL_STATE->POWER_MANAGEMENT_MODULE.frequency_value);
GLOBAL_STATE->device_model_str = nvs_config_get_string(NVS_CONFIG_DEVICE_MODEL, "");
if (strcmp(GLOBAL_STATE->device_model_str, "max") == 0) {
ESP_LOGI(TAG, "DEVICE: Max");
GLOBAL_STATE->device_model = DEVICE_MAX;
GLOBAL_STATE->asic_count = 1;
GLOBAL_STATE->voltage_domain = 1;
} else if (strcmp(GLOBAL_STATE->device_model_str, "ultra") == 0) {
ESP_LOGI(TAG, "DEVICE: Ultra");
GLOBAL_STATE->device_model = DEVICE_ULTRA;
GLOBAL_STATE->asic_count = 1;
GLOBAL_STATE->voltage_domain = 1;
} else if (strcmp(GLOBAL_STATE->device_model_str, "supra") == 0) {
ESP_LOGI(TAG, "DEVICE: Supra");
GLOBAL_STATE->device_model = DEVICE_SUPRA;
GLOBAL_STATE->asic_count = 1;
GLOBAL_STATE->voltage_domain = 1;
} else if (strcmp(GLOBAL_STATE->device_model_str, "gamma") == 0) {
ESP_LOGI(TAG, "DEVICE: Gamma");
GLOBAL_STATE->device_model = DEVICE_GAMMA;
GLOBAL_STATE->asic_count = 1;
GLOBAL_STATE->voltage_domain = 1;
} else {
ESP_LOGE(TAG, "Invalid DEVICE model");
// maybe should return here to now execute anything with a faulty device parameter !
// this stops crashes/reboots and allows dev testing without an asic
GLOBAL_STATE->device_model = DEVICE_UNKNOWN;
GLOBAL_STATE->asic_count = -1;
GLOBAL_STATE->voltage_domain = 1;
return ESP_FAIL;
}
GLOBAL_STATE->board_version = atoi(nvs_config_get_string(NVS_CONFIG_BOARD_VERSION, "000"));
GLOBAL_STATE->asic_model_str = nvs_config_get_string(NVS_CONFIG_ASIC_MODEL, "");
GLOBAL_STATE->device_model_str = nvs_config_get_string(NVS_CONFIG_DEVICE_MODEL, "invalid");
char * board_version = nvs_config_get_string(NVS_CONFIG_BOARD_VERSION, "000");
GLOBAL_STATE->board_version = atoi(board_version);
free(board_version);
ESP_LOGI(TAG, "Found Device Model: %s", GLOBAL_STATE->device_model_str);
ESP_LOGI(TAG, "Found Board Version: %d", GLOBAL_STATE->board_version);
GLOBAL_STATE->asic_model_str = nvs_config_get_string(NVS_CONFIG_ASIC_MODEL, "");
if (strcmp(GLOBAL_STATE->asic_model_str, "BM1366") == 0) {
ESP_LOGI(TAG, "ASIC: %dx BM1366 (%" PRIu64 " cores)", GLOBAL_STATE->asic_count, BM1366_CORE_COUNT);
GLOBAL_STATE->asic_model = 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,
.set_version_mask = BM1366_set_version_mask};
//GLOBAL_STATE.asic_job_frequency_ms = (NONCE_SPACE / (double) (GLOBAL_STATE.POWER_MANAGEMENT_MODULE.frequency_value * BM1366_CORE_COUNT * 1000)) / (double) GLOBAL_STATE.asic_count; // version-rolling so Small Cores have different Nonce Space
GLOBAL_STATE->asic_job_frequency_ms = 2000; //ms
GLOBAL_STATE->ASIC_difficulty = BM1366_ASIC_DIFFICULTY;
GLOBAL_STATE->ASIC_functions = ASIC_functions;
} else if (strcmp(GLOBAL_STATE->asic_model_str, "BM1370") == 0) {
ESP_LOGI(TAG, "ASIC: %dx BM1370 (%" PRIu64 " cores)", GLOBAL_STATE->asic_count, BM1370_CORE_COUNT);
GLOBAL_STATE->asic_model = ASIC_BM1370;
AsicFunctions ASIC_functions = {.init_fn = BM1370_init,
.receive_result_fn = BM1370_proccess_work,
.set_max_baud_fn = BM1370_set_max_baud,
.set_difficulty_mask_fn = BM1370_set_job_difficulty_mask,
.send_work_fn = BM1370_send_work,
.set_version_mask = BM1370_set_version_mask};
//GLOBAL_STATE.asic_job_frequency_ms = (NONCE_SPACE / (double) (GLOBAL_STATE.POWER_MANAGEMENT_MODULE.frequency_value * BM1370_CORE_COUNT * 1000)) / (double) GLOBAL_STATE.asic_count; // version-rolling so Small Cores have different Nonce Space
GLOBAL_STATE->asic_job_frequency_ms = 500; //ms
GLOBAL_STATE->ASIC_difficulty = BM1370_ASIC_DIFFICULTY;
GLOBAL_STATE->ASIC_functions = ASIC_functions;
} else if (strcmp(GLOBAL_STATE->asic_model_str, "BM1368") == 0) {
ESP_LOGI(TAG, "ASIC: %dx BM1368 (%" PRIu64 " cores)", GLOBAL_STATE->asic_count, BM1368_CORE_COUNT);
GLOBAL_STATE->asic_model = ASIC_BM1368;
AsicFunctions ASIC_functions = {.init_fn = BM1368_init,
.receive_result_fn = BM1368_proccess_work,
.set_max_baud_fn = BM1368_set_max_baud,
.set_difficulty_mask_fn = BM1368_set_job_difficulty_mask,
.send_work_fn = BM1368_send_work,
.set_version_mask = BM1368_set_version_mask};
//GLOBAL_STATE.asic_job_frequency_ms = (NONCE_SPACE / (double) (GLOBAL_STATE.POWER_MANAGEMENT_MODULE.frequency_value * BM1368_CORE_COUNT * 1000)) / (double) GLOBAL_STATE.asic_count; // version-rolling so Small Cores have different Nonce Space
GLOBAL_STATE->asic_job_frequency_ms = 500; //ms
GLOBAL_STATE->ASIC_difficulty = BM1368_ASIC_DIFFICULTY;
GLOBAL_STATE->ASIC_functions = ASIC_functions;
} else if (strcmp(GLOBAL_STATE->asic_model_str, "BM1397") == 0) {
ESP_LOGI(TAG, "ASIC: %dx BM1397 (%" PRIu64 " cores)", GLOBAL_STATE->asic_count, BM1397_SMALL_CORE_COUNT);
GLOBAL_STATE->asic_model = 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,
.set_version_mask = BM1397_set_version_mask};
GLOBAL_STATE->asic_job_frequency_ms = (NONCE_SPACE / (double) (GLOBAL_STATE->POWER_MANAGEMENT_MODULE.frequency_value * BM1397_SMALL_CORE_COUNT * 1000)) / (double) GLOBAL_STATE->asic_count; // no version-rolling so same Nonce Space is splitted between Small Cores
GLOBAL_STATE->ASIC_difficulty = BM1397_ASIC_DIFFICULTY;
GLOBAL_STATE->ASIC_functions = ASIC_functions;
} else {
ESP_LOGE(TAG, "Invalid ASIC model");
AsicFunctions ASIC_functions = {.init_fn = NULL,
.receive_result_fn = NULL,
.set_max_baud_fn = NULL,
.set_difficulty_mask_fn = NULL,
.send_work_fn = NULL};
GLOBAL_STATE->ASIC_functions = ASIC_functions;
// maybe should return here to not execute anything with a faulty device parameter !
return ESP_FAIL;
}
ESP_RETURN_ON_ERROR(ASIC_set_device_model(GLOBAL_STATE), TAG, "Failed to get device model");
return ESP_OK;
}

View File

@ -10,6 +10,18 @@
#define DS4432U_OUT0_REG 0xF8 // register for current output 0
#define DS4432U_OUT1_REG 0xF9 // register for current output 1
// DS4432U Transfer function constants for Bitaxe board
// #define BITAXE_RFS 80000.0 // R16
// #define BITAXE_IFS ((DS4432_VRFS * 127.0) / (BITAXE_RFS * 16))
#define BITAXE_IFS 0.000098921 // (Vrfs / Rfs) x (127/16) -> Vrfs = 0.997, Rfs = 80000
#define BITAXE_RA 4750.0 // R14
#define BITAXE_RB 3320.0 // R15
#define BITAXE_VNOM 1.451 // this is with the current DAC set to 0. Should be pretty close to (VFB*(RA+RB))/RB
#define BITAXE_VMAX 2.39
#define BITAXE_VMIN 0.046
#define TPS40305_VFB 0.6
static const char *TAG = "DS4432U";
static i2c_master_dev_handle_t ds4432u_dev_handle;
@ -35,6 +47,29 @@ esp_err_t DS4432U_set_current_code(uint8_t output, uint8_t code) {
return i2c_bitaxe_register_write_byte(ds4432u_dev_handle, reg, code);
}
esp_err_t DS4432U_set_voltage(float vout) {
float change;
uint8_t reg;
// make sure the requested voltage is in within range of BITAXE_VMIN and BITAXE_VMAX
if (vout > BITAXE_VMAX || vout < BITAXE_VMIN) {
return ESP_FAIL;
}
// this is the transfer function. comes from the DS4432U+ datasheet
change = fabs((((TPS40305_VFB / BITAXE_RB) - ((vout - TPS40305_VFB) / BITAXE_RA)) / BITAXE_IFS) * 127);
reg = (uint8_t)ceil(change);
// Set the MSB high if the requested voltage is BELOW nominal
if (vout < BITAXE_VNOM) {
reg |= 0x80;
}
ESP_RETURN_ON_ERROR(DS4432U_set_current_code(0, reg), TAG, "DS4432U set current code failed!");
return ESP_OK;
}
/**
* @brief Get the current DAC code value for a specific DS4432U output.
*

View File

@ -10,5 +10,6 @@ esp_err_t DS4432U_test(void);
esp_err_t DS4432U_init(void);
esp_err_t DS4432U_set_current_code(uint8_t output, uint8_t code);
esp_err_t DS4432U_get_current_code(uint8_t output, uint8_t *code);
esp_err_t DS4432U_set_voltage(float vout);
#endif /* DS4432U_H_ */

View File

@ -3,6 +3,7 @@
#include <math.h>
#include <string.h>
#include "esp_log.h"
#include "esp_err.h"
#include "pmbus_commands.h"
#include "i2c_bitaxe.h"
@ -35,6 +36,8 @@ static uint8_t MFR_REVISION[] = {0x00, 0x00, 0x01};
static i2c_master_dev_handle_t tps546_dev_handle;
static TPS546_CONFIG tps546_config;
/**
* @brief SMBus read byte
* @param command The command to read
@ -55,6 +58,15 @@ static esp_err_t smb_write_byte(uint8_t command, uint8_t data)
return i2c_bitaxe_register_write_byte(tps546_dev_handle, command, data);
}
/**
* @brief SMBus write addr
* @param command The command to write
*/
static esp_err_t smb_write_addr(uint8_t command)
{
return i2c_bitaxe_register_write_addr(tps546_dev_handle, command);
}
/**
* @brief SMBus read word
* @param command The command to read
@ -318,7 +330,7 @@ static uint16_t float_2_ulinear16(float value)
/**
* @brief Set up the TPS546 regulator and turn it on
*/
int TPS546_init(void)
esp_err_t TPS546_init(TPS546_CONFIG config)
{
uint8_t data[7];
uint8_t u8_value;
@ -328,11 +340,13 @@ int TPS546_init(void)
uint8_t comp_config[5];
uint8_t voutmode;
tps546_config = config;
ESP_LOGI(TAG, "Initializing the core voltage regulator");
if (i2c_bitaxe_add_device(TPS546_I2CADDR, &tps546_dev_handle, TAG) != ESP_OK) {
ESP_LOGE(TAG, "Failed to add I2C device");
return -1;
return ESP_FAIL;
}
/* Establish communication with regulator */
@ -342,7 +356,7 @@ int TPS546_init(void)
if ( (memcmp(data, DEVICE_ID1, 6) != 0) && (memcmp(data, DEVICE_ID2, 6) != 0) && (memcmp(data, DEVICE_ID3, 6) != 0))
{
ESP_LOGE(TAG, "Cannot find TPS546 regulator - Device ID mismatch");
return -1;
return ESP_FAIL;
}
/* Make sure power is turned off until commanded */
@ -375,46 +389,77 @@ int TPS546_init(void)
/* Show voltage settings */
TPS546_show_voltage_settings();
//TPS546_print_status();
uint16_t status;
TPS546_check_status(&status);
// ESP_LOGI(TAG, "-----------VOLTAGE/CURRENT---------------------");
// /* Get voltage input (SLINEAR11) */
// ESP_LOGI(TAG, "READ_VIN: %.2fV", TPS546_get_vin());
// /* Get output current (SLINEAR11) */
// ESP_LOGI(TAG, "READ_IOUT: %.2fA", TPS546_get_iout());
// /* Get voltage output (ULINEAR16) */
// ESP_LOGI(TAG, "READ_VOUT: %.2fV", TPS546_get_vout());
if (status != 0) {
ESP_LOGE(TAG, "Status error: %04x", status);
TPS546_parse_status(status);
}
ESP_LOGI(TAG, "-----------VOLTAGE/CURRENT---------------------");
smb_read_word(PMBUS_READ_VIN, &u16_value);
ESP_LOGI(TAG, "read READ_VIN: %.2fV", slinear11_2_float(u16_value));
smb_read_word(PMBUS_READ_IOUT, &u16_value);
ESP_LOGI(TAG, "read READ_IOUT: %.2fA", slinear11_2_float(u16_value));
smb_read_word(PMBUS_READ_VOUT, &u16_value);
ESP_LOGI(TAG, "read READ_VOUT: %.2fV", ulinear16_2_float(u16_value));
ESP_LOGI(TAG, "-----------TIMING---------------------");
smb_read_word(PMBUS_TON_DELAY, &u16_value);
temp = slinear11_2_int(u16_value);
ESP_LOGI(TAG, "TON_DELAY: %d", temp);
ESP_LOGI(TAG, "read TON_DELAY: %dms", temp);
smb_read_word(PMBUS_TON_RISE, &u16_value);
temp = slinear11_2_int(u16_value);
ESP_LOGI(TAG, "TON_RISE: %d", temp);
ESP_LOGI(TAG, "read TON_RISE: %dms", temp);
smb_read_word(PMBUS_TON_MAX_FAULT_LIMIT, &u16_value);
temp = slinear11_2_int(u16_value);
ESP_LOGI(TAG, "TON_MAX_FAULT_LIMIT: %d", temp);
ESP_LOGI(TAG, "read TON_MAX_FAULT_LIMIT: %dms", temp);
smb_read_byte(PMBUS_TON_MAX_FAULT_RESPONSE, &u8_value);
ESP_LOGI(TAG, "TON_MAX_FAULT_RESPONSE: %02x", u8_value);
ESP_LOGI(TAG, "read TON_MAX_FAULT_RESPONSE: %02x", u8_value);
smb_read_word(PMBUS_TOFF_DELAY, &u16_value);
temp = slinear11_2_int(u16_value);
ESP_LOGI(TAG, "TOFF_DELAY: %d", temp);
ESP_LOGI(TAG, "read TOFF_DELAY: %dms", temp);
smb_read_word(PMBUS_TOFF_FALL, &u16_value);
temp = slinear11_2_int(u16_value);
ESP_LOGI(TAG, "TOFF_FALL: %d", temp);
ESP_LOGI(TAG, "--------------------------------------");
ESP_LOGI(TAG, "read TOFF_FALL: %dms", temp);
ESP_LOGI(TAG, "---------CONFIG--------------------");
smb_read_byte(PMBUS_PHASE, &u8_value);
ESP_LOGI(TAG, "read PHASE: %02x", u8_value);
smb_read_word(PMBUS_STACK_CONFIG, &u16_value);
ESP_LOGI(TAG, "read STACK_CONFIG: %04x", u16_value);
smb_read_byte(PMBUS_SYNC_CONFIG, &u8_value);
ESP_LOGI(TAG, "read SYNC_CONFIG: %02x", u8_value);
smb_read_word(PMBUS_INTERLEAVE, &u16_value);
ESP_LOGI(TAG, "read INTERLEAVE: %04x", u16_value);
smb_read_byte(PMBUS_CAPABILITY, &u8_value);
ESP_LOGI(TAG, "read CAPABILITY: %02x", u8_value);
// Read the compensation config registers
if (smb_read_block(PMBUS_COMPENSATION_CONFIG, comp_config, 5) != ESP_OK) {
ESP_LOGE(TAG, "Failed to read COMPENSATION CONFIG");
return -1;
return ESP_FAIL;
}
ESP_LOGI(TAG, "COMPENSATION CONFIG");
ESP_LOGI(TAG, "read COMPENSATION CONFIG");
ESP_LOGI(TAG, "%02x %02x %02x %02x %02x", comp_config[0], comp_config[1],
comp_config[2], comp_config[3], comp_config[4]);
return 0;
ESP_LOGI(TAG, "Clearing faults");
TPS546_clear_faults();
return ESP_OK;
}
esp_err_t TPS546_clear_faults(void) {
// if (smb_write_byte(PMBUS_CLEAR_FAULTS, 0xFF) != ESP_OK) {
if (smb_write_addr(PMBUS_CLEAR_FAULTS) != ESP_OK) {
ESP_LOGE(TAG, "Failed to clear faults");
return ESP_FAIL;
}
return ESP_OK;
}
/**
@ -442,10 +487,9 @@ void TPS546_read_mfr_info(uint8_t *read_mfr_revision)
return;
}
ESP_LOGI(TAG, "MFR_ID: %s", read_mfr_id);
ESP_LOGI(TAG, "MFR_MODEL: %s", read_mfr_model);
ESP_LOGI(TAG, "MFR_REVISION: %d%d%d ", read_mfr_revision[0],
read_mfr_revision[1], read_mfr_revision[2]);
ESP_LOGI(TAG, "MFR_ID: %02X %02X %02X", read_mfr_id[0], read_mfr_id[1], read_mfr_id[2]);
ESP_LOGI(TAG, "MFR_MODEL: %02X %02X %02X", read_mfr_model[0], read_mfr_model[1], read_mfr_model[2]);
ESP_LOGI(TAG, "MFR_REVISION: %02X %02X %02X", read_mfr_revision[0], read_mfr_revision[1], read_mfr_revision[2]);
}
/**
@ -453,9 +497,12 @@ void TPS546_read_mfr_info(uint8_t *read_mfr_revision)
*/
void TPS546_set_mfr_info(void)
{
ESP_LOGI(TAG, "Setting MFR info");
ESP_LOGI(TAG, "----- Manufacturer Info");
ESP_LOGI(TAG, "Setting MFR_ID: %02X %02X %02X", MFR_ID[0], MFR_ID[1], MFR_ID[2]);
smb_write_block(PMBUS_MFR_ID, MFR_ID, 3);
ESP_LOGI(TAG, "Setting MFR_MODEL: %02X %02X %02X", MFR_MODEL[0], MFR_MODEL[1], MFR_MODEL[2]);
smb_write_block(PMBUS_MFR_MODEL, MFR_MODEL, 3);
ESP_LOGI(TAG, "Setting MFR_REVISION: %02X %02X %02X", MFR_REVISION[0], MFR_REVISION[1], MFR_REVISION[2]);
smb_write_block(PMBUS_MFR_REVISION, MFR_REVISION, 3);
}
@ -466,78 +513,104 @@ void TPS546_write_entire_config(void)
{
ESP_LOGI(TAG, "---Writing new config values to TPS546---");
/* set up the ON_OFF_CONFIG */
ESP_LOGI(TAG, "Setting ON_OFF_CONFIG");
ESP_LOGI(TAG, "Setting ON_OFF_CONFIG: %02X", TPS546_INIT_ON_OFF_CONFIG);
if (smb_write_byte(PMBUS_ON_OFF_CONFIG, TPS546_INIT_ON_OFF_CONFIG) != ESP_OK) {
ESP_LOGE(TAG, "Failed to write ON_OFF_CONFIG");
return;
}
/* Phase */
ESP_LOGI(TAG, "Setting PHASE: %02X", TPS546_INIT_PHASE);
smb_write_byte(PMBUS_PHASE, TPS546_INIT_PHASE);
/* Switch frequency */
ESP_LOGI(TAG, "Setting FREQUENCY");
ESP_LOGI(TAG, "Setting FREQUENCY: %dMHz", TPS546_INIT_FREQUENCY);
smb_write_word(PMBUS_FREQUENCY_SWITCH, int_2_slinear11(TPS546_INIT_FREQUENCY));
/* vin voltage */
ESP_LOGI(TAG, "Setting VIN_ON: %.2f", TPS546_INIT_VIN_ON);
smb_write_word(PMBUS_VIN_ON, float_2_slinear11(TPS546_INIT_VIN_ON));
ESP_LOGI(TAG, "Setting VIN_OFF: %.2f", TPS546_INIT_VIN_OFF);
smb_write_word(PMBUS_VIN_OFF, float_2_slinear11(TPS546_INIT_VIN_OFF));
ESP_LOGI(TAG, "Setting VIN_UV_WARN_LIMIT: %.2f", TPS546_INIT_VIN_UV_WARN_LIMIT);
smb_write_word(PMBUS_VIN_UV_WARN_LIMIT, float_2_slinear11(TPS546_INIT_VIN_UV_WARN_LIMIT));
ESP_LOGI(TAG, "Setting VIN_OV_FAULT_LIMIT: %.2f", TPS546_INIT_VIN_OV_FAULT_LIMIT);
smb_write_word(PMBUS_VIN_OV_FAULT_LIMIT, float_2_slinear11(TPS546_INIT_VIN_OV_FAULT_LIMIT));
//deal with the UV_WARN_LIMIT bug
if (tps546_config.TPS546_INIT_VIN_UV_WARN_LIMIT > 0) {
ESP_LOGI(TAG, "Setting VIN_UV_WARN_LIMIT: %.2f", tps546_config.TPS546_INIT_VIN_UV_WARN_LIMIT);
smb_write_word(PMBUS_VIN_UV_WARN_LIMIT, float_2_slinear11(tps546_config.TPS546_INIT_VIN_UV_WARN_LIMIT));
}
ESP_LOGI(TAG, "Setting VIN_ON: %.2fV", tps546_config.TPS546_INIT_VIN_ON);
smb_write_word(PMBUS_VIN_ON, float_2_slinear11(tps546_config.TPS546_INIT_VIN_ON));
ESP_LOGI(TAG, "Setting VIN_OFF: %.2fV", tps546_config.TPS546_INIT_VIN_OFF);
smb_write_word(PMBUS_VIN_OFF, float_2_slinear11(tps546_config.TPS546_INIT_VIN_OFF));
ESP_LOGI(TAG, "Setting VIN_OV_FAULT_LIMIT: %.2fV", tps546_config.TPS546_INIT_VIN_OV_FAULT_LIMIT);
smb_write_word(PMBUS_VIN_OV_FAULT_LIMIT, float_2_slinear11(tps546_config.TPS546_INIT_VIN_OV_FAULT_LIMIT));
ESP_LOGI(TAG, "Setting VIN_OV_FAULT_RESPONSE: %02X", TPS546_INIT_VIN_OV_FAULT_RESPONSE);
smb_write_byte(PMBUS_VIN_OV_FAULT_RESPONSE, TPS546_INIT_VIN_OV_FAULT_RESPONSE);
/* vout voltage */
ESP_LOGI(TAG, "Setting VOUT SCALE: %.2f", TPS546_INIT_SCALE_LOOP);
smb_write_word(PMBUS_VOUT_SCALE_LOOP, float_2_slinear11(TPS546_INIT_SCALE_LOOP));
ESP_LOGI(TAG, "VOUT_COMMAND: %.2f", TPS546_INIT_VOUT_COMMAND);
smb_write_word(PMBUS_VOUT_COMMAND, float_2_ulinear16(TPS546_INIT_VOUT_COMMAND));
ESP_LOGI(TAG, "VOUT_MAX: %d", TPS546_INIT_VOUT_MAX);
smb_write_word(PMBUS_VOUT_MAX, float_2_ulinear16(TPS546_INIT_VOUT_MAX));
ESP_LOGI(TAG, "VOUT_OV_FAULT_LIMIT: %.2f", TPS546_INIT_VOUT_OV_FAULT_LIMIT);
ESP_LOGI(TAG, "Setting VOUT SCALE: %.2f", tps546_config.TPS546_INIT_SCALE_LOOP);
smb_write_word(PMBUS_VOUT_SCALE_LOOP, float_2_slinear11(tps546_config.TPS546_INIT_SCALE_LOOP));
ESP_LOGI(TAG, "Setting VOUT_COMMAND: %.2fV", tps546_config.TPS546_INIT_VOUT_COMMAND);
smb_write_word(PMBUS_VOUT_COMMAND, float_2_ulinear16(tps546_config.TPS546_INIT_VOUT_COMMAND));
ESP_LOGI(TAG, "Setting VOUT_MAX: %.2fV", tps546_config.TPS546_INIT_VOUT_MAX);
smb_write_word(PMBUS_VOUT_MAX, float_2_ulinear16(tps546_config.TPS546_INIT_VOUT_MAX));
ESP_LOGI(TAG, "Setting VOUT_MIN: %.2fV", tps546_config.TPS546_INIT_VOUT_MIN);
smb_write_word(PMBUS_VOUT_MIN, float_2_ulinear16(tps546_config.TPS546_INIT_VOUT_MIN));
ESP_LOGI(TAG, "Setting VOUT_OV_FAULT_LIMIT: %.2f", TPS546_INIT_VOUT_OV_FAULT_LIMIT);
smb_write_word(PMBUS_VOUT_OV_FAULT_LIMIT, float_2_ulinear16(TPS546_INIT_VOUT_OV_FAULT_LIMIT));
ESP_LOGI(TAG, "VOUT_OV_WARN_LIMIT: %.2f", TPS546_INIT_VOUT_OV_WARN_LIMIT);
ESP_LOGI(TAG, "Setting VOUT_OV_WARN_LIMIT: %.2f", TPS546_INIT_VOUT_OV_WARN_LIMIT);
smb_write_word(PMBUS_VOUT_OV_WARN_LIMIT, float_2_ulinear16(TPS546_INIT_VOUT_OV_WARN_LIMIT));
ESP_LOGI(TAG, "VOUT_MARGIN_HIGH: %.2f", TPS546_INIT_VOUT_MARGIN_HIGH);
ESP_LOGI(TAG, "Setting VOUT_MARGIN_HIGH: %.2f", TPS546_INIT_VOUT_MARGIN_HIGH);
smb_write_word(PMBUS_VOUT_MARGIN_HIGH, float_2_ulinear16(TPS546_INIT_VOUT_MARGIN_HIGH));
ESP_LOGI(TAG, "VOUT_MARGIN_LOW: %.2f", TPS546_INIT_VOUT_MARGIN_LOW);
ESP_LOGI(TAG, "Setting VOUT_MARGIN_LOW: %.2f", TPS546_INIT_VOUT_MARGIN_LOW);
smb_write_word(PMBUS_VOUT_MARGIN_LOW, float_2_ulinear16(TPS546_INIT_VOUT_MARGIN_LOW));
ESP_LOGI(TAG, "VOUT_UV_WARN_LIMIT: %.2f", TPS546_INIT_VOUT_UV_WARN_LIMIT);
ESP_LOGI(TAG, "Setting VOUT_UV_WARN_LIMIT: %.2f", TPS546_INIT_VOUT_UV_WARN_LIMIT);
smb_write_word(PMBUS_VOUT_UV_WARN_LIMIT, float_2_ulinear16(TPS546_INIT_VOUT_UV_WARN_LIMIT));
ESP_LOGI(TAG, "VOUT_UV_FAULT_LIMIT: %.2f", TPS546_INIT_VOUT_UV_FAULT_LIMIT);
ESP_LOGI(TAG, "Setting VOUT_UV_FAULT_LIMIT: %.2f", TPS546_INIT_VOUT_UV_FAULT_LIMIT);
smb_write_word(PMBUS_VOUT_UV_FAULT_LIMIT, float_2_ulinear16(TPS546_INIT_VOUT_UV_FAULT_LIMIT));
ESP_LOGI(TAG, "VOUT_MIN: %d", TPS546_INIT_VOUT_MIN);
smb_write_word(PMBUS_VOUT_MIN, float_2_ulinear16(TPS546_INIT_VOUT_MIN));
/* iout current */
ESP_LOGI(TAG, "Setting IOUT");
smb_write_word(PMBUS_IOUT_OC_WARN_LIMIT, float_2_slinear11(TPS546_INIT_IOUT_OC_WARN_LIMIT));
smb_write_word(PMBUS_IOUT_OC_FAULT_LIMIT, float_2_slinear11(TPS546_INIT_IOUT_OC_FAULT_LIMIT));
ESP_LOGI(TAG, "----- IOUT");
ESP_LOGI(TAG, "Setting IOUT_OC_WARN_LIMIT: %.2fA", tps546_config.TPS546_INIT_IOUT_OC_WARN_LIMIT);
smb_write_word(PMBUS_IOUT_OC_WARN_LIMIT, float_2_slinear11(tps546_config.TPS546_INIT_IOUT_OC_WARN_LIMIT));
ESP_LOGI(TAG, "Setting IOUT_OC_FAULT_LIMIT: %.2fA", tps546_config.TPS546_INIT_IOUT_OC_FAULT_LIMIT);
smb_write_word(PMBUS_IOUT_OC_FAULT_LIMIT, float_2_slinear11(tps546_config.TPS546_INIT_IOUT_OC_FAULT_LIMIT));
ESP_LOGI(TAG, "Setting IOUT_OC_FAULT_RESPONSE: %02x", TPS546_INIT_IOUT_OC_FAULT_RESPONSE);
smb_write_byte(PMBUS_IOUT_OC_FAULT_RESPONSE, TPS546_INIT_IOUT_OC_FAULT_RESPONSE);
/* temperature */
ESP_LOGI(TAG, "Setting TEMPERATURE");
ESP_LOGI(TAG, "OT_WARN_LIMIT: %d", TPS546_INIT_OT_WARN_LIMIT);
ESP_LOGI(TAG, "----- TEMPERATURE");
ESP_LOGI(TAG, "Setting OT_WARN_LIMIT: %dC", TPS546_INIT_OT_WARN_LIMIT);
smb_write_word(PMBUS_OT_WARN_LIMIT, int_2_slinear11(TPS546_INIT_OT_WARN_LIMIT));
ESP_LOGI(TAG, "OT_FAULT_LIMIT: %d", TPS546_INIT_OT_FAULT_LIMIT);
ESP_LOGI(TAG, "Setting OT_FAULT_LIMIT: %dC", TPS546_INIT_OT_FAULT_LIMIT);
smb_write_word(PMBUS_OT_FAULT_LIMIT, int_2_slinear11(TPS546_INIT_OT_FAULT_LIMIT));
ESP_LOGI(TAG, "OT_FAULT_RESPONSE: %02x", TPS546_INIT_OT_FAULT_RESPONSE);
ESP_LOGI(TAG, "Setting OT_FAULT_RESPONSE: %02x", TPS546_INIT_OT_FAULT_RESPONSE);
smb_write_byte(PMBUS_OT_FAULT_RESPONSE, TPS546_INIT_OT_FAULT_RESPONSE);
/* timing */
ESP_LOGI(TAG, "Setting TIMING");
ESP_LOGI(TAG, "TON_DELAY: %d", TPS546_INIT_TON_DELAY);
ESP_LOGI(TAG, "----- TIMING");
ESP_LOGI(TAG, "Setting TON_DELAY: %dms", TPS546_INIT_TON_DELAY);
smb_write_word(PMBUS_TON_DELAY, int_2_slinear11(TPS546_INIT_TON_DELAY));
ESP_LOGI(TAG, "TON_RISE: %d", TPS546_INIT_TON_RISE);
ESP_LOGI(TAG, "Setting TON_RISE: %dms", TPS546_INIT_TON_RISE);
smb_write_word(PMBUS_TON_RISE, int_2_slinear11(TPS546_INIT_TON_RISE));
ESP_LOGI(TAG, "TON_MAX_FAULT_LIMIT: %d", TPS546_INIT_TON_MAX_FAULT_LIMIT);
ESP_LOGI(TAG, "Setting TON_MAX_FAULT_LIMIT: %dms", TPS546_INIT_TON_MAX_FAULT_LIMIT);
smb_write_word(PMBUS_TON_MAX_FAULT_LIMIT, int_2_slinear11(TPS546_INIT_TON_MAX_FAULT_LIMIT));
ESP_LOGI(TAG, "TON_MAX_FAULT_RESPONSE: %02x", TPS546_INIT_TON_MAX_FAULT_RESPONSE);
ESP_LOGI(TAG, "Setting TON_MAX_FAULT_RESPONSE: %02x", TPS546_INIT_TON_MAX_FAULT_RESPONSE);
smb_write_byte(PMBUS_TON_MAX_FAULT_RESPONSE, TPS546_INIT_TON_MAX_FAULT_RESPONSE);
ESP_LOGI(TAG, "TOFF_DELAY: %d", TPS546_INIT_TOFF_DELAY);
ESP_LOGI(TAG, "Setting TOFF_DELAY: %dms", TPS546_INIT_TOFF_DELAY);
smb_write_word(PMBUS_TOFF_DELAY, int_2_slinear11(TPS546_INIT_TOFF_DELAY));
ESP_LOGI(TAG, "TOFF_FALL: %d", TPS546_INIT_TOFF_FALL);
ESP_LOGI(TAG, "Setting TOFF_FALL: %dms", TPS546_INIT_TOFF_FALL);
smb_write_word(PMBUS_TOFF_FALL, int_2_slinear11(TPS546_INIT_TOFF_FALL));
/* Compensation config */
@ -549,11 +622,11 @@ void TPS546_write_entire_config(void)
smb_write_word(PMBUS_PIN_DETECT_OVERRIDE, INIT_PIN_DETECT_OVERRIDE);
/* TODO write new MFR_REVISION number to reflect these parameters */
ESP_LOGI(TAG, "Writing MFR ID");
ESP_LOGI(TAG, "Setting MFR ID");
smb_write_block(PMBUS_MFR_ID, MFR_ID, 3);
ESP_LOGI(TAG, "Writing MFR MODEL");
ESP_LOGI(TAG, "Setting MFR MODEL");
smb_write_block(PMBUS_MFR_ID, MFR_MODEL, 3);
ESP_LOGI(TAG, "Writing MFR REVISION");
ESP_LOGI(TAG, "Setting MFR REVISION");
smb_write_block(PMBUS_MFR_ID, MFR_REVISION, 3);
/*
@ -659,27 +732,123 @@ float TPS546_get_vout(void)
}
}
void TPS546_print_status(void) {
uint16_t u16_value;
esp_err_t TPS546_check_status(uint16_t *status) {
if (smb_read_word(PMBUS_STATUS_WORD, status) != ESP_OK) {
ESP_LOGE(TAG, "Could not read STATUS_WORD");
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t TPS546_parse_status(uint16_t status) {
uint8_t u8_value;
if (smb_read_word(PMBUS_STATUS_WORD, &u16_value) != ESP_OK) {
ESP_LOGE(TAG, "Could not read STATUS_WORD");
} else {
ESP_LOGI(TAG, "TPS546 Status: %04X", u16_value);
if (status & TPS546_STATUS_BUSY) {
ESP_LOGI(TAG, "TPS546 is busy");
return ESP_OK;
}
if (smb_read_byte(PMBUS_STATUS_VOUT, &u8_value) != ESP_OK) {
ESP_LOGE(TAG, "Could not read STATUS_VOUT");
} else {
ESP_LOGI(TAG, "TPS546 VOUT Status: %02X", u8_value);
if (status & TPS546_STATUS_OFF) {
ESP_LOGI(TAG, "TPS546 is off");
}
if (smb_read_byte(PMBUS_STATUS_INPUT, &u8_value) != ESP_OK) {
ESP_LOGE(TAG, "Could not read STATUS_INPUT");
} else {
ESP_LOGI(TAG, "TPS546 INPUT Status: %02X", u8_value);
if (status & TPS546_STATUS_VOUT_OV) {
ESP_LOGI(TAG, "TPS546 VOUT is out of range");
}
if (status & TPS546_STATUS_IOUT_OC) {
ESP_LOGI(TAG, "TPS546 IOUT is out of range");
}
if (status & TPS546_STATUS_VIN_UV) {
ESP_LOGI(TAG, "TPS546 VIN is out of range");
}
if (status & TPS546_STATUS_TEMP) {
ESP_LOGI(TAG, "TPS546 TEMP Status Error");
//the host should check STATUS_TEMPERATURE for more information.
if (smb_read_byte(PMBUS_STATUS_TEMPERATURE, &u8_value) != ESP_OK) {
ESP_LOGE(TAG, "Could not read STATUS_TEMPERATURE");
} else {
ESP_LOGI(TAG, "TPS546 Temperature Status: %02X", u8_value);
}
}
if (status & TPS546_STATUS_CML) {
ESP_LOGI(TAG, "TPS546 CML Status Error");
//the host should check STATUS_CML for more information.
if (smb_read_byte(PMBUS_STATUS_CML, &u8_value) != ESP_OK) {
ESP_LOGE(TAG, "Could not read STATUS_CML");
} else {
ESP_LOGI(TAG, "TPS546 CML Status: %02X", u8_value);
}
}
if (status & TPS546_STATUS_NONE) {
ESP_LOGI(TAG, "TPS546 Status Word Error");
//The host should check the STATUS_WORD for more information.
} else {
return ESP_OK;
}
//STATUS_WORD bits
if (status & TPS546_STATUS_VOUT) {
ESP_LOGI(TAG, "TPS546 VOUT Status Error");
//the host should check STATUS_VOUT for more information.
if (smb_read_byte(PMBUS_STATUS_VOUT, &u8_value) != ESP_OK) {
ESP_LOGE(TAG, "Could not read STATUS_VOUT");
} else {
ESP_LOGI(TAG, "TPS546 VOUT Status: %02X", u8_value);
}
}
if (status & TPS546_STATUS_IOUT) {
ESP_LOGI(TAG, "TPS546 IOUT Status Error");
//the host should check STATUS_IOUT for more information.
if (smb_read_byte(PMBUS_STATUS_IOUT, &u8_value) != ESP_OK) {
ESP_LOGE(TAG, "Could not read STATUS_IOUT");
} else {
ESP_LOGI(TAG, "TPS546 IOUT Status: %02X", u8_value);
}
}
if (status & TPS546_STATUS_INPUT) {
ESP_LOGI(TAG, "TPS546 INPUT Status Error");
//the host should check STATUS_INPUT for more information.
if (smb_read_byte(PMBUS_STATUS_INPUT, &u8_value) != ESP_OK) {
ESP_LOGE(TAG, "Could not read STATUS_INPUT");
} else {
ESP_LOGI(TAG, "TPS546 INPUT Status: %02X", u8_value);
}
}
if (status & TPS546_STATUS_MFR) {
ESP_LOGI(TAG, "TPS546 MFR_SPECIFIC Status Error");
//the host should check STATUS_MFR_SPECIFIC for more information.
if (smb_read_byte(PMBUS_STATUS_MFR_SPECIFIC, &u8_value) != ESP_OK) {
ESP_LOGE(TAG, "Could not read STATUS_MFR_SPECIFIC");
} else {
ESP_LOGI(TAG, "TPS546 MFR_SPECIFIC Status: %02X", u8_value);
}
}
if (status & TPS546_STATUS_PGOOD) {
ESP_LOGI(TAG, "TPS546 PGOOD Status Error");
}
if (status & TPS546_STATUS_OTHER) {
ESP_LOGI(TAG, "TPS546 OTHER Status Error");
//the host should check STATUS_OTHER for more information.
if (smb_read_byte(PMBUS_STATUS_OTHER, &u8_value) != ESP_OK) {
ESP_LOGE(TAG, "Could not read STATUS_OTHER");
} else {
ESP_LOGI(TAG, "TPS546 OTHER Status: %02X", u8_value);
}
}
return ESP_OK;
}
/**
@ -690,24 +859,26 @@ void TPS546_print_status(void) {
* send a 0 to turn off the output
* @param volts The desired output voltage
**/
void TPS546_set_vout(float volts)
{
esp_err_t TPS546_set_vout(float volts) {
uint16_t value;
if (volts == 0) {
/* turn off output */
if (smb_write_byte(PMBUS_OPERATION, OPERATION_OFF) != ESP_OK) {
ESP_LOGE(TAG, "Could not turn off Vout");
return ESP_FAIL;
}
} else {
/* make sure we're in range */
if ((volts < TPS546_INIT_VOUT_MIN) || (volts > TPS546_INIT_VOUT_MAX)) {
if ((volts < tps546_config.TPS546_INIT_VOUT_MIN) || (volts > tps546_config.TPS546_INIT_VOUT_MAX)) {
ESP_LOGE(TAG, "Voltage requested (%f V) is out of range", volts);
return ESP_FAIL;
} else {
/* set the output voltage */
value = float_2_ulinear16(volts);
if (smb_write_word(PMBUS_VOUT_COMMAND, value) != ESP_OK) {
ESP_LOGE(TAG, "Could not set Vout to %1.2f V", volts);
return ESP_FAIL;
}
ESP_LOGI(TAG, "Vout changed to %1.2f V", volts);
@ -715,70 +886,88 @@ void TPS546_set_vout(float volts)
/* turn on output */
if (smb_write_byte(PMBUS_OPERATION, OPERATION_ON) != ESP_OK) {
ESP_LOGE(TAG, "Could not turn on Vout");
return ESP_FAIL;
}
}
}
return ESP_OK;
}
void TPS546_show_voltage_settings(void)
{
uint16_t u16_value;
uint8_t u8_value;
float f_value;
ESP_LOGI(TAG, "-----------VOLTAGE---------------------");
/* VIN_ON SLINEAR11 */
smb_read_word(PMBUS_VIN_ON, &u16_value);
f_value = slinear11_2_float(u16_value);
ESP_LOGI(TAG, "VIN ON set to: %.2f", f_value);
ESP_LOGI(TAG, "read VIN_ON: %.2fV", f_value);
/* VIN_OFF SLINEAR11 */
smb_read_word(PMBUS_VIN_OFF, &u16_value);
f_value = slinear11_2_float(u16_value);
ESP_LOGI(TAG, "VIN OFF set to: %.2f", f_value);
ESP_LOGI(TAG, "read VIN_OFF: %.2fV", f_value);
/* VIN_OV_FAULT_LIMIT SLINEAR11 */
smb_read_word(PMBUS_VIN_OV_FAULT_LIMIT, &u16_value);
f_value = slinear11_2_float(u16_value);
ESP_LOGI(TAG, "read VIN_OV_FAULT_LIMIT: %.2fV", f_value);
/* VIN_UV_WARN_LIMIT SLINEAR11 */
smb_read_word(PMBUS_VIN_UV_WARN_LIMIT, &u16_value);
f_value = slinear11_2_float(u16_value);
ESP_LOGI(TAG, "read VIN_UV_WARN_LIMIT: %.2fV", f_value);
/* VIN_OV_FAULT_RESPONSE */
smb_read_byte(PMBUS_VIN_OV_FAULT_RESPONSE, &u8_value);
ESP_LOGI(TAG, "read VIN_OV_FAULT_RESPONSE: %02X", u8_value);
/* VOUT_MAX */
smb_read_word(PMBUS_VOUT_MAX, &u16_value);
f_value = ulinear16_2_float(u16_value);
ESP_LOGI(TAG, "Vout Max set to: %.2f V", f_value);
ESP_LOGI(TAG, "read VOUT_MAX: %.2fV", f_value);
/* VOUT_OV_FAULT_LIMIT */
smb_read_word(PMBUS_VOUT_OV_FAULT_LIMIT, &u16_value);
f_value = ulinear16_2_float(u16_value);
ESP_LOGI(TAG, "Vout OV Fault Limit: %.2f V", f_value);
ESP_LOGI(TAG, "read VOUT_OV_FAULT_LIMIT: %.2fV", f_value * tps546_config.TPS546_INIT_VOUT_COMMAND);
/* VOUT_OV_WARN_LIMIT */
smb_read_word(PMBUS_VOUT_OV_WARN_LIMIT, &u16_value);
f_value = ulinear16_2_float(u16_value);
ESP_LOGI(TAG, "Vout OV Warn Limit: %.2f V", f_value);
ESP_LOGI(TAG, "read VOUT_OV_WARN_LIMIT: %.2fV", f_value * tps546_config.TPS546_INIT_VOUT_COMMAND);
/* VOUT_MARGIN_HIGH */
smb_read_word(PMBUS_VOUT_MARGIN_HIGH, &u16_value);
f_value = ulinear16_2_float(u16_value);
ESP_LOGI(TAG, "Vout Margin HIGH: %.2f V", f_value);
ESP_LOGI(TAG, "read VOUT_MARGIN_HIGH: %.2fV", f_value * tps546_config.TPS546_INIT_VOUT_COMMAND);
/* --- VOUT_COMMAND --- */
smb_read_word(PMBUS_VOUT_COMMAND, &u16_value);
f_value = ulinear16_2_float(u16_value);
ESP_LOGI(TAG, "Vout set to: %.2f V", f_value);
ESP_LOGI(TAG, "read VOUT_COMMAND: %.2fV", f_value);
/* VOUT_MARGIN_LOW */
smb_read_word(PMBUS_VOUT_MARGIN_LOW, &u16_value);
f_value = ulinear16_2_float(u16_value);
ESP_LOGI(TAG, "Vout Margin LOW: %.2f V", f_value);
ESP_LOGI(TAG, "read VOUT_MARGIN_LOW: %.2fV", f_value * tps546_config.TPS546_INIT_VOUT_COMMAND);
/* VOUT_UV_WARN_LIMIT */
smb_read_word(PMBUS_VOUT_UV_WARN_LIMIT, &u16_value);
f_value = ulinear16_2_float(u16_value);
ESP_LOGI(TAG, "Vout UV Warn Limit: %.2f V", f_value);
ESP_LOGI(TAG, "read VOUT_UV_WARN_LIMIT: %.2fV", f_value * tps546_config.TPS546_INIT_VOUT_COMMAND);
/* VOUT_UV_FAULT_LIMIT */
smb_read_word(PMBUS_VOUT_UV_FAULT_LIMIT, &u16_value);
f_value = ulinear16_2_float(u16_value);
ESP_LOGI(TAG, "Vout UV Fault Limit: %.2f V", f_value);
ESP_LOGI(TAG, "read VOUT_UV_FAULT_LIMIT: %.2fV", f_value * tps546_config.TPS546_INIT_VOUT_COMMAND);
/* VOUT_MIN */
smb_read_word(PMBUS_VOUT_MIN, &u16_value);
f_value = ulinear16_2_float(u16_value);
ESP_LOGI(TAG, "Vout Min set to: %.2f V", f_value);
ESP_LOGI(TAG, "read VOUT_MIN: %.2f V", f_value);
}

View File

@ -1,6 +1,9 @@
#ifndef TPS546_H_
#define TPS546_H_
#include <stdint.h>
#include <esp_err.h>
#define TPS546_I2CADDR 0x24 //< TPS546 i2c address
#define TPS546_MANUFACTURER_ID 0xFE //< Manufacturer ID
#define TPS546_REVISION 0xFF //< Chip revision
@ -14,30 +17,49 @@
#define OPERATION_OFF 0x00
#define OPERATION_ON 0x80
#define TPS546_INIT_PHASE 0x00 /* phase */
#define TPS546_INIT_FREQUENCY 650 /* KHz */
typedef struct
{
/* vin voltage */
float TPS546_INIT_VIN_ON; /* V */
float TPS546_INIT_VIN_OFF; /* V */
float TPS546_INIT_VIN_UV_WARN_LIMIT; /* V */
float TPS546_INIT_VIN_OV_FAULT_LIMIT; /* V */
/* vout voltage */
float TPS546_INIT_SCALE_LOOP; /* Voltage Scale factor */
float TPS546_INIT_VOUT_MIN; /* V */
float TPS546_INIT_VOUT_MAX; /* V */
float TPS546_INIT_VOUT_COMMAND; /* V absolute value */
/* iout current */
float TPS546_INIT_IOUT_OC_WARN_LIMIT; /* A */
float TPS546_INIT_IOUT_OC_FAULT_LIMIT; /* A */
} TPS546_CONFIG;
/* vin voltage */
#define TPS546_INIT_VIN_ON 4.8 /* V */
#define TPS546_INIT_VIN_OFF 4.5 /* V */
#define TPS546_INIT_VIN_UV_WARN_LIMIT 5.8 /* V */
#define TPS546_INIT_VIN_OV_FAULT_LIMIT 6.0 /* V */
// #define TPS546_INIT_VIN_ON 11.0 /* V */
// #define TPS546_INIT_VIN_OFF 10.5 /* V */
// #define TPS546_INIT_VIN_UV_WARN_LIMIT 14.0 /* V */
// #define TPS546_INIT_VIN_OV_FAULT_LIMIT 15.0 /* V */
#define TPS546_INIT_VIN_OV_FAULT_RESPONSE 0xB7 /* retry 6 times */
/* vout voltage */
#define TPS546_INIT_SCALE_LOOP 0.25 /* Voltage Scale factor */
#define TPS546_INIT_VOUT_MAX 3 /* V */
//#define TPS546_INIT_SCALE_LOOP 0.25 /* Voltage Scale factor */
//#define TPS546_INIT_VOUT_MAX 3 /* V */
#define TPS546_INIT_VOUT_OV_FAULT_LIMIT 1.25 /* %/100 above VOUT_COMMAND */
#define TPS546_INIT_VOUT_OV_WARN_LIMIT 1.1 /* %/100 above VOUT_COMMAND */
#define TPS546_INIT_VOUT_MARGIN_HIGH 1.1 /* %/100 above VOUT */
#define TPS546_INIT_VOUT_COMMAND 1.2 /* V absolute value */
//#define TPS546_INIT_VOUT_COMMAND 1.2 /* V absolute value */
#define TPS546_INIT_VOUT_MARGIN_LOW 0.90 /* %/100 below VOUT */
#define TPS546_INIT_VOUT_UV_WARN_LIMIT 0.90 /* %/100 below VOUT_COMMAND */
#define TPS546_INIT_VOUT_UV_FAULT_LIMIT 0.75 /* %/100 below VOUT_COMMAND */
#define TPS546_INIT_VOUT_MIN 1 /* v */
//#define TPS546_INIT_VOUT_MIN 1 /* v */
/* iout current */
#define TPS546_INIT_IOUT_OC_WARN_LIMIT 25.00 /* A */
#define TPS546_INIT_IOUT_OC_FAULT_LIMIT 30.00 /* A */
// #define TPS546_INIT_IOUT_OC_WARN_LIMIT 50.00 /* A */
// #define TPS546_INIT_IOUT_OC_FAULT_LIMIT 55.00 /* A */
#define TPS546_INIT_IOUT_OC_FAULT_RESPONSE 0xC0 /* shut down, no retries */
/* temperature */
@ -54,9 +76,9 @@
#define TPS546_INIT_TOFF_DELAY 0
#define TPS546_INIT_TOFF_FALL 0
#define INIT_STACK_CONFIG 0x0000
#define INIT_SYNC_CONFIG 0x0010
#define INIT_PIN_DETECT_OVERRIDE 0x0000
#define INIT_STACK_CONFIG 0x0001 //One-Slave, 2-phase
#define INIT_SYNC_CONFIG 0x00D0 //Enable Auto Detect SYNC
#define INIT_PIN_DETECT_OVERRIDE 0xFFFF //use pin values
/*-------------------------*/
@ -67,9 +89,26 @@
#define ON_OFF_CONFIG_POLARITY 0x00 // turn off POLARITY bit
#define ON_OFF_CONFIG_DELAY 0x00 // turn off DELAY bit
//// STATUS_WORD Offsets
#define TPS546_STATUS_VOUT 0x8000 //bit 15
#define TPS546_STATUS_IOUT 0x4000
#define TPS546_STATUS_INPUT 0x2000
#define TPS546_STATUS_MFR 0x1000
#define TPS546_STATUS_PGOOD 0x0800
#define TPS546_STATUS_OTHER 0x0200
#define TPS546_STATUS_BUSY 0x0080
#define TPS546_STATUS_OFF 0x0040
#define TPS546_STATUS_VOUT_OV 0x0020
#define TPS546_STATUS_IOUT_OC 0x0010
#define TPS546_STATUS_VIN_UV 0x0008
#define TPS546_STATUS_TEMP 0x0004
#define TPS546_STATUS_CML 0x0002
#define TPS546_STATUS_NONE 0x0001
/* public functions */
int TPS546_init(void);
esp_err_t TPS546_init(TPS546_CONFIG config);
void TPS546_read_mfr_info(uint8_t *);
void TPS546_set_mfr_info(void);
void TPS546_write_entire_config(void);
@ -79,8 +118,12 @@ int TPS546_get_temperature(void);
float TPS546_get_vin(void);
float TPS546_get_iout(void);
float TPS546_get_vout(void);
void TPS546_set_vout(float volts);
esp_err_t TPS546_set_vout(float volts);
void TPS546_show_voltage_settings(void);
void TPS546_print_status(void);
esp_err_t TPS546_check_status(uint16_t *);
esp_err_t TPS546_parse_status(uint16_t status);
esp_err_t TPS546_clear_faults(void);
#endif /* TPS546_H_ */

147
main/power/power.c Normal file
View File

@ -0,0 +1,147 @@
#include "TPS546.h"
#include "INA260.h"
#include "DS4432U.h"
#include "power.h"
#include "vcore.h"
#define GPIO_ASIC_ENABLE CONFIG_GPIO_ASIC_ENABLE
#define SUPRA_POWER_OFFSET 5 //Watts
#define GAMMA_POWER_OFFSET 5 //Watts
#define GAMMATURBO_POWER_OFFSET 5 //Watts
esp_err_t Power_disable(GlobalState * GLOBAL_STATE) {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
if (GLOBAL_STATE->board_version >= 402 && GLOBAL_STATE->board_version <= 499) {
// Turn off core voltage
VCORE_set_voltage(0.0, GLOBAL_STATE);
} else if (GLOBAL_STATE->board_version == 202 || GLOBAL_STATE->board_version == 203 || GLOBAL_STATE->board_version == 204) {
gpio_set_level(GPIO_ASIC_ENABLE, 1);
}
break;
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
// Turn off core voltage
VCORE_set_voltage(0.0, GLOBAL_STATE);
break;
default:
}
return ESP_OK;
}
float Power_get_current(GlobalState * GLOBAL_STATE) {
float current = 0.0;
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
if (GLOBAL_STATE->board_version >= 402 && GLOBAL_STATE->board_version <= 499) {
current = TPS546_get_iout() * 1000.0;
} else {
if (INA260_installed() == true) {
current = INA260_read_current();
}
}
break;
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
current = TPS546_get_iout() * 1000.0;
break;
default:
}
return current;
}
float Power_get_power(GlobalState * GLOBAL_STATE) {
float power = 0.0;
float current = 0.0;
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
if (GLOBAL_STATE->board_version >= 402 && GLOBAL_STATE->board_version <= 499) {
current = TPS546_get_iout() * 1000.0;
// calculate regulator power (in milliwatts)
power = (TPS546_get_vout() * current) / 1000.0;
// The power reading from the TPS546 is only it's output power. So the rest of the Bitaxe power is not accounted for.
power += SUPRA_POWER_OFFSET; // Add offset for the rest of the Bitaxe power. TODO: this better.
} else {
if (INA260_installed() == true) {
power = INA260_read_power() / 1000.0;
}
}
break;
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
current = TPS546_get_iout() * 1000.0;
// calculate regulator power (in milliwatts)
power = (TPS546_get_vout() * current) / 1000.0;
// The power reading from the TPS546 is only it's output power. So the rest of the Bitaxe power is not accounted for.
power += GAMMATURBO_POWER_OFFSET; // Add offset for the rest of the Bitaxe power. TODO: this better.
break;
default:
}
return power;
}
float Power_get_input_voltage(GlobalState * GLOBAL_STATE) {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
if (GLOBAL_STATE->board_version >= 402 && GLOBAL_STATE->board_version <= 499) {
return TPS546_get_vin() * 1000.0;
} else {
if (INA260_installed() == true) {
return INA260_read_voltage();
}
}
break;
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
return TPS546_get_vin() * 1000.0;
break;
default:
}
return 0.0;
}
float Power_get_vreg_temp(GlobalState * GLOBAL_STATE) {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
if (GLOBAL_STATE->board_version >= 402 && GLOBAL_STATE->board_version <= 499) {
return TPS546_get_temperature();
} else {
if (INA260_installed() == true) {
return 0.0;
}
}
break;
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
return TPS546_get_temperature();
break;
default:
}
return 0.0;
}

15
main/power/power.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef POWER_H
#define POWER_H
#include <esp_err.h>
#include "global_state.h"
esp_err_t Power_disable(GlobalState * GLOBAL_STATE);
float Power_get_current(GlobalState * GLOBAL_STATE);
float Power_get_power(GlobalState * GLOBAL_STATE);
float Power_get_input_voltage(GlobalState * GLOBAL_STATE);
float Power_get_vreg_temp(GlobalState * GLOBAL_STATE);
#endif // POWER_H

146
main/power/vcore.c Normal file
View File

@ -0,0 +1,146 @@
#include <stdio.h>
#include <math.h>
#include "esp_log.h"
#include "vcore.h"
#include "adc.h"
#include "DS4432U.h"
#include "TPS546.h"
#include "INA260.h"
#define GPIO_ASIC_ENABLE CONFIG_GPIO_ASIC_ENABLE
#define GPIO_ASIC_RESET CONFIG_GPIO_ASIC_RESET
#define GPIO_PLUG_SENSE CONFIG_GPIO_PLUG_SENSE
static TPS546_CONFIG TPS546_CONFIG_GAMMATURBO = {
/* vin voltage */
.TPS546_INIT_VIN_ON = 11.0,
.TPS546_INIT_VIN_OFF = 10.5,
.TPS546_INIT_VIN_UV_WARN_LIMIT = 11.0,
.TPS546_INIT_VIN_OV_FAULT_LIMIT = 14.0,
/* vout voltage */
.TPS546_INIT_SCALE_LOOP = 0.25,
.TPS546_INIT_VOUT_MIN = 1,
.TPS546_INIT_VOUT_MAX = 3,
.TPS546_INIT_VOUT_COMMAND = 1.2,
/* iout current */
.TPS546_INIT_IOUT_OC_WARN_LIMIT = 50.00, /* A */
.TPS546_INIT_IOUT_OC_FAULT_LIMIT = 55.00 /* A */
};
static TPS546_CONFIG TPS546_CONFIG_GAMMA = {
/* vin voltage */
.TPS546_INIT_VIN_ON = 4.8,
.TPS546_INIT_VIN_OFF = 4.5,
.TPS546_INIT_VIN_UV_WARN_LIMIT = 0, //Set to 0 to ignore. TI Bug in this register
.TPS546_INIT_VIN_OV_FAULT_LIMIT = 5.5,
/* vout voltage */
.TPS546_INIT_SCALE_LOOP = 0.25,
.TPS546_INIT_VOUT_MIN = 1,
.TPS546_INIT_VOUT_MAX = 2,
.TPS546_INIT_VOUT_COMMAND = 1.2,
/* iout current */
.TPS546_INIT_IOUT_OC_WARN_LIMIT = 25.00, /* A */
.TPS546_INIT_IOUT_OC_FAULT_LIMIT = 30.00 /* A */
};
static const char *TAG = "vcore.c";
esp_err_t VCORE_init(GlobalState * GLOBAL_STATE) {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
if (GLOBAL_STATE->board_version >= 402 && GLOBAL_STATE->board_version <= 499) {
if (TPS546_init(TPS546_CONFIG_GAMMA) != ESP_OK) {
ESP_LOGE(TAG, "TPS546 init failed!");
return ESP_FAIL;
}
} else {
ESP_RETURN_ON_ERROR(DS4432U_init(), TAG, "DS4432 init failed!");
ESP_RETURN_ON_ERROR(INA260_init(), TAG, "INA260 init failed!");
}
break;
case DEVICE_GAMMA:
ESP_RETURN_ON_ERROR(TPS546_init(TPS546_CONFIG_GAMMA), TAG, "TPS546 init failed!");
break;
case DEVICE_GAMMATURBO:
ESP_RETURN_ON_ERROR(TPS546_init(TPS546_CONFIG_GAMMATURBO), TAG, "TPS546 init failed!");
break;
// case DEVICE_HEX:
default:
}
//configure plug sense, if present
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
if (GLOBAL_STATE->board_version < 402 || GLOBAL_STATE->board_version > 499) {
// Configure plug sense pin as input(barrel jack) 1 is plugged in
gpio_config_t barrel_jack_conf = {
.pin_bit_mask = (1ULL << GPIO_PLUG_SENSE),
.mode = GPIO_MODE_INPUT,
};
gpio_config(&barrel_jack_conf);
int barrel_jack_plugged_in = gpio_get_level(GPIO_PLUG_SENSE);
gpio_set_direction(GPIO_ASIC_ENABLE, GPIO_MODE_OUTPUT);
if (barrel_jack_plugged_in == 1 || GLOBAL_STATE->board_version != 204) {
// turn ASIC on
gpio_set_level(GPIO_ASIC_ENABLE, 0);
} else {
// turn ASIC off
gpio_set_level(GPIO_ASIC_ENABLE, 1);
}
}
break;
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
break;
default:
}
return ESP_OK;
}
esp_err_t VCORE_set_voltage(float core_voltage, GlobalState * global_state)
{
switch (global_state->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
if (global_state->board_version >= 402 && global_state->board_version <= 499) {
ESP_LOGI(TAG, "Set ASIC voltage = %.3fV", core_voltage);
ESP_RETURN_ON_ERROR(TPS546_set_vout(core_voltage), TAG, "TPS546 set voltage failed!");
} else {
ESP_LOGI(TAG, "Set ASIC voltage = %.3fV", core_voltage);
ESP_RETURN_ON_ERROR(DS4432U_set_voltage(core_voltage), TAG, "DS4432U set voltage failed!");
}
break;
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
ESP_LOGI(TAG, "Set ASIC voltage = %.3fV", core_voltage);
ESP_RETURN_ON_ERROR(TPS546_set_vout(core_voltage), TAG, "TPS546 set voltage failed!");
break;
// case DEVICE_HEX:
default:
}
return ESP_OK;
}
int16_t VCORE_get_voltage_mv(GlobalState * global_state) {
switch (global_state->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
return ADC_get_vcore();
// case DEVICE_HEX:
default:
}
return -1;
}

View File

@ -5,6 +5,6 @@
esp_err_t VCORE_init(GlobalState * global_state);
esp_err_t VCORE_set_voltage(float core_voltage, GlobalState * global_state);
uint16_t VCORE_get_voltage_mv(GlobalState * global_state);
int16_t VCORE_get_voltage_mv(GlobalState * global_state);
#endif /* VCORE_H_ */

View File

@ -23,6 +23,8 @@ static lv_obj_t *efficiency_label;
static lv_obj_t *difficulty_label;
static lv_obj_t *chip_temp_label;
static lv_obj_t *firmware_update_scr_filename_label;
static lv_obj_t *firmware_update_scr_status_label;
static lv_obj_t *ip_addr_scr_overheat_label;
static lv_obj_t *ip_addr_scr_urls_label;
static lv_obj_t *mining_url_scr_urls_label;
@ -35,7 +37,7 @@ static lv_obj_t *self_test_finished_label;
static double current_hashrate;
static float current_power;
static uint64_t current_difficulty;
static float curreny_chip_temp;
static float current_chip_temp;
static bool found_block;
#define SCREEN_UPDATE_MS 500
@ -97,7 +99,7 @@ static lv_obj_t * create_scr_invalid_asic(SystemModule * module) {
lv_label_set_text(label1, "ASIC MODEL INVALID");
lv_obj_t *label2 = lv_label_create(scr);
lv_label_set_text(label2, "Configuration SSID:");
lv_label_set_text(label2, "Wi-Fi (for setup):");
lv_obj_t *label3 = lv_label_create(scr);
lv_label_set_text(label3, module->ap_ssid);
@ -113,11 +115,15 @@ static lv_obj_t * create_scr_configure(SystemModule * module) {
lv_obj_t *label1 = lv_label_create(scr);
lv_obj_set_width(label1, LV_HOR_RES);
lv_obj_set_style_anim_duration(label1, 15000, LV_PART_MAIN);
lv_label_set_long_mode(label1, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_label_set_text(label1, "Welcome to your new Bitaxe! Connect to the configuration Wifi and connect the Bitaxe to your network.");
lv_label_set_text(label1, "Welcome to your new Bitaxe! Connect to the configuration Wi-Fi and connect the Bitaxe to your network.");
// skip a line, it looks nicer this way
lv_label_create(scr);
lv_obj_t *label2 = lv_label_create(scr);
lv_label_set_text(label2, "Configuration SSID:");
lv_label_set_text(label2, "Wi-Fi (for setup):");
lv_obj_t *label3 = lv_label_create(scr);
lv_label_set_text(label3, module->ap_ssid);
@ -125,6 +131,23 @@ static lv_obj_t * create_scr_configure(SystemModule * module) {
return scr;
}
static lv_obj_t * create_scr_ota(SystemModule * module) {
lv_obj_t * scr = lv_obj_create(NULL);
lv_obj_set_flex_flow(scr, LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(scr, LV_FLEX_ALIGN_SPACE_EVENLY, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START);
lv_obj_t *label1 = lv_label_create(scr);
lv_obj_set_width(label1, LV_HOR_RES);
lv_label_set_text(label1, "Firmware update");
firmware_update_scr_filename_label = lv_label_create(scr);
firmware_update_scr_status_label = lv_label_create(scr);
return scr;
}
static lv_obj_t * create_scr_connection(SystemModule * module) {
lv_obj_t * scr = lv_obj_create(NULL);
@ -134,13 +157,13 @@ static lv_obj_t * create_scr_connection(SystemModule * module) {
lv_obj_t *label1 = lv_label_create(scr);
lv_obj_set_width(label1, LV_HOR_RES);
lv_label_set_long_mode(label1, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_label_set_text_fmt(label1, "SSID: %s", module->ssid);
lv_label_set_text_fmt(label1, "Wi-Fi: %s", module->ssid);
wifi_status_label = lv_label_create(scr);
lv_label_set_text(wifi_status_label, module->wifi_status);
lv_obj_t *label3 = lv_label_create(scr);
lv_label_set_text(label3, "Configuration SSID:");
lv_label_set_text(label3, "Wi-Fi (for setup):");
lv_obj_t *label4 = lv_label_create(scr);
lv_label_set_text(label4, module->ap_ssid);
@ -188,16 +211,16 @@ static lv_obj_t * create_scr_stats() {
lv_obj_set_flex_align(scr, LV_FLEX_ALIGN_SPACE_EVENLY, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START);
hashrate_label = lv_label_create(scr);
lv_label_set_text(hashrate_label, "Gh/s: n/a");
lv_label_set_text(hashrate_label, "Gh/s: --");
efficiency_label = lv_label_create(scr);
lv_label_set_text(efficiency_label, "J/Th: n/a");
lv_label_set_text(efficiency_label, "J/Th: --");
difficulty_label = lv_label_create(scr);
lv_label_set_text(difficulty_label, "Best: n/a");
lv_label_set_text(difficulty_label, "Best: --");
chip_temp_label = lv_label_create(scr);
lv_label_set_text(chip_temp_label, "Temp: n/a");
lv_label_set_text(chip_temp_label, "Temp: --");
return scr;
}
@ -236,7 +259,18 @@ static void screen_update_cb(lv_timer_t * timer)
return;
}
if (GLOBAL_STATE->ASIC_functions.init_fn == NULL) {
if (GLOBAL_STATE->SYSTEM_MODULE.is_firmware_update) {
if (strcmp(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_filename, lv_label_get_text(firmware_update_scr_filename_label)) != 0) {
lv_label_set_text(firmware_update_scr_filename_label, GLOBAL_STATE->SYSTEM_MODULE.firmware_update_filename);
}
if (strcmp(GLOBAL_STATE->SYSTEM_MODULE.firmware_update_status, lv_label_get_text(firmware_update_scr_status_label)) != 0) {
lv_label_set_text(firmware_update_scr_status_label, GLOBAL_STATE->SYSTEM_MODULE.firmware_update_status);
}
screen_show(SCR_FIRMWARE_UPDATE);
return;
}
if (GLOBAL_STATE->valid_model == false) {
screen_show(SCR_INVALID_ASIC);
return;
}
@ -319,14 +353,14 @@ static void screen_update_cb(lv_timer_t * timer)
}
}
if (curreny_chip_temp != power_management->chip_temp_avg) {
if (current_chip_temp != power_management->chip_temp_avg && power_management->chip_temp_avg > 0) {
lv_label_set_text_fmt(chip_temp_label, "Temp: %.1f C", power_management->chip_temp_avg);
}
current_hashrate = module->current_hashrate;
current_power = power_management->power;
current_difficulty = module->best_session_nonce_diff;
curreny_chip_temp = power_management->chip_temp_avg;
current_chip_temp = power_management->chip_temp_avg;
if (CAROUSEL_DELAY_COUNT > current_screen_counter || found_block) {
return;
@ -353,6 +387,7 @@ esp_err_t screen_start(void * pvParameters)
screens[SCR_OVERHEAT] = create_scr_overheat(module);
screens[SCR_INVALID_ASIC] = create_scr_invalid_asic(module);
screens[SCR_CONFIGURE] = create_scr_configure(module);
screens[SCR_FIRMWARE_UPDATE] = create_scr_ota(module);
screens[SCR_CONNECTION] = create_scr_connection(module);
screens[SCR_LOGO] = create_scr_logo();
screens[SCR_URLS] = create_scr_urls(module);

View File

@ -6,6 +6,7 @@ typedef enum {
SCR_OVERHEAT,
SCR_INVALID_ASIC,
SCR_CONFIGURE,
SCR_FIRMWARE_UPDATE,
SCR_CONNECTION,
SCR_LOGO,
SCR_URLS,

View File

@ -23,6 +23,8 @@
#include "TPS546.h"
#include "esp_psram.h"
#include "asic.h"
#define GPIO_ASIC_ENABLE CONFIG_GPIO_ASIC_ENABLE
#define TESTS_FAILED 0
@ -366,11 +368,12 @@ void self_test(void * pvParameters)
tests_done(GLOBAL_STATE, TESTS_FAILED);
}
uint8_t chips_detected = (GLOBAL_STATE->ASIC_functions.init_fn)(GLOBAL_STATE->POWER_MANAGEMENT_MODULE.frequency_value, GLOBAL_STATE->asic_count);
ESP_LOGI(TAG, "%u chips detected, %u expected", chips_detected, GLOBAL_STATE->asic_count);
uint8_t chips_detected = ASIC_init(GLOBAL_STATE);
uint8_t chips_expected = ASIC_get_asic_count(GLOBAL_STATE);
ESP_LOGI(TAG, "%u chips detected, %u expected", chips_detected, chips_expected);
if (chips_detected != GLOBAL_STATE->asic_count) {
ESP_LOGE(TAG, "SELF TEST FAIL, %d of %d CHIPS DETECTED", chips_detected, GLOBAL_STATE->asic_count);
if (chips_detected != chips_expected) {
ESP_LOGE(TAG, "SELF TEST FAIL, %d of %d CHIPS DETECTED", chips_detected, chips_expected);
char error_buf[20];
snprintf(error_buf, 20, "ASIC:FAIL %d CHIPS", chips_detected);
display_msg(error_buf, GLOBAL_STATE);
@ -378,7 +381,7 @@ void self_test(void * pvParameters)
}
//setup and test hashrate
int baud = (*GLOBAL_STATE->ASIC_functions.set_max_baud_fn)();
int baud = ASIC_set_max_baud(GLOBAL_STATE);
vTaskDelay(10 / portTICK_PERIOD_MS);
if (SERIAL_set_baud(baud) != ESP_OK) {
@ -437,11 +440,13 @@ void self_test(void * pvParameters)
uint8_t difficulty_mask = 8;
(*GLOBAL_STATE->ASIC_functions.set_difficulty_mask_fn)(difficulty_mask);
//(*GLOBAL_STATE->ASIC_functions.set_difficulty_mask_fn)(difficulty_mask);
ASIC_set_job_difficulty_mask(GLOBAL_STATE, difficulty_mask);
ESP_LOGI(TAG, "Sending work");
(*GLOBAL_STATE->ASIC_functions.send_work_fn)(GLOBAL_STATE, &job);
//(*GLOBAL_STATE->ASIC_functions.send_work_fn)(GLOBAL_STATE, &job);
ASIC_send_work(GLOBAL_STATE, &job);
double start = esp_timer_get_time();
double sum = 0;
@ -449,7 +454,7 @@ void self_test(void * pvParameters)
double hash_rate = 0;
while(duration < 3){
task_result * asic_result = (*GLOBAL_STATE->ASIC_functions.receive_result_fn)(GLOBAL_STATE);
task_result * asic_result = ASIC_process_work(GLOBAL_STATE);
if (asic_result != NULL) {
// check the nonce difficulty
double nonce_diff = test_nonce_value(&job, asic_result->nonce, asic_result->rolled_version);

View File

@ -20,7 +20,6 @@
#include "system.h"
#include "i2c_bitaxe.h"
#include "EMC2101.h"
#include "INA260.h"
#include "adc.h"
#include "connect.h"
@ -29,6 +28,7 @@
#include "input.h"
#include "screen.h"
#include "vcore.h"
#include "thermal.h"
static const char * TAG = "SystemModule";
@ -63,10 +63,18 @@ void SYSTEM_init_system(GlobalState * GLOBAL_STATE)
module->pool_url = nvs_config_get_string(NVS_CONFIG_STRATUM_URL, CONFIG_STRATUM_URL);
module->fallback_pool_url = nvs_config_get_string(NVS_CONFIG_FALLBACK_STRATUM_URL, CONFIG_FALLBACK_STRATUM_URL);
//set the pool port
// set the pool port
module->pool_port = nvs_config_get_u16(NVS_CONFIG_STRATUM_PORT, CONFIG_STRATUM_PORT);
module->fallback_pool_port = nvs_config_get_u16(NVS_CONFIG_FALLBACK_STRATUM_PORT, CONFIG_FALLBACK_STRATUM_PORT);
// set the pool user
module->pool_user = nvs_config_get_string(NVS_CONFIG_STRATUM_USER, CONFIG_STRATUM_USER);
module->fallback_pool_user = nvs_config_get_string(NVS_CONFIG_FALLBACK_STRATUM_USER, CONFIG_FALLBACK_STRATUM_USER);
// set the pool password
module->pool_pass = nvs_config_get_string(NVS_CONFIG_STRATUM_PASS, CONFIG_STRATUM_PW);
module->fallback_pool_pass = nvs_config_get_string(NVS_CONFIG_FALLBACK_STRATUM_PASS, CONFIG_FALLBACK_STRATUM_PW);
// set fallback to false.
module->is_using_fallback = false;
@ -90,33 +98,7 @@ void SYSTEM_init_peripherals(GlobalState * GLOBAL_STATE) {
VCORE_init(GLOBAL_STATE);
VCORE_set_voltage(nvs_config_get_u16(NVS_CONFIG_ASIC_VOLTAGE, CONFIG_ASIC_VOLTAGE) / 1000.0, GLOBAL_STATE);
//init the EMC2101, if we have one
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
EMC2101_init(nvs_config_get_u16(NVS_CONFIG_INVERT_FAN_POLARITY, 1));
break;
case DEVICE_GAMMA:
EMC2101_init(nvs_config_get_u16(NVS_CONFIG_INVERT_FAN_POLARITY, 1));
EMC2101_set_ideality_factor(EMC2101_IDEALITY_1_0319);
EMC2101_set_beta_compensation(EMC2101_BETA_11);
break;
default:
}
//initialize the INA260, if we have one.
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
if (GLOBAL_STATE->board_version < 402) {
INA260_init();
}
break;
case DEVICE_GAMMA:
default:
}
Thermal_init(GLOBAL_STATE->device_model, nvs_config_get_u16(NVS_CONFIG_INVERT_FAN_POLARITY, 1));
vTaskDelay(500 / portTICK_PERIOD_MS);
@ -132,6 +114,7 @@ void SYSTEM_init_peripherals(GlobalState * GLOBAL_STATE) {
case DEVICE_ULTRA:
case DEVICE_SUPRA:
case DEVICE_GAMMA:
case DEVICE_GAMMATURBO:
// display
if (display_init(GLOBAL_STATE) != ESP_OK || !GLOBAL_STATE->SYSTEM_MODULE.is_screen_active) {
ESP_LOGW(TAG, "OLED init failed!");
@ -160,11 +143,38 @@ void SYSTEM_notify_accepted_share(GlobalState * GLOBAL_STATE)
module->shares_accepted++;
}
void SYSTEM_notify_rejected_share(GlobalState * GLOBAL_STATE)
static int compare_rejected_reason_stats(const void *a, const void *b) {
const RejectedReasonStat *ea = a;
const RejectedReasonStat *eb = b;
return (eb->count > ea->count) - (ea->count > eb->count);
}
void SYSTEM_notify_rejected_share(GlobalState * GLOBAL_STATE, char * error_msg)
{
SystemModule * module = &GLOBAL_STATE->SYSTEM_MODULE;
module->shares_rejected++;
for (int i = 0; i < module->rejected_reason_stats_count; i++) {
if (strncmp(module->rejected_reason_stats[i].message, error_msg, sizeof(module->rejected_reason_stats[i].message) - 1) == 0) {
module->rejected_reason_stats[i].count++;
return;
}
}
if (module->rejected_reason_stats_count < sizeof(module->rejected_reason_stats)) {
strncpy(module->rejected_reason_stats[module->rejected_reason_stats_count].message,
error_msg,
sizeof(module->rejected_reason_stats[module->rejected_reason_stats_count].message) - 1);
module->rejected_reason_stats[module->rejected_reason_stats_count].message[sizeof(module->rejected_reason_stats[module->rejected_reason_stats_count].message) - 1] = '\0'; // Ensure null termination
module->rejected_reason_stats[module->rejected_reason_stats_count].count = 1;
module->rejected_reason_stats_count++;
}
if (module->rejected_reason_stats_count > 1) {
qsort(module->rejected_reason_stats, module->rejected_reason_stats_count,
sizeof(module->rejected_reason_stats[0]), compare_rejected_reason_stats);
}
}
void SYSTEM_notify_mining_started(GlobalState * GLOBAL_STATE)

View File

@ -7,7 +7,7 @@ void SYSTEM_init_system(GlobalState * GLOBAL_STATE);
void SYSTEM_init_peripherals(GlobalState * GLOBAL_STATE);
void SYSTEM_notify_accepted_share(GlobalState * GLOBAL_STATE);
void SYSTEM_notify_rejected_share(GlobalState * GLOBAL_STATE);
void SYSTEM_notify_rejected_share(GlobalState * GLOBAL_STATE, char * error_msg);
void SYSTEM_notify_found_nonce(GlobalState * GLOBAL_STATE, double found_diff, uint8_t job_id);
void SYSTEM_notify_mining_started(GlobalState * GLOBAL_STATE);
void SYSTEM_notify_new_ntime(GlobalState * GLOBAL_STATE, uint32_t ntime);

View File

@ -1,3 +1,5 @@
#include <lwip/tcpip.h>
#include "system.h"
#include "work_queue.h"
#include "serial.h"
@ -7,7 +9,7 @@
#include "nvs_config.h"
#include "utils.h"
#include "stratum_task.h"
#include <lwip/tcpip.h>
#include "asic.h"
static const char *TAG = "asic_result";
@ -17,7 +19,8 @@ void ASIC_result_task(void *pvParameters)
while (1)
{
task_result *asic_result = (*GLOBAL_STATE->ASIC_functions.receive_result_fn)(GLOBAL_STATE);
//task_result *asic_result = (*GLOBAL_STATE->ASIC_functions.receive_result_fn)(GLOBAL_STATE);
task_result *asic_result = ASIC_process_work(GLOBAL_STATE);
if (asic_result == NULL)
{
@ -28,7 +31,7 @@ void ASIC_result_task(void *pvParameters)
if (GLOBAL_STATE->valid_jobs[job_id] == 0)
{
ESP_LOGI(TAG, "Invalid job nonce found, 0x%02X", job_id);
ESP_LOGW(TAG, "Invalid job nonce found, 0x%02X", job_id);
continue;
}
@ -41,18 +44,18 @@ void ASIC_result_task(void *pvParameters)
//log the ASIC response
ESP_LOGI(TAG, "Ver: %08" PRIX32 " Nonce %08" PRIX32 " diff %.1f of %ld.", asic_result->rolled_version, asic_result->nonce, nonce_diff, GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->pool_diff);
if (nonce_diff > GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->pool_diff)
if (nonce_diff >= GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->pool_diff)
{
char * user = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? nvs_config_get_string(NVS_CONFIG_FALLBACK_STRATUM_USER, FALLBACK_STRATUM_USER) : nvs_config_get_string(NVS_CONFIG_STRATUM_USER, STRATUM_USER);
char * user = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_user : GLOBAL_STATE->SYSTEM_MODULE.pool_user;
int ret = STRATUM_V1_submit_share(
GLOBAL_STATE->sock,
GLOBAL_STATE->send_uid++,
user,
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);
free(user);
if (ret < 0) {
ESP_LOGI(TAG, "Unable to write share to socket. Closing connection. Ret: %d (errno %d: %s)", ret, errno, strerror(errno));

View File

@ -8,6 +8,8 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "asic.h"
static const char *TAG = "ASIC_task";
// static bm_job ** active_jobs; is required to keep track of the active jobs since the
@ -42,7 +44,8 @@ void ASIC_task(void *pvParameters)
GLOBAL_STATE->stratum_difficulty = next_bm_job->pool_diff;
}
(*GLOBAL_STATE->ASIC_functions.send_work_fn)(GLOBAL_STATE, next_bm_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
ASIC_send_work(GLOBAL_STATE, next_bm_job);
// Time to execute the above code is ~0.3ms
// Delay for ASIC(s) to finish the job

View File

@ -1,12 +1,14 @@
#include <sys/time.h>
#include <limits.h>
#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"
#include <sys/time.h>
#include "asic.h"
static const char *TAG = "create_jobs_task";
@ -32,7 +34,8 @@ void create_jobs_task(void *pvParameters)
if (GLOBAL_STATE->new_stratum_version_rolling_msg) {
ESP_LOGI(TAG, "Set chip version rolls %i", (int)(GLOBAL_STATE->version_mask >> 13));
(GLOBAL_STATE->ASIC_functions.set_version_mask)(GLOBAL_STATE->version_mask);
//(GLOBAL_STATE->ASIC_functions.set_version_mask)(GLOBAL_STATE->version_mask);
ASIC_set_version_mask(GLOBAL_STATE, GLOBAL_STATE->version_mask);
GLOBAL_STATE->new_stratum_version_rolling_msg = false;
}

View File

@ -1,7 +1,5 @@
#include <string.h>
#include "EMC2101.h"
#include "INA260.h"
#include "bm1397.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@ -12,10 +10,9 @@
#include "serial.h"
#include "TPS546.h"
#include "vcore.h"
#define GPIO_ASIC_ENABLE CONFIG_GPIO_ASIC_ENABLE
#define GPIO_ASIC_RESET CONFIG_GPIO_ASIC_RESET
#define GPIO_PLUG_SENSE CONFIG_GPIO_PLUG_SENSE
#include "thermal.h"
#include "power.h"
#include "asic.h"
#define POLL_RATE 2000
#define MAX_TEMP 90.0
@ -29,9 +26,6 @@
#define TPS546_THROTTLE_TEMP 105.0
#define TPS546_MAX_TEMP 145.0
#define SUPRA_POWER_OFFSET 5
#define GAMMA_POWER_OFFSET 5
static const char * TAG = "power_management";
// static float _fbound(float value, float lower_bound, float upper_bound)
@ -61,18 +55,10 @@ static double automatic_fan_speed(float chip_temp, GlobalState * GLOBAL_STATE)
double fan_range = 100 - min_fan_speed;
result = ((chip_temp - min_temp) / temp_range) * fan_range + min_fan_speed;
}
PowerManagementModule * power_management = &GLOBAL_STATE->POWER_MANAGEMENT_MODULE;
power_management->fan_perc = result;
Thermal_set_fan_percent(GLOBAL_STATE->device_model, result/100.0);
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
case DEVICE_GAMMA:
float perc = (float) result / 100;
GLOBAL_STATE->POWER_MANAGEMENT_MODULE.fan_perc = perc;
EMC2101_set_fan_speed( perc );
break;
default:
}
return result;
}
@ -86,195 +72,64 @@ void POWER_MANAGEMENT_task(void * pvParameters)
power_management->frequency_multiplier = 1;
power_management->HAS_POWER_EN = GLOBAL_STATE->board_version == 202 || GLOBAL_STATE->board_version == 203 || GLOBAL_STATE->board_version == 204;
power_management->HAS_PLUG_SENSE = GLOBAL_STATE->board_version == 204;
//int last_frequency_increase = 0;
//uint16_t frequency_target = nvs_config_get_u16(NVS_CONFIG_ASIC_FREQ, CONFIG_ASIC_FREQUENCY);
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
if (GLOBAL_STATE->board_version < 402 || GLOBAL_STATE->board_version > 499) {
// Configure plug sense pin as input(barrel jack) 1 is plugged in
gpio_config_t barrel_jack_conf = {
.pin_bit_mask = (1ULL << GPIO_PLUG_SENSE),
.mode = GPIO_MODE_INPUT,
};
gpio_config(&barrel_jack_conf);
int barrel_jack_plugged_in = gpio_get_level(GPIO_PLUG_SENSE);
gpio_set_direction(GPIO_ASIC_ENABLE, GPIO_MODE_OUTPUT);
if (barrel_jack_plugged_in == 1 || !power_management->HAS_PLUG_SENSE) {
// turn ASIC on
gpio_set_level(GPIO_ASIC_ENABLE, 0);
} else {
// turn ASIC off
gpio_set_level(GPIO_ASIC_ENABLE, 1);
}
}
break;
case DEVICE_GAMMA:
break;
default:
}
vTaskDelay(500 / portTICK_PERIOD_MS);
uint16_t last_core_voltage = 0.0;
uint16_t last_asic_frequency = power_management->frequency_value;
while (1) {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
if (GLOBAL_STATE->board_version >= 402 && GLOBAL_STATE->board_version <= 499) {
power_management->voltage = TPS546_get_vin() * 1000;
power_management->current = TPS546_get_iout() * 1000;
// calculate regulator power (in milliwatts)
power_management->power = (TPS546_get_vout() * power_management->current) / 1000;
// The power reading from the TPS546 is only it's output power. So the rest of the Bitaxe power is not accounted for.
power_management->power += SUPRA_POWER_OFFSET; // Add offset for the rest of the Bitaxe power. TODO: this better.
} else {
if (INA260_installed() == true) {
power_management->voltage = INA260_read_voltage();
power_management->current = INA260_read_current();
power_management->power = INA260_read_power() / 1000;
}
}
power_management->voltage = Power_get_input_voltage(GLOBAL_STATE);
power_management->power = Power_get_power(GLOBAL_STATE);
break;
case DEVICE_GAMMA:
power_management->voltage = TPS546_get_vin() * 1000;
power_management->current = TPS546_get_iout() * 1000;
// calculate regulator power (in milliwatts)
power_management->power = (TPS546_get_vout() * power_management->current) / 1000;
// The power reading from the TPS546 is only it's output power. So the rest of the Bitaxe power is not accounted for.
power_management->power += GAMMA_POWER_OFFSET; // Add offset for the rest of the Bitaxe power. TODO: this better.
break;
default:
power_management->fan_rpm = Thermal_get_fan_speed(GLOBAL_STATE->device_model);
power_management->chip_temp_avg = Thermal_get_chip_temp(GLOBAL_STATE);
power_management->vr_temp = Power_get_vreg_temp(GLOBAL_STATE);
// ASIC Thermal Diode will give bad readings if the ASIC is turned off
// if(power_management->voltage < tps546_config.TPS546_INIT_VOUT_MIN){
// goto looper;
// }
//overheat mode if the voltage regulator or ASIC is too hot
if ((power_management->vr_temp > TPS546_THROTTLE_TEMP || power_management->chip_temp_avg > THROTTLE_TEMP) && (power_management->frequency_value > 50 || power_management->voltage > 1000)) {
ESP_LOGE(TAG, "OVERHEAT! VR: %fC ASIC %fC", power_management->vr_temp, power_management->chip_temp_avg );
power_management->fan_perc = 100;
Thermal_set_fan_percent(GLOBAL_STATE->device_model, 1);
// Turn off core voltage
Power_disable(GLOBAL_STATE);
nvs_config_set_u16(NVS_CONFIG_ASIC_VOLTAGE, 1000);
nvs_config_set_u16(NVS_CONFIG_ASIC_FREQ, 50);
nvs_config_set_u16(NVS_CONFIG_FAN_SPEED, 100);
nvs_config_set_u16(NVS_CONFIG_AUTO_FAN_SPEED, 0);
nvs_config_set_u16(NVS_CONFIG_OVERHEAT_MODE, 1);
exit(EXIT_FAILURE);
}
power_management->fan_rpm = EMC2101_get_fan_speed();
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
power_management->chip_temp_avg = GLOBAL_STATE->ASIC_initalized ? EMC2101_get_external_temp() : -1;
if ((power_management->chip_temp_avg > THROTTLE_TEMP) &&
(power_management->frequency_value > 50 || power_management->voltage > 1000)) {
ESP_LOGE(TAG, "OVERHEAT ASIC %fC", power_management->chip_temp_avg );
EMC2101_set_fan_speed(1);
if (power_management->HAS_POWER_EN) {
gpio_set_level(GPIO_ASIC_ENABLE, 1);
}
nvs_config_set_u16(NVS_CONFIG_ASIC_VOLTAGE, 1000);
nvs_config_set_u16(NVS_CONFIG_ASIC_FREQ, 50);
nvs_config_set_u16(NVS_CONFIG_FAN_SPEED, 100);
nvs_config_set_u16(NVS_CONFIG_AUTO_FAN_SPEED, 0);
nvs_config_set_u16(NVS_CONFIG_OVERHEAT_MODE, 1);
exit(EXIT_FAILURE);
}
break;
case DEVICE_ULTRA:
case DEVICE_SUPRA:
if (GLOBAL_STATE->board_version >= 402 && GLOBAL_STATE->board_version <= 499) {
power_management->chip_temp_avg = GLOBAL_STATE->ASIC_initalized ? EMC2101_get_external_temp() : -1;
power_management->vr_temp = (float)TPS546_get_temperature();
} else {
power_management->chip_temp_avg = EMC2101_get_internal_temp() + 5;
power_management->vr_temp = 0.0;
}
// EMC2101 will give bad readings if the ASIC is turned off
if(power_management->voltage < TPS546_INIT_VOUT_MIN){
break;
}
//overheat mode if the voltage regulator or ASIC is too hot
if ((power_management->vr_temp > TPS546_THROTTLE_TEMP || power_management->chip_temp_avg > THROTTLE_TEMP) &&
(power_management->frequency_value > 50 || power_management->voltage > 1000)) {
ESP_LOGE(TAG, "OVERHEAT! VR: %fC ASIC %fC", power_management->vr_temp, power_management->chip_temp_avg );
EMC2101_set_fan_speed(1);
if (GLOBAL_STATE->board_version >= 402 && GLOBAL_STATE->board_version <= 499) {
// Turn off core voltage
VCORE_set_voltage(0.0, GLOBAL_STATE);
} else if (power_management->HAS_POWER_EN) {
gpio_set_level(GPIO_ASIC_ENABLE, 1);
}
nvs_config_set_u16(NVS_CONFIG_ASIC_VOLTAGE, 1000);
nvs_config_set_u16(NVS_CONFIG_ASIC_FREQ, 50);
nvs_config_set_u16(NVS_CONFIG_FAN_SPEED, 100);
nvs_config_set_u16(NVS_CONFIG_AUTO_FAN_SPEED, 0);
nvs_config_set_u16(NVS_CONFIG_OVERHEAT_MODE, 1);
exit(EXIT_FAILURE);
}
break;
case DEVICE_GAMMA:
power_management->chip_temp_avg = GLOBAL_STATE->ASIC_initalized ? EMC2101_get_external_temp() : -1;
power_management->vr_temp = (float)TPS546_get_temperature();
// EMC2101 will give bad readings if the ASIC is turned off
if(power_management->voltage < TPS546_INIT_VOUT_MIN){
break;
}
//overheat mode if the voltage regulator or ASIC is too hot
if ((power_management->vr_temp > TPS546_THROTTLE_TEMP || power_management->chip_temp_avg > THROTTLE_TEMP) &&
(power_management->frequency_value > 50 || power_management->voltage > 1000)) {
ESP_LOGE(TAG, "OVERHEAT! VR: %fC ASIC %fC", power_management->vr_temp, power_management->chip_temp_avg );
EMC2101_set_fan_speed(1);
// Turn off core voltage
VCORE_set_voltage(0.0, GLOBAL_STATE);
nvs_config_set_u16(NVS_CONFIG_ASIC_VOLTAGE, 1000);
nvs_config_set_u16(NVS_CONFIG_ASIC_FREQ, 50);
nvs_config_set_u16(NVS_CONFIG_FAN_SPEED, 100);
nvs_config_set_u16(NVS_CONFIG_AUTO_FAN_SPEED, 0);
nvs_config_set_u16(NVS_CONFIG_OVERHEAT_MODE, 1);
exit(EXIT_FAILURE);
}
break;
default:
}
if (nvs_config_get_u16(NVS_CONFIG_AUTO_FAN_SPEED, 1) == 1) {
power_management->fan_perc = (float)automatic_fan_speed(power_management->chip_temp_avg, GLOBAL_STATE);
} else {
switch (GLOBAL_STATE->device_model) {
case DEVICE_MAX:
case DEVICE_ULTRA:
case DEVICE_SUPRA:
case DEVICE_GAMMA:
float fs = (float) nvs_config_get_u16(NVS_CONFIG_FAN_SPEED, 100);
power_management->fan_perc = fs;
EMC2101_set_fan_speed((float) fs / 100);
break;
default:
}
float fs = (float) nvs_config_get_u16(NVS_CONFIG_FAN_SPEED, 100);
power_management->fan_perc = fs;
Thermal_set_fan_percent(GLOBAL_STATE->device_model, (float) fs / 100.0);
}
// Read the state of plug sense pin
if (power_management->HAS_PLUG_SENSE) {
int gpio_plug_sense_state = gpio_get_level(GPIO_PLUG_SENSE);
if (gpio_plug_sense_state == 0) {
// turn ASIC off
gpio_set_level(GPIO_ASIC_ENABLE, 1);
}
}
// if (power_management->HAS_PLUG_SENSE) {
// int gpio_plug_sense_state = gpio_get_level(GPIO_PLUG_SENSE);
// if (gpio_plug_sense_state == 0) {
// // turn ASIC off
// gpio_set_level(GPIO_ASIC_ENABLE, 1);
// }
// }
// New voltage and frequency adjustment code
uint16_t core_voltage = nvs_config_get_u16(NVS_CONFIG_ASIC_VOLTAGE, CONFIG_ASIC_VOLTAGE);
@ -288,12 +143,13 @@ void POWER_MANAGEMENT_task(void * pvParameters)
if (asic_frequency != last_asic_frequency) {
ESP_LOGI(TAG, "New ASIC frequency requested: %uMHz (current: %uMHz)", asic_frequency, last_asic_frequency);
if (do_frequency_transition((float)asic_frequency)) {
bool success = ASIC_set_frequency(GLOBAL_STATE, (float)asic_frequency);
if (success) {
power_management->frequency_value = (float)asic_frequency;
ESP_LOGI(TAG, "Successfully transitioned to new ASIC frequency: %uMHz", asic_frequency);
} else {
ESP_LOGE(TAG, "Failed to transition to new ASIC frequency: %uMHz", asic_frequency);
}
last_asic_frequency = asic_frequency;
}
@ -306,6 +162,7 @@ void POWER_MANAGEMENT_task(void * pvParameters)
ESP_LOGI(TAG, "Overheat mode updated to: %d", module->overheat_mode);
}
// looper:
vTaskDelay(POLL_RATE / portTICK_PERIOD_MS);
}
}

Some files were not shown because too many files have changed in this diff Show More