Skip to content
Draft
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
9 changes: 6 additions & 3 deletions main/fan_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ void FanController::loadSettings()

void FanController::update(float chipTempMax, float vrTemp)
{
// Temperature input per channel: ch0=chip, ch1=VR
// Overheat thresholds use original per-channel temps (ch0=chip, ch1=VR)
float overheatInput[MAX_FANS] = { chipTempMax, vrTemp };

// PID temperature input per channel: ch0=chip, ch1=VR
float tempInput[MAX_FANS] = { chipTempMax, vrTemp };

// only 2nd channel can be linked
Expand All @@ -102,8 +105,8 @@ void FanController::update(float chipTempMax, float vrTemp)
m_pid[ch]->Compute();
}

// Overheat: drive fan to 100% and flag it (checked even in LINKED mode for shutdown purposes)
if (m_config[ch].overheatTemp && tempInput[ch] > m_config[ch].overheatTemp) {
// Overheat: use original temps, not PID-mixed temps
if (m_config[ch].overheatTemp && overheatInput[ch] > m_config[ch].overheatTemp) {
m_overheated[ch] = true;
m_fanPerc[ch] = 100;
m_board->setFanSpeedCh(ch, 1.0f);
Expand Down
9 changes: 7 additions & 2 deletions main/http_server/axe-os/src/app/pages/edit/edit.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,9 +398,14 @@ export class EditComponent implements OnInit {
const currentValue = this.normalizeValue(current[key]);
const originalValue = this.normalizeValue(this.originalSettings[key]);

// Special case: masked password fields
// Masked password fields: unchanged if still '*****', changed otherwise
if (typeof currentValue === 'string' && currentValue === '*****') {
continue; // User hasn't changed this field
continue;
}
// Fields not present in original settings (e.g. wifiPass):
// if we got past the '*****' check, the user has typed something new
if (originalValue === undefined || originalValue === null) {
return true;
}

if (currentValue !== originalValue) {
Expand Down
30 changes: 11 additions & 19 deletions main/http_server/axe-os/src/app/pages/home/home.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ <h4>{{ 'COMMON.SHUTDOWN' | translate }}</h4>

<button
nbButton ghost size="tiny" type="button"
style="position: absolute; top: 4px; right: 4px; z-index: 1; opacity: 0.5;"
class="pool-reset-btn"
[attr.aria-label]="'HOME.RESET_STATS' | translate"
[nbTooltip]="'HOME.RESET_STATS' | translate"
(click)="openResetStatsDialog(resetStatsDialog)"
Expand Down Expand Up @@ -466,7 +466,7 @@ <h4>{{ 'COMMON.SHUTDOWN' | translate }}</h4>

<!-- Input voltage bar -->
<div class="power-bar" role="img"
[class.power-bar--warn]="isInputVoltageWarn(info.voltage)"
[class.power-bar--warn]="isInputVoltageWarn(info.voltage, info.minVoltage, info.maxVoltage)"
[class.power-bar--crit]="false"
[class.power-bar--max]="isBarMax(info.voltage, info.maxVoltage)"
[attr.aria-label]="('PERFORMANCE.INPUT_VOLTAGE' | translate) + ': ' + (info.voltage | number: '1.1-1') + ' V'">
Expand Down Expand Up @@ -554,15 +554,7 @@ <h4>{{ 'COMMON.SHUTDOWN' | translate }}</h4>
</div>

<div class="heat-bars">
@let fanRpm1 = (info.fanrpm ?? 0);
@let fanRpm2 = (info.fanrpm2 ?? 0);
@let fanC1HasRpm = fanRpm1 > 0;
@let fanC2HasRpm = fanRpm2 > 0;
@let singleFanUsesC2 = !fanC1HasRpm && fanC2HasRpm;
@let primaryFanPercent = singleFanUsesC2 ? (info.fanspeed2 ?? 0) : (info.fanspeed ?? 0);
@let primaryFanRpm = singleFanUsesC2 ? (info.fanrpm2 ?? 0) : (info.fanrpm ?? 0);
@let showFanC1 = (primaryFanPercent > 0) || (primaryFanRpm > 0) || !fanC2HasRpm;
@let showFanC2 = fanC1HasRpm && fanC2HasRpm;
@let showFanC2 = (info.fanCount ?? 1) > 1;

<!-- VR temp bar -->
<div class="power-bar power-bar--interactive" *ngIf="info.vrTemp > 0" role="img" data-bar="vr-temp"
Expand Down Expand Up @@ -605,15 +597,15 @@ <h4>{{ 'COMMON.SHUTDOWN' | translate }}</h4>
</div>

<!-- Fan bar (metric = fan speed %, shows RPM as secondary label) -->
@let fanC1LowRpm = shouldShowLowRpmHint(primaryFanPercent, primaryFanRpm);
<div class="power-bar" *ngIf="showFanC1" role="img"
@let fanC1LowRpm = shouldShowLowRpmHint(info.fanspeed ?? 0, info.fanrpm ?? 0);
<div class="power-bar" role="img"
[class.power-bar--interactive]="fanC1LowRpm"
[class.power-bar--max]="isBarMax(primaryFanPercent, 100)"
[class.power-bar--max]="isBarMax(info.fanspeed ?? 0, 100)"
(mouseenter)="showConditionalHoverTooltip('fan-c1', fanC1LowRpm, $event)"
(mousemove)="moveConditionalHoverTooltip(fanC1LowRpm, $event)"
(mouseleave)="hideHoverTooltip('fan-c1')"
[attr.aria-label]="getFanAriaLabel(showFanC2 ? 1 : null, primaryFanPercent, primaryFanRpm)">
<div class="power-bar__fill" [style.width.%]="toPct(primaryFanPercent, 0, 100)"></div>
[attr.aria-label]="getFanAriaLabel(showFanC2 ? 1 : null, info.fanspeed ?? 0, info.fanrpm ?? 0)">
<div class="power-bar__fill" [style.width.%]="toPct(info.fanspeed ?? 0, 0, 100)"></div>
<div class="power-bar__label">{{ 'HOME.FAN_ASICS_LABEL' | translate }}</div>
<span class="power-bar-tooltip"
*ngIf="fanC1LowRpm"
Expand All @@ -625,11 +617,11 @@ <h4>{{ 'COMMON.SHUTDOWN' | translate }}</h4>
</span>
<div class="power-bar__value power-bar__value--inline">
<span class="fan-inline">
<ng-container *ngIf="shouldShowFanRpm(primaryFanPercent, primaryFanRpm)">
<span class="power-bar__subvalue">{{ primaryFanRpm | number: '1.0-0' }}<span class="unit">&nbsp;RPM</span></span>
<ng-container *ngIf="shouldShowFanRpm(info.fanspeed ?? 0, info.fanrpm ?? 0)">
<span class="power-bar__subvalue">{{ (info.fanrpm ?? 0) | number: '1.0-0' }}<span class="unit">&nbsp;RPM</span></span>
<span class="power-bar__sep">/</span>
</ng-container>
<span class="power-bar__mainvalue">{{ primaryFanPercent | number: '1.0-0' }}<span class="unit">&nbsp;%</span></span>
<span class="power-bar__mainvalue">{{ (info.fanspeed ?? 0) | number: '1.0-0' }}<span class="unit">&nbsp;%</span></span>
</span>
</div>
</div>
Expand Down
24 changes: 24 additions & 0 deletions main/http_server/axe-os/src/app/pages/home/home.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,30 @@ nb-card-header{
line-height: 1;
}

/* Reset-session-stats button: pinned into the tile's top-right corner.
Strip the nbButton padding so the icon sits right in the corner and
clears the dual-pool allocation % that is rendered on the same row. */
.pool-reset-btn.pool-reset-btn{
position: absolute;
top: 1px;
right: 1px;
z-index: 2;
opacity: 0.5;
padding: 0 !important;
min-width: 0 !important;
width: 16px;
height: 16px;
line-height: 1;

nb-icon{
font-size: 14px;
}

&:hover{
opacity: 0.9;
}
}

/* Host/Port/Ping/Loss block should be visually smaller (same size as labels) */
.pool-tile-info__bottom{
/* Keep Host/Port/Ping/Loss within the same vertical band as the grey box */
Expand Down
7 changes: 4 additions & 3 deletions main/http_server/axe-os/src/app/pages/home/home.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,10 @@ export class HomeComponent implements AfterViewChecked, OnInit, OnDestroy {
* Input Voltage warn-band (yellow) should be data-driven (HOME_CFG) and centralized.
* We keep the template free of thresholds by routing through this method.
*/
public isInputVoltageWarn(voltage: any): boolean {
const band = HOME_CFG.tiles.inputVoltageBand;
return isOutsideBand(voltage, band.low, band.high);
public isInputVoltageWarn(voltage: any, voltageMin?: number, voltageMax?: number): boolean {
const low = voltageMin ?? HOME_CFG.tiles.inputVoltageBand.low;
const high = voltageMax ?? HOME_CFG.tiles.inputVoltageBand.high;
return isOutsideBand(voltage, low, high);
}

/**
Expand Down
29 changes: 23 additions & 6 deletions main/http_server/axe-os/src/app/pages/home/home.quicklinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,29 @@ const POOLS: PoolMeta[] = [
match: (h) => h.includes('powermining.io'),
quickLink: (a) => `https://pool.powermining.io/#/app/${a}`,
},
{
id: 'blitzpool',
name: 'blitzpool.yourdevice.ch',
match: (h) => h.includes('blitzpool.yourdevice.ch'),
quickLink: (a) => `https://blitzpool.yourdevice.ch/#/app/${a}`,
},
{
id: 'blitzpool',
name: 'blitzpool.yourdevice.ch',
match: (h) => h.includes('blitzpool.yourdevice.ch'),
quickLink: (a) => `https://blitzpool.yourdevice.ch/#/app/${a}`,
},
{
id: 'braiins-solo',
name: 'Braiins Solo',
match: (h) => h.includes('solo.stratum.braiins.com'),
quickLink: (a) => `https://solo.braiins.com/stats/${a}`,
faviconHost: 'solo.braiins.com',
faviconPath: '/icon.png'
},
{
id: 'mining-dutch',
name: 'mining-dutch.nl',
// stratum host is a regional subdomain (e.g. europe.mining-dutch.nl);
// account-based pool, so link to the main site instead of the wallet
match: (h) => h.includes('mining-dutch.nl'),
quickLink: () => `https://www.mining-dutch.nl`,
faviconHost: 'www.mining-dutch.nl',
}
];

/* ------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion main/http_server/axe-os/src/app/services/system.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ export class SystemService {
}

public sendAlertTest(uri: string = '', totp?: string): Observable<any> {
const headers = totp ? new HttpHeaders({ 'X-OTP-Code': totp }) : undefined;
const headers = totp ? new HttpHeaders({ 'X-TOTP': totp }) : undefined;
return this.httpClient.post(`${uri}/api/alert/test`, {}, {
responseType: 'text',
headers,
Expand Down
17 changes: 9 additions & 8 deletions main/http_server/handler_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ esp_err_t GET_system_info(httpd_req_t *req)
char *fallbackStratumURL = Config::getStratumFallbackURL();
char *fallbackStratumUser= Config::getStratumFallbackUser();

char *sv2_auth = Config::getSV2AuthorityPubkey();
char *fb_sv2_auth = Config::getFallbackSV2AuthorityPubkey();


// static
doc["asicCount"] = board->getAsicCount();
doc["smallCoreCount"] = (board->getAsics()) ? board->getAsics()->getSmallCoreCount() : 0;
Expand Down Expand Up @@ -210,14 +214,8 @@ esp_err_t GET_system_info(httpd_req_t *req)
doc["fallbackStratumTLS"] = Config::isStratumFallbackTLS();
doc["stratumProtocol"] = Config::getStratumProtocol();
doc["fallbackStratumProtocol"] = Config::getFallbackStratumProtocol();
{
char *sv2_auth = Config::getSV2AuthorityPubkey();
doc["sv2AuthorityPubkey"] = sv2_auth ? sv2_auth : "";
safe_free(sv2_auth);
char *fb_sv2_auth = Config::getFallbackSV2AuthorityPubkey();
doc["fallbackSv2AuthorityPubkey"] = fb_sv2_auth ? fb_sv2_auth : "";
safe_free(fb_sv2_auth);
}
doc["sv2AuthorityPubkey"] = sv2_auth;
doc["fallbackSv2AuthorityPubkey"] = fb_sv2_auth;
doc["sv2ChannelType"] = Config::getSV2ChannelType();
doc["fallbackSv2ChannelType"] = Config::getFallbackSV2ChannelType();
doc["voltage"] = POWER_MANAGEMENT_MODULE.getVoltage();
Expand Down Expand Up @@ -264,6 +262,9 @@ esp_err_t GET_system_info(httpd_req_t *req)
free(fallbackStratumURL);
free(fallbackStratumUser);

free(sv2_auth);
free(fb_sv2_auth);

return ret;
}

Expand Down
3 changes: 2 additions & 1 deletion main/http_server/http_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ esp_err_t getPostData(httpd_req_t *req)
}

while (cur_len < total_len) {
received = httpd_req_recv(req, buf + cur_len, total_len);
int remaining = total_len - cur_len;
received = httpd_req_recv(req, buf + cur_len, remaining);
if (received <= 0) {
/* Respond with 500 Internal Server Error */
ESP_LOGE(TAG, "error receiving data");
Expand Down
2 changes: 2 additions & 0 deletions main/macros.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <pthread.h> // PThreadGuard below uses pthread_mutex_*


static inline void* _malloc_psram(size_t sz) {
if (!sz) return NULL;
Expand Down
3 changes: 3 additions & 0 deletions main/stratum/stratum_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ void StratumManager::loadSettings(bool reconnect)
m_stratumTasks[i]->triggerReconnect();
}

// reset session stats for this pool
resetPoolSessionStats(i);

// reset ping stats
if (m_pingTasks[i]) {
m_pingTasks[i]->reset();
Expand Down
4 changes: 4 additions & 0 deletions main/stratum/stratum_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ class StratumManager {

virtual int getPoolMode() = 0;

// reset stats for a single pool (called from loadSettings with mutex held)
virtual void resetPoolSessionStats(int pool) {
}

public:
virtual void resetSessionStats() {
PThreadGuard lock(m_mutex);
Expand Down
16 changes: 10 additions & 6 deletions main/stratum/stratum_manager_dual_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,19 @@ class StratumManagerDualPool : public StratumManager {
return (m_balance >= 50) ? m_networkDifficulty[0] : m_networkDifficulty[1];
}

virtual void resetPoolSessionStats(int pool) override {
StratumManager::resetPoolSessionStats(pool);
m_accepted[pool] = 0;
m_rejected[pool] = 0;
m_bestSessionDiff[pool] = 0;
suffixString(std::max(m_bestSessionDiff[0], m_bestSessionDiff[1]), m_bestSessionDiffString, DIFF_STRING_SIZE, 0);
if (m_stratumTasks[pool]) m_stratumTasks[pool]->m_poolErrors = 0;
}

virtual void resetSessionStats() override {
PThreadGuard lock(m_mutex);
m_foundBlocks = 0;
for (int i = 0; i < 2; i++) {
m_accepted[i] = 0;
m_rejected[i] = 0;
m_bestSessionDiff[i] = 0;
suffixString(0, m_bestSessionDiffString, DIFF_STRING_SIZE, 0);
if (m_stratumTasks[i]) m_stratumTasks[i]->m_poolErrors = 0;
resetPoolSessionStats(i);
}
}

Expand Down
13 changes: 9 additions & 4 deletions main/stratum/stratum_manager_fallback.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,20 @@ class StratumManagerFallback : public StratumManager {
return m_networkDifficulty;
}

virtual void resetSessionStats() override {
PThreadGuard lock(m_mutex);
m_foundBlocks = 0;
virtual void resetPoolSessionStats(int pool) override {
StratumManager::resetPoolSessionStats(pool);
// fallback mode shares a single counter for both pools
m_accepted = 0;
m_rejected = 0;
m_bestSessionDiff = 0;
suffixString(0, m_bestSessionDiffString, DIFF_STRING_SIZE, 0);
if (m_stratumTasks[pool]) m_stratumTasks[pool]->m_poolErrors = 0;
}

virtual void resetSessionStats() override {
PThreadGuard lock(m_mutex);
for (int i = 0; i < 2; i++) {
if (m_stratumTasks[i]) m_stratumTasks[i]->m_poolErrors = 0;
resetPoolSessionStats(i);
}
}

Expand Down
5 changes: 4 additions & 1 deletion main/stratum/stratum_task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,12 +308,15 @@ void StratumTaskBase::task()
m_poolErrors++;
}

// gate new submits before tearing the transport down; the
// transport's internal lock covers a submit already inside send()
m_isConnected = false;

// shutdown and reconnect
ESP_LOGIE(m_reconnect, m_tag, "Shutdown socket ...");
m_transport->close();

disconnectedCallback();
m_isConnected = false;

// skip reconnect delay
if (m_reconnect) {
Expand Down
9 changes: 4 additions & 5 deletions main/stratum/stratum_task_v2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -589,10 +589,9 @@ void StratumTaskV2::submitShare(const char *jobid, const char *extranonce_2,
const uint32_t ntime, const uint32_t nonce,
const uint32_t version_rolled, const uint32_t version_base)
{
sv2_noise_ctx_t *noise = m_noiseTransport.getNoiseCtx();
esp_transport_handle_t transport = m_noiseTransport.getTransportHandle();

if (!noise || !transport) {
// this runs on the ASIC result task; go through m_noiseTransport.send()
// so its lock protects the noise ctx against a concurrent close()
if (!m_noiseTransport.getNoiseCtx()) {
ESP_LOGE(m_tag, "Cannot submit share: no connection");
return;
}
Expand Down Expand Up @@ -636,7 +635,7 @@ void StratumTaskV2::submitShare(const char *jobid, const char *extranonce_2,

m_lastSubmitTimeUs = esp_timer_get_time();

if (sv2_noise_send(noise, transport, buf, frame_len) != 0) {
if (m_noiseTransport.send(buf, frame_len) != frame_len) {
ESP_LOGE(m_tag, "Failed to send share");
}
}
Expand Down
Loading