Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion main/global_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ typedef struct
float hashrate_10m;
float hashrate_1h;
float error_percentage;
int64_t start_time;
int64_t start_time_us;
uint64_t shares_accepted;
uint64_t shares_rejected;
uint64_t work_received;
Expand Down Expand Up @@ -89,6 +89,7 @@ typedef struct
char * asic_status;
char * version;
char * axeOSVersion;
uint64_t uptime_seconds;
} SystemModule;

typedef struct
Expand Down
66 changes: 35 additions & 31 deletions main/http_server/axe-os/src/app/components/home/home.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<div class="col-12 md:col-6 xl:col-3">
<div class="card mb-0">
<div class="flex flex-column justify-content-between">
<span class="block text-lg font-medium mb-3">Hashrate</span>
<span class="block text-lg font-medium mb-2">Hashrate</span>

<ng-container *ngIf="!info.power_fault; else powerFault">
<div class="flex align-items-center justify-content-between gap-2 mb-3">
Expand Down Expand Up @@ -85,10 +85,10 @@
<div class="col-12 md:col-6 xl:col-3">
<div class="card mb-0">
<div class="flex flex-column justify-content-between">
<span class="block text-lg font-medium mb-3">Efficiency</span>
<span class="block text-lg font-medium mb-2">Efficiency</span>

<ng-container *ngIf="!info.power_fault; else powerFault">
<div class="flex align-items-center justify-content-between gap-2 mb-3">
<div class="flex align-items-center justify-content-between gap-2 mb-2">
<span class="text-900 font-medium text-2xl white-space-nowrap">
{{getEfficiency(info) | number: '1.2-2'}} J/Th
</span>
Expand Down Expand Up @@ -124,13 +124,9 @@
</div>
<div class="col-12 md:col-6 xl:col-3">
<div class="card mb-0">
<div class="flex justify-content-between mb-3">
<div>
<span class="block text-lg font-medium mb-3">Shares</span>
<div class="text-900 font-medium text-2xl">
{{info.sharesAccepted | number: '1.0-0'}}
</div>
</div>
<div class="block text-lg font-medium mb-2">Shares</div>
<div class="text-900 font-medium text-2xl mb-2">
{{info.sharesAccepted | number: '1.0-0'}}
</div>
<div *ngIf="info.sharesRejected === 0">
<span class="text-red-500 font-medium">0 </span>
Expand All @@ -155,30 +151,38 @@

<div class="col-12 md:col-6 xl:col-3">
<div class="card mb-0">
<div class="flex justify-content-between mb-3">
<div>
<span class="block text-lg font-medium mb-3">Best Difficulty</span>
<div class="text-900 font-medium text-2xl">
<span class="cursor-pointer" pTooltip="{{info.bestDiff | number:'1.0-0'}}" tooltipPosition="bottom">
{{info.bestDiff | diffSuffix}}
</span>
<span class="text-500 text-lg">all-time best</span>
<span class="text-sm font-medium mb-3" *ngIf="info.networkDifficulty">
<tooltip-text-icon
[text]="'(' + getNetworkDifficultyPercentage(info) + '%)'"
tooltip="Chance to find a Block"
[split]="false"
/>
</span>
</div>
</div>
<div class="block text-lg font-medium mb-2">Best Difficulty</div>
<div class="text-900 font-medium text-2xl mb-2">
<span class="cursor-pointer" pTooltip="{{info.bestDiff | number:'1.0-0'}}" tooltipPosition="left">
{{info.bestDiff | diffSuffix}}
</span>
<span class="text-500 text-lg mr-1">all-time best</span>
<span class="text-sm font-medium mr-1" *ngIf="info.networkDifficulty">
<tooltip-text-icon
[text]="'(' + getNetworkDifficultyPercentage(info) + '%)'"
tooltip="Chance to find a Block"
[split]="false"
/>
</span>
</div>
<div>
<span class="text-900 font-medium cursor-pointer" pTooltip="{{info.bestSessionDiff | number:'1.0-0'}}" tooltipPosition="bottom">
<div class="mb-2">
<span class="text-900 font-medium cursor-pointer mr-1" pTooltip="{{info.bestSessionDiff | number:'1.0-0'}}" tooltipPosition="left">
{{info.bestSessionDiff | diffSuffix}}
</span>
<span class="text-500 text-lg">session best</span>
<span class="text-sm font-medium mb-3"> ({{ info.uptimeSeconds | dateAgo: { intervals: 2, strict:true, short:true } }})</span>
<span class="text-500 text-lg mr-1">session best</span>
<span class="text-sm font-medium"> ({{ info.uptimeSeconds | dateAgo: { intervals: 2, strict:true, short:true } }})</span>
</div>
<div *ngIf="info.totalLog2Work">
<span class="text-900 font-medium cursor-pointer mr-1" pTooltip="{{info.totalHashes | number}} total hashes" tooltipPosition="left">
{{info.totalLog2Work | number:'1.6-6'}}
</span>
<span class="text-500 text-lg">
<tooltip-text-icon
text="total work (log 2)"
tooltip="Approximate base-2 logarithm of your total accumulated hashes (personal mining effort). Example: log2_work = 50 means roughly 2^50 ≈ 1 quadrillion hashes attempted."
tooltipPosition="left"
/>
</span>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { LoadingService } from 'src/app/services/loading.service';
import { DateAgoPipe } from 'src/app/pipes/date-ago.pipe';
import { ByteSuffixPipe } from 'src/app/pipes/byte-suffix.pipe';
import { SystemInfo as ISystemInfo, SystemASIC as ISystemASIC, GenericResponse, } from 'src/app/generated';
import { formatNumber } from '@angular/common';

type TableRow = {
label: string;
Expand Down Expand Up @@ -89,6 +90,9 @@ export class SystemComponent implements OnInit, OnDestroy {
{ label: 'Board Version', value: data.info.boardVersion },
{ label: 'ASIC Type', value: (data.asic.asicCount > 1 ? data.asic.asicCount + 'x ' : ' ') + data.asic.ASICModel, class: 'pb-3' },
{ label: 'Uptime', value: DateAgoPipe.transform(data.info.uptimeSeconds) },
{ label: 'Total Uptime', value: DateAgoPipe.transform(data.info.totalUptimeSeconds || 0) },
{ label: 'Total Work (log2)', value: (data.info.totalLog2Work || 0).toFixed(6) },
{ label: 'Total Hashes', value: formatNumber(data.info.totalHashes || 0, 'en-us')},
{ label: 'Reset Reason', value: data.info.resetReason, class: 'pb-3' },
{ label: 'Wi-Fi SSID', value: data.info.ssid, isSensitiveData: true },
{ label: 'Wi-Fi Status', value: data.info.wifiStatus },
Expand Down
5 changes: 4 additions & 1 deletion main/http_server/http_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,10 @@ static esp_err_t GET_system_info(httpd_req_t * req)
cJSON_AddItemToArray(error_array, error_obj);
}

cJSON_AddNumberToObject(root, "uptimeSeconds", (esp_timer_get_time() - GLOBAL_STATE->SYSTEM_MODULE.start_time) / 1000000);
cJSON_AddNumberToObject(root, "uptimeSeconds", GLOBAL_STATE->SYSTEM_MODULE.uptime_seconds);
cJSON_AddNumberToObject(root, "totalUptimeSeconds", SYSTEM_noinit_get_total_uptime_seconds());
cJSON_AddNumberToObject(root, "totalHashes", SYSTEM_noinit_get_total_hashes());
cJSON_AddNumberToObject(root, "totalLog2Work", SYSTEM_noinit_get_total_log2_work());
cJSON_AddNumberToObject(root, "smallCoreCount", GLOBAL_STATE->DEVICE_CONFIG.family.asic.small_core_count);
cJSON_AddStringToObject(root, "ASICModel", GLOBAL_STATE->DEVICE_CONFIG.family.asic.name);
cJSON_AddStringToObject(root, "stratumURL", stratumURL);
Expand Down
9 changes: 9 additions & 0 deletions main/http_server/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,15 @@ components:
sharesRejected:
type: number
description: Number of rejected shares
totalUptimeSeconds:
type: number
description: Total uptime in seconds
totalHashes:
type: number
description: Total hashes done by the device
totalLog2Work:
type: number
description: Log2 of total hashes
sharesRejectedReasons:
type: array
description: Reason(s) shares were rejected
Expand Down
3 changes: 3 additions & 0 deletions main/nvs_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ static Settings settings[NVS_CONFIG_COUNT] = {
[NVS_CONFIG_TPS546] = {.nvs_key_name = "TPS546", .type = TYPE_BOOL},
[NVS_CONFIG_TMP1075] = {.nvs_key_name = "TMP1075", .type = TYPE_BOOL},
[NVS_CONFIG_POWER_CONSUMPTION_TARGET] = {.nvs_key_name = "power_cons_tgt", .type = TYPE_U16},
[NVS_CONFIG_TOTAL_UPTIME] = {.nvs_key_name = "total_uptime", .type = TYPE_U64},
[NVS_CONFIG_CUMULATIVE_HASHES_HIGH] = {.nvs_key_name = "cum_hashes_hi", .type = TYPE_U64},
[NVS_CONFIG_CUMULATIVE_HASHES_LOW] = {.nvs_key_name = "cum_hashes_lo", .type = TYPE_U64},
};

Settings *nvs_config_get_settings(NvsConfigKey key)
Expand Down
5 changes: 5 additions & 0 deletions main/nvs_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ typedef enum {
NVS_CONFIG_TPS546,
NVS_CONFIG_TMP1075,
NVS_CONFIG_POWER_CONSUMPTION_TARGET,

NVS_CONFIG_TOTAL_UPTIME,
NVS_CONFIG_CUMULATIVE_HASHES_HIGH,
NVS_CONFIG_CUMULATIVE_HASHES_LOW,

NVS_CONFIG_COUNT
} NvsConfigKey;

Expand Down
41 changes: 21 additions & 20 deletions main/screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ static float current_hashrate;
static float current_power;
static uint64_t current_difficulty;
static float current_chip_temp;
static uint32_t current_uptime_seconds;

#define NOTIFICATION_SHARE_ACCEPTED (1 << 0)
#define NOTIFICATION_SHARE_REJECTED (1 << 1)
Expand Down Expand Up @@ -647,26 +648,26 @@ static void uptime_update_cb(lv_timer_t * timer)
{
if (wifi_uptime_label) {
char uptime[50];
uint32_t uptime_seconds = (esp_timer_get_time() - GLOBAL_STATE->SYSTEM_MODULE.start_time) / 1000000;

uint32_t days = uptime_seconds / (24 * 3600);
uptime_seconds %= (24 * 3600);
uint32_t hours = uptime_seconds / 3600;
uptime_seconds %= 3600;
uint32_t minutes = uptime_seconds / 60;
uptime_seconds %= 60;

if (days > 0) {
snprintf(uptime, sizeof(uptime), "Uptime: %ldd %ldh %ldm %lds", days, hours, minutes, uptime_seconds);
} else if (hours > 0) {
snprintf(uptime, sizeof(uptime), "Uptime: %ldh %ldm %lds", hours, minutes, uptime_seconds);
} else if (minutes > 0) {
snprintf(uptime, sizeof(uptime), "Uptime: %ldm %lds", minutes, uptime_seconds);
} else {
snprintf(uptime, sizeof(uptime), "Uptime: %lds", uptime_seconds);
}

if (strcmp(lv_label_get_text(wifi_uptime_label), uptime) != 0) {
uint32_t uptime_seconds = (esp_timer_get_time() - GLOBAL_STATE->SYSTEM_MODULE.start_time_us) / 1000000;
if (current_uptime_seconds != uptime_seconds) {
current_uptime_seconds = uptime_seconds;
uint32_t days = uptime_seconds / (24 * 3600);
uptime_seconds %= (24 * 3600);
uint32_t hours = uptime_seconds / 3600;
uptime_seconds %= 3600;
uint32_t minutes = uptime_seconds / 60;
uptime_seconds %= 60;

if (days > 0) {
snprintf(uptime, sizeof(uptime), "Uptime: %ldd %ldh %ldm %lds", days, hours, minutes, uptime_seconds);
} else if (hours > 0) {
snprintf(uptime, sizeof(uptime), "Uptime: %ldh %ldm %lds", hours, minutes, uptime_seconds);
} else if (minutes > 0) {
snprintf(uptime, sizeof(uptime), "Uptime: %ldm %lds", minutes, uptime_seconds);
} else {
snprintf(uptime, sizeof(uptime), "Uptime: %lds", uptime_seconds);
}

lv_label_set_text(wifi_uptime_label, uptime);
}
}
Expand Down
117 changes: 114 additions & 3 deletions main/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_attr.h"

#include "driver/gpio.h"
#include "esp_app_desc.h"
Expand All @@ -19,7 +20,7 @@
#include "lwip/inet.h"

#include "system.h"
#include "i2c_bitaxe.h"
#include "global_state.h"
#include "INA260.h"
#include "adc.h"
#include "connect.h"
Expand All @@ -31,6 +32,22 @@
#include "thermal.h"
#include "utils.h"

#define NVS_COUNTER_UPDATE_INTERVAL_MS 60 * 60 * 1000 // Update NVS once per hour
#define NOINIT_SENTINEL_VALUE 0x4C4F4732 // "LOG2" in hex

typedef struct
{
uint64_t total_uptime; // Total uptime in seconds
uint64_t cumulative_hashes_high; // High 64 bits of 128-bit cumulative hash count
uint64_t cumulative_hashes_low; // Low 64 bits of 128-bit cumulative hash count
uint32_t sentinel; // Magic value to detect valid noinit data
} NoinitState;

__NOINIT_ATTR static NoinitState noinit_state; // Noinit state survives soft reboots but is lost on power cycle
static uint64_t last_update_time_ms;
static uint64_t last_nvs_write_time_ms;
static uint64_t total_uptime_at_system_start;

static const char * TAG = "system";

//local function prototypes
Expand All @@ -45,11 +62,35 @@ void SYSTEM_init_system(GlobalState * GLOBAL_STATE)
module->shares_rejected = 0;
module->best_nonce_diff = nvs_config_get_u64(NVS_CONFIG_BEST_DIFF);
module->best_session_nonce_diff = 0;
module->start_time = esp_timer_get_time();
module->start_time_us = esp_timer_get_time();
module->lastClockSync = 0;
module->block_found = 0;
module->show_new_block = false;

if (noinit_state.sentinel != NOINIT_SENTINEL_VALUE) {
noinit_state.sentinel = NOINIT_SENTINEL_VALUE;
noinit_state.total_uptime = 0;
noinit_state.cumulative_hashes_high = 0;
noinit_state.cumulative_hashes_low = 0;
}

// Load values from NVS (persist across power cycle)
uint64_t nvs_total_uptime = nvs_config_get_u64(NVS_CONFIG_TOTAL_UPTIME);
if (nvs_total_uptime > noinit_state.total_uptime) {
noinit_state.total_uptime = nvs_total_uptime;
}
total_uptime_at_system_start = noinit_state.total_uptime;

uint64_t nvs_hashes_high = nvs_config_get_u64(NVS_CONFIG_CUMULATIVE_HASHES_HIGH);
uint64_t nvs_hashes_low = nvs_config_get_u64(NVS_CONFIG_CUMULATIVE_HASHES_LOW);
if (nvs_hashes_high > noinit_state.cumulative_hashes_high) {
noinit_state.cumulative_hashes_high = nvs_hashes_high;
noinit_state.cumulative_hashes_low = nvs_hashes_low;
} else if (nvs_hashes_high == noinit_state.cumulative_hashes_high &&
nvs_hashes_low > noinit_state.cumulative_hashes_low) {
noinit_state.cumulative_hashes_low = nvs_hashes_low;
}

// Initialize network address strings
strcpy(module->ip_addr_str, "");
strcpy(module->ipv6_addr_str, "");
Expand Down Expand Up @@ -115,7 +156,8 @@ void SYSTEM_init_system(GlobalState * GLOBAL_STATE)
pthread_mutex_init(&GLOBAL_STATE->valid_jobs_lock, NULL);
}

void SYSTEM_init_versions(GlobalState * GLOBAL_STATE) {
void SYSTEM_init_versions(GlobalState * GLOBAL_STATE)
{
const esp_app_desc_t *app_desc = esp_app_get_description();

// Store the firmware version
Expand Down Expand Up @@ -276,3 +318,72 @@ static esp_err_t ensure_overheat_mode_config() {

return ESP_OK;
}

void SYSTEM_noinit_update(SystemModule * SYSTEM_MODULE)
{
uint64_t current_time_ms = esp_timer_get_time() / 1000;

// Initialize last_update_time on first call
if (last_update_time_ms == 0) {
last_update_time_ms = current_time_ms;
last_nvs_write_time_ms = current_time_ms;
return;
}

uint64_t elapsed_ms = current_time_ms - last_update_time_ms;
last_update_time_ms = current_time_ms;

// Only update if at least 1 second has passed
if (elapsed_ms < 1000) {
return;
}

SYSTEM_MODULE->uptime_seconds = (esp_timer_get_time() - SYSTEM_MODULE->start_time_us) / 1000000;
noinit_state.total_uptime = total_uptime_at_system_start + SYSTEM_MODULE->uptime_seconds;

// Update cumulative hashes: hashrate (GH/s) × milliseconds × 1e6 = raw hashes
uint64_t hashes_done = elapsed_ms * 1e6 * SYSTEM_MODULE->current_hashrate;
uint64_t new_low = noinit_state.cumulative_hashes_low + hashes_done;
if (new_low < noinit_state.cumulative_hashes_low) {
noinit_state.cumulative_hashes_high++;
}
noinit_state.cumulative_hashes_low = new_low;

// Persist to NVS once per hour to reduce wear
if (current_time_ms - last_nvs_write_time_ms >= NVS_COUNTER_UPDATE_INTERVAL_MS) {
nvs_config_set_u64(NVS_CONFIG_TOTAL_UPTIME, noinit_state.total_uptime);
nvs_config_set_u64(NVS_CONFIG_CUMULATIVE_HASHES_HIGH, noinit_state.cumulative_hashes_high);
nvs_config_set_u64(NVS_CONFIG_CUMULATIVE_HASHES_LOW, noinit_state.cumulative_hashes_low);
last_nvs_write_time_ms = current_time_ms;
}
}

uint64_t SYSTEM_noinit_get_total_uptime_seconds()
{
return noinit_state.total_uptime;
}

// Convert 128-bit to double: high * 2^64 + low. Loses precision for very large values, but sufficient for display
double SYSTEM_noinit_get_total_hashes()
{
return (double)noinit_state.cumulative_hashes_high * 18446744073709551616.0 + (double)noinit_state.cumulative_hashes_low;
}

double SYSTEM_noinit_get_total_log2_work()
{
// If high part is 0, just compute log2 of low part
if (noinit_state.cumulative_hashes_high == 0) {
if (noinit_state.cumulative_hashes_low == 0) {
return 0.0;
}
return log2((double)noinit_state.cumulative_hashes_low);
}

// For 128-bit value: log2(high * 2^64 + low) = 64 + log2(high + low/2^64)
// Since low/2^64 is very small compared to high, we approximate:
// log2(high * 2^64 + low) ≈ 64 + log2(high) for large values
// More precise: 64 + log2(high + low/2^64)
double high_plus_fraction = (double)noinit_state.cumulative_hashes_high +
(double)noinit_state.cumulative_hashes_low / 18446744073709551616.0;
return 64.0 + log2(high_plus_fraction);
}
Loading
Loading