mirror of
https://github.com/skot/ESP-Miner.git
synced 2025-06-13 06:30:52 +02:00
Http-server (#17)
* rename miner to main * serving out of storage * axe os * http server work * basic stats showing * update sdkconfig * SDKCONFIG * sdk config * edit page init * edit pool config * pool config edit working * OTA Success * remove compiled output * toggle AP mode with boot button * favicon * ota website update * add sdkconfig.ci back * update readme * change website build to warning * Update github workflow to build web dist * Allow AP mode before STA connection complete * spacing for johnny :) * formatting * Improve connecting to wifi with AP mode * added working indicator for UI * formatting * formatting * remove redundant sdkconfig in CMakeLists * vs code format on save workspace settings --------- Co-authored-by: johnny9 <985648+johnny9@users.noreply.github.com>
This commit is contained in:
parent
6d76741af8
commit
199c151c0f
9
.github/workflows/build.yml
vendored
9
.github/workflows/build.yml
vendored
@ -8,6 +8,15 @@ jobs:
|
|||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: '16'
|
||||||
|
- name: Build web dist
|
||||||
|
working-directory: ./main/http_server/axe-os
|
||||||
|
run: |
|
||||||
|
npm ci
|
||||||
|
npm run build
|
||||||
- name: esp-idf build
|
- name: esp-idf build
|
||||||
uses: espressif/esp-idf-ci-action@v1
|
uses: espressif/esp-idf-ci-action@v1
|
||||||
with:
|
with:
|
||||||
|
9
.gitignore
vendored
9
.gitignore
vendored
@ -3,8 +3,13 @@ sdkconfig
|
|||||||
sdkconfig.old
|
sdkconfig.old
|
||||||
dependencies.lock
|
dependencies.lock
|
||||||
|
|
||||||
# User specific VSCode
|
# Visual Studio Code
|
||||||
**/.vscode/*
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
# Production folder
|
# Production folder
|
||||||
build/
|
build/
|
||||||
|
17
.vscode/settings.json
vendored
Normal file
17
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"idf.flashType": "UART",
|
||||||
|
"idf.portWin": "COM6",
|
||||||
|
"idf.adapterTargetName": "esp32s3",
|
||||||
|
"idf.openOcdConfigs": [
|
||||||
|
"interface/ftdi/esp32_devkitj_v1.cfg",
|
||||||
|
"target/esp32s3.cfg"
|
||||||
|
],
|
||||||
|
"files.associations": {
|
||||||
|
"freertos.h": "c",
|
||||||
|
"esp_netif.h": "c",
|
||||||
|
"esp_http_server.h": "c",
|
||||||
|
"esp_chip_info.h": "c",
|
||||||
|
"xtensa_context.h": "c"
|
||||||
|
},
|
||||||
|
"editor.formatOnSave": true
|
||||||
|
}
|
@ -7,4 +7,7 @@ cmake_minimum_required(VERSION 3.5)
|
|||||||
# set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
# set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||||
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
|
||||||
|
|
||||||
project(esp-miner)
|
project(esp-miner)
|
||||||
|
|
||||||
|
@ -8,12 +8,12 @@
|
|||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
|
#include "lwip/lwip_napt.h"
|
||||||
#include "lwip/err.h"
|
#include "lwip/err.h"
|
||||||
#include "lwip/sys.h"
|
#include "lwip/sys.h"
|
||||||
|
|
||||||
#include "connect.h"
|
#include "connect.h"
|
||||||
#include "miner.h"
|
#include "main.h"
|
||||||
|
|
||||||
|
|
||||||
#if CONFIG_ESP_WPA3_SAE_PWE_HUNT_AND_PECK
|
#if CONFIG_ESP_WPA3_SAE_PWE_HUNT_AND_PECK
|
||||||
@ -59,6 +59,10 @@ static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_
|
|||||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||||
esp_wifi_connect();
|
esp_wifi_connect();
|
||||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||||
|
|
||||||
|
// Wait a little
|
||||||
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
if (s_retry_num < WIFI_MAXIMUM_RETRY) {
|
if (s_retry_num < WIFI_MAXIMUM_RETRY) {
|
||||||
esp_wifi_connect();
|
esp_wifi_connect();
|
||||||
s_retry_num++;
|
s_retry_num++;
|
||||||
@ -77,23 +81,53 @@ static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EventBits_t wifi_init_sta(const char * wifi_ssid, const char * wifi_pass) {
|
|
||||||
s_wifi_event_group = xEventGroupCreate();
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_netif_init());
|
esp_netif_t *wifi_init_softap(void)
|
||||||
|
{
|
||||||
|
esp_netif_t *esp_netif_ap = esp_netif_create_default_wifi_ap();
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
wifi_config_t wifi_ap_config = {
|
||||||
esp_netif_create_default_wifi_sta();
|
.ap = {
|
||||||
|
.ssid = "Bitaxe",
|
||||||
|
.ssid_len = strlen("Bitaxe"),
|
||||||
|
.channel = 1,
|
||||||
|
.max_connection = 30,
|
||||||
|
.authmode = WIFI_AUTH_OPEN,
|
||||||
|
.pmf_cfg = {
|
||||||
|
.required = false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_ap_config));
|
||||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
|
||||||
|
|
||||||
esp_event_handler_instance_t instance_any_id;
|
return esp_netif_ap;
|
||||||
esp_event_handler_instance_t instance_got_ip;
|
}
|
||||||
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));
|
|
||||||
|
|
||||||
wifi_config_t wifi_config = {
|
void toggle_wifi_softap(void){
|
||||||
|
wifi_mode_t mode = WIFI_MODE_NULL;
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_get_mode(&mode));
|
||||||
|
|
||||||
|
if (mode == WIFI_MODE_APSTA) {
|
||||||
|
ESP_LOGI(TAG, "ESP_WIFI Access Point Off");
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "ESP_WIFI Access Point On");
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wifi_softap_off(void){
|
||||||
|
ESP_LOGI(TAG, "ESP_WIFI Access Point Off");
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize wifi station */
|
||||||
|
esp_netif_t *wifi_init_sta(const char * wifi_ssid, const char * wifi_pass)
|
||||||
|
{
|
||||||
|
esp_netif_t *esp_netif_sta = esp_netif_create_default_wifi_sta();
|
||||||
|
|
||||||
|
wifi_config_t wifi_sta_config = {
|
||||||
.sta = {
|
.sta = {
|
||||||
/* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (pasword len => 8).
|
/* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (pasword len => 8).
|
||||||
* If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value
|
* If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value
|
||||||
@ -105,17 +139,55 @@ EventBits_t wifi_init_sta(const char * wifi_ssid, const char * wifi_pass) {
|
|||||||
// .sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,
|
// .sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
strncpy((char *) wifi_config.sta.ssid, wifi_ssid, 31);
|
strncpy((char *) wifi_sta_config.sta.ssid, wifi_ssid, 31);
|
||||||
wifi_config.sta.ssid[31] = '\0';
|
wifi_sta_config.sta.ssid[31] = '\0';
|
||||||
strncpy((char *) wifi_config.sta.password, wifi_pass, 63);
|
strncpy((char *) wifi_sta_config.sta.password, wifi_pass, 63);
|
||||||
wifi_config.sta.password[63] = '\0';
|
wifi_sta_config.sta.password[63] = '\0';
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_sta_config) );
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "wifi_init_sta finished.");
|
||||||
|
|
||||||
|
return esp_netif_sta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void wifi_init(const char * wifi_ssid, const char * wifi_pass) {
|
||||||
|
s_wifi_event_group = xEventGroupCreate();
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_netif_init());
|
||||||
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||||
|
|
||||||
|
esp_event_handler_instance_t instance_any_id;
|
||||||
|
esp_event_handler_instance_t instance_got_ip;
|
||||||
|
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 */
|
||||||
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
|
||||||
|
|
||||||
|
/* Initialize AP */
|
||||||
|
ESP_LOGI(TAG, "ESP_WIFI Access Point On");
|
||||||
|
esp_netif_t *esp_netif_ap = 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() );
|
ESP_ERROR_CHECK(esp_wifi_start() );
|
||||||
|
|
||||||
ESP_LOGI(TAG, "wifi_init_sta finished.");
|
ESP_LOGI(TAG, "wifi_init_sta finished.");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EventBits_t wifi_connect(void){
|
||||||
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
|
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
|
||||||
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
|
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
|
||||||
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
||||||
|
@ -27,4 +27,7 @@ typedef enum {
|
|||||||
WIFI_RETRYING,
|
WIFI_RETRYING,
|
||||||
} wifi_status_t;
|
} wifi_status_t;
|
||||||
|
|
||||||
EventBits_t wifi_init_sta(const char * ssid, const char * pass);
|
void toggle_wifi_softap(void);
|
||||||
|
void wifi_softap_off(void);
|
||||||
|
void wifi_init(const char * wifi_ssid, const char * wifi_pass);
|
||||||
|
EventBits_t wifi_connect(void);
|
||||||
|
@ -6,7 +6,7 @@ SRCS
|
|||||||
"fonts.c"
|
"fonts.c"
|
||||||
"INA260.c"
|
"INA260.c"
|
||||||
"led_controller.c"
|
"led_controller.c"
|
||||||
"miner.c"
|
"main.c"
|
||||||
"nvs_config.c"
|
"nvs_config.c"
|
||||||
"oled.c"
|
"oled.c"
|
||||||
"system.c"
|
"system.c"
|
||||||
@ -15,9 +15,20 @@ SRCS
|
|||||||
"./tasks/create_jobs_task.c"
|
"./tasks/create_jobs_task.c"
|
||||||
"./tasks/asic_task.c"
|
"./tasks/asic_task.c"
|
||||||
"./tasks/asic_result_task.c"
|
"./tasks/asic_result_task.c"
|
||||||
|
"./tasks/user_input_task.c"
|
||||||
"./tasks/power_management_task.c"
|
"./tasks/power_management_task.c"
|
||||||
|
"./http_server/http_server.c"
|
||||||
|
|
||||||
INCLUDE_DIRS
|
INCLUDE_DIRS
|
||||||
"."
|
"."
|
||||||
"tasks"
|
"tasks"
|
||||||
|
"http_server"
|
||||||
"../components/connect/include"
|
"../components/connect/include"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(WEB_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/http_server/axe-os")
|
||||||
|
if(EXISTS ${WEB_SRC_DIR}/dist/axe-os)
|
||||||
|
spiffs_create_partition_image(www ${WEB_SRC_DIR}/dist/axe-os FLASH_IN_PROJECT)
|
||||||
|
else()
|
||||||
|
message(WARNING "${WEB_SRC_DIR}/dist doesn't exit. Please run 'npm run build' in ${WEB_SRC_DIR}")
|
||||||
|
endif()
|
@ -53,4 +53,5 @@ typedef struct {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* GLOBAL_STATE_H_ */
|
#endif /* GLOBAL_STATE_H_ */
|
16
main/http_server/axe-os/.editorconfig
Normal file
16
main/http_server/axe-os/.editorconfig
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.ts]
|
||||||
|
quote_type = single
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
42
main/http_server/axe-os/.gitignore
vendored
Normal file
42
main/http_server/axe-os/.gitignore
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# Compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# Node
|
||||||
|
/node_modules
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
.idea/
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
/.angular/cache
|
||||||
|
.sass-cache/
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
4
main/http_server/axe-os/.vscode/extensions.json
vendored
Normal file
4
main/http_server/axe-os/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
||||||
|
"recommendations": ["angular.ng-template"]
|
||||||
|
}
|
20
main/http_server/axe-os/.vscode/launch.json
vendored
Normal file
20
main/http_server/axe-os/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "ng serve",
|
||||||
|
"type": "chrome",
|
||||||
|
"request": "launch",
|
||||||
|
"url": "http://localhost:4200/",
|
||||||
|
"sourceMaps": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ng test",
|
||||||
|
"type": "chrome",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "npm: test",
|
||||||
|
"url": "http://localhost:9876/debug.html"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
5
main/http_server/axe-os/.vscode/settings.json
vendored
Normal file
5
main/http_server/axe-os/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"cSpell.words": [
|
||||||
|
"toastr"
|
||||||
|
]
|
||||||
|
}
|
42
main/http_server/axe-os/.vscode/tasks.json
vendored
Normal file
42
main/http_server/axe-os/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "start",
|
||||||
|
"isBackground": true,
|
||||||
|
"problemMatcher": {
|
||||||
|
"owner": "typescript",
|
||||||
|
"pattern": "$tsc",
|
||||||
|
"background": {
|
||||||
|
"activeOnStart": true,
|
||||||
|
"beginsPattern": {
|
||||||
|
"regexp": "(.*?)"
|
||||||
|
},
|
||||||
|
"endsPattern": {
|
||||||
|
"regexp": "bundle generation complete"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "test",
|
||||||
|
"isBackground": true,
|
||||||
|
"problemMatcher": {
|
||||||
|
"owner": "typescript",
|
||||||
|
"pattern": "$tsc",
|
||||||
|
"background": {
|
||||||
|
"activeOnStart": true,
|
||||||
|
"beginsPattern": {
|
||||||
|
"regexp": "(.*?)"
|
||||||
|
},
|
||||||
|
"endsPattern": {
|
||||||
|
"regexp": "bundle generation complete"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
27
main/http_server/axe-os/README.md
Normal file
27
main/http_server/axe-os/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# AxeOs
|
||||||
|
|
||||||
|
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 16.1.3.
|
||||||
|
|
||||||
|
## Development server
|
||||||
|
|
||||||
|
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||||
|
|
||||||
|
## Running end-to-end tests
|
||||||
|
|
||||||
|
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
|
||||||
|
|
||||||
|
## Further help
|
||||||
|
|
||||||
|
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
111
main/http_server/axe-os/angular.json
Normal file
111
main/http_server/axe-os/angular.json
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"axe-os": {
|
||||||
|
"projectType": "application",
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"style": "scss"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"prefix": "app",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/axe-os",
|
||||||
|
"index": "src/index.html",
|
||||||
|
"main": "src/main.ts",
|
||||||
|
"polyfills": [
|
||||||
|
"zone.js"
|
||||||
|
],
|
||||||
|
"tsConfig": "tsconfig.app.json",
|
||||||
|
"inlineStyleLanguage": "scss",
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss",
|
||||||
|
"node_modules/ngx-toastr/toastr.css"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "750kb",
|
||||||
|
"maximumError": "1mb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "anyComponentStyle",
|
||||||
|
"maximumWarning": "2kb",
|
||||||
|
"maximumError": "4kb"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputHashing": "all"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"buildOptimizer": false,
|
||||||
|
"optimization": false,
|
||||||
|
"vendorChunk": true,
|
||||||
|
"extractLicenses": false,
|
||||||
|
"sourceMap": true,
|
||||||
|
"namedChunks": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "production"
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"browserTarget": "axe-os:build:production"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"browserTarget": "axe-os:build:development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "development"
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "axe-os:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"polyfills": [
|
||||||
|
"zone.js",
|
||||||
|
"zone.js/testing"
|
||||||
|
],
|
||||||
|
"tsConfig": "tsconfig.spec.json",
|
||||||
|
"inlineStyleLanguage": "scss",
|
||||||
|
"assets": [
|
||||||
|
"src/favicon.ico",
|
||||||
|
"src/assets"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.scss"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13229
main/http_server/axe-os/package-lock.json
generated
Normal file
13229
main/http_server/axe-os/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
42
main/http_server/axe-os/package.json
Normal file
42
main/http_server/axe-os/package.json
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"name": "axe-os",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"start": "ng serve",
|
||||||
|
"build": "ng build --configuration=production",
|
||||||
|
"watch": "ng build --watch --configuration development",
|
||||||
|
"test": "ng test",
|
||||||
|
"bundle-report": "ng build --configuration=production --stats-json && webpack-bundle-analyzer dist/axe-os/stats.json"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/animations": "^16.1.0",
|
||||||
|
"@angular/common": "^16.1.0",
|
||||||
|
"@angular/compiler": "^16.1.0",
|
||||||
|
"@angular/core": "^16.1.0",
|
||||||
|
"@angular/forms": "^16.1.0",
|
||||||
|
"@angular/platform-browser": "^16.1.0",
|
||||||
|
"@angular/platform-browser-dynamic": "^16.1.0",
|
||||||
|
"@angular/router": "^16.1.0",
|
||||||
|
"ngx-toastr": "^17.0.2",
|
||||||
|
"rxjs": "~7.8.0",
|
||||||
|
"tslib": "^2.3.0",
|
||||||
|
"zone.js": "~0.13.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular-devkit/build-angular": "^16.1.3",
|
||||||
|
"@angular/cli": "~16.1.3",
|
||||||
|
"@angular/compiler-cli": "^16.1.0",
|
||||||
|
"@types/jasmine": "~4.3.0",
|
||||||
|
"gzipper": "^7.2.0",
|
||||||
|
"jasmine-core": "~4.6.0",
|
||||||
|
"karma": "~6.4.0",
|
||||||
|
"karma-chrome-launcher": "~3.2.0",
|
||||||
|
"karma-coverage": "~2.2.0",
|
||||||
|
"karma-jasmine": "~5.1.0",
|
||||||
|
"karma-jasmine-html-reporter": "~2.1.0",
|
||||||
|
"typescript": "~5.1.3",
|
||||||
|
"webpack-bundle-analyzer": "^4.9.0"
|
||||||
|
}
|
||||||
|
}
|
22
main/http_server/axe-os/src/app/app-routing.module.ts
Normal file
22
main/http_server/axe-os/src/app/app-routing.module.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
|
||||||
|
import { EditComponent } from './components/edit/edit.component';
|
||||||
|
import { HomeComponent } from './components/home/home.component';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: HomeComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'edit',
|
||||||
|
component: EditComponent
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forRoot(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class AppRoutingModule { }
|
5
main/http_server/axe-os/src/app/app.component.html
Normal file
5
main/http_server/axe-os/src/app/app.component.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<app-loading></app-loading>
|
||||||
|
<app-header></app-header>
|
||||||
|
<div class="content">
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</div>
|
14
main/http_server/axe-os/src/app/app.component.scss
Normal file
14
main/http_server/axe-os/src/app/app.component.scss
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
.content {
|
||||||
|
margin-top: 150px;
|
||||||
|
|
||||||
|
padding-left: 10vw;
|
||||||
|
padding-right: 10vw;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width:900px) {
|
||||||
|
.content {
|
||||||
|
padding-left: 25px;
|
||||||
|
padding-right: 25px;
|
||||||
|
}
|
||||||
|
}
|
29
main/http_server/axe-os/src/app/app.component.spec.ts
Normal file
29
main/http_server/axe-os/src/app/app.component.spec.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
describe('AppComponent', () => {
|
||||||
|
beforeEach(() => TestBed.configureTestingModule({
|
||||||
|
imports: [RouterTestingModule],
|
||||||
|
declarations: [AppComponent]
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should create the app', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should have as title 'axe-os'`, () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app.title).toEqual('axe-os');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render title', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.nativeElement as HTMLElement;
|
||||||
|
expect(compiled.querySelector('.content span')?.textContent).toContain('axe-os app is running!');
|
||||||
|
});
|
||||||
|
});
|
15
main/http_server/axe-os/src/app/app.component.ts
Normal file
15
main/http_server/axe-os/src/app/app.component.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrls: ['./app.component.scss']
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
44
main/http_server/axe-os/src/app/app.module.ts
Normal file
44
main/http_server/axe-os/src/app/app.module.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { CommonModule, HashLocationStrategy, LocationStrategy } from '@angular/common';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
import { ToastrModule } from 'ngx-toastr';
|
||||||
|
|
||||||
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { EditComponent } from './components/edit/edit.component';
|
||||||
|
import { HeaderComponent } from './components/header/header.component';
|
||||||
|
import { HomeComponent } from './components/home/home.component';
|
||||||
|
import { LoadingComponent } from './components/loading/loading.component';
|
||||||
|
|
||||||
|
const components = [
|
||||||
|
AppComponent,
|
||||||
|
HeaderComponent
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
...components,
|
||||||
|
EditComponent,
|
||||||
|
HomeComponent,
|
||||||
|
LoadingComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
AppRoutingModule,
|
||||||
|
HttpClientModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
ToastrModule.forRoot({
|
||||||
|
positionClass: 'toast-bottom-right'
|
||||||
|
}),
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
CommonModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: LocationStrategy, useClass: HashLocationStrategy },
|
||||||
|
],
|
||||||
|
bootstrap: [AppComponent]
|
||||||
|
})
|
||||||
|
export class AppModule { }
|
@ -0,0 +1,48 @@
|
|||||||
|
<div class="card">
|
||||||
|
<h2>Edit</h2>
|
||||||
|
<ng-container *ngIf="form != null">
|
||||||
|
<form [formGroup]="form">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>WiFi SSID: </label>
|
||||||
|
<input formControlName="ssid" type="text">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>WiFi Password: </label>
|
||||||
|
<input formControlName="wifiPass" type="password">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Stratum URL:</label>
|
||||||
|
<input formControlName="stratumURL" type="text">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Stratum Port:</label>
|
||||||
|
<input formControlName="stratumPort" type="number">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Stratum User: </label>
|
||||||
|
<input formControlName="stratumUser" type="text">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</ng-container>
|
||||||
|
<div class="mt-2">
|
||||||
|
<button (click)="updateSystem()" class="btn btn-primary mr-2">Save</button>
|
||||||
|
<button [routerLink]="['/']" class="btn btn-secondary">Cancel</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<h2>Update Firmware <span *ngIf="firmwareUpdateProgress != null">{{firmwareUpdateProgress}}%</span></h2>
|
||||||
|
<input type="file" id="file" (change)="otaUpdate($event)" accept=".bin">
|
||||||
|
<br>
|
||||||
|
<small>(esp-miner.bin)</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<h2>Update Website <span *ngIf="websiteUpdateProgress != null">{{websiteUpdateProgress}}%</span></h2>
|
||||||
|
<input type="file" id="file" (change)="otaWWWUpdate($event)" accept=".bin">
|
||||||
|
<br>
|
||||||
|
<small>(www.bin)</small>
|
||||||
|
</div>
|
@ -0,0 +1,3 @@
|
|||||||
|
input {
|
||||||
|
min-width: 500px
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { EditComponent } from './edit.component';
|
||||||
|
|
||||||
|
describe('EditComponent', () => {
|
||||||
|
let component: EditComponent;
|
||||||
|
let fixture: ComponentFixture<EditComponent>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [EditComponent]
|
||||||
|
});
|
||||||
|
fixture = TestBed.createComponent(EditComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,114 @@
|
|||||||
|
import { HttpErrorResponse, HttpEventType } from '@angular/common/http';
|
||||||
|
import { Component } 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-edit',
|
||||||
|
templateUrl: './edit.component.html',
|
||||||
|
styleUrls: ['./edit.component.scss']
|
||||||
|
})
|
||||||
|
export class EditComponent {
|
||||||
|
|
||||||
|
public form!: FormGroup;
|
||||||
|
|
||||||
|
public firmwareUpdateProgress: number | null = null;
|
||||||
|
public websiteUpdateProgress: number | null = null;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private fb: FormBuilder,
|
||||||
|
private systemService: SystemService,
|
||||||
|
private toastr: ToastrService,
|
||||||
|
private toastrService: ToastrService,
|
||||||
|
private loadingService: LoadingService
|
||||||
|
) {
|
||||||
|
this.systemService.getInfo()
|
||||||
|
.pipe(this.loadingService.lockUIUntilComplete())
|
||||||
|
.subscribe(info => {
|
||||||
|
this.form = this.fb.group({
|
||||||
|
stratumURL: [info.stratumURL, [Validators.required]],
|
||||||
|
stratumPort: [info.stratumPort, [Validators.required]],
|
||||||
|
stratumUser: [info.stratumUser, [Validators.required]],
|
||||||
|
ssid: [info.ssid, [Validators.required]],
|
||||||
|
wifiPass: [info.wifiPass, [Validators.required]],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateSystem() {
|
||||||
|
this.systemService.updateSystem(this.form.value)
|
||||||
|
.pipe(this.loadingService.lockUIUntilComplete())
|
||||||
|
.subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.toastr.success('Success!', 'Saved.');
|
||||||
|
},
|
||||||
|
error: (err: HttpErrorResponse) => {
|
||||||
|
this.toastr.error('Error.', `Could not save. ${err.message}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
otaUpdate(event: any) {
|
||||||
|
const file = event.target?.files.item(0) as File;
|
||||||
|
|
||||||
|
if (file.name != 'esp-miner.bin') {
|
||||||
|
this.toastrService.error('Incorrect file, looking for esp-miner.bin.', 'Error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.systemService.performOTAUpdate(file)
|
||||||
|
.pipe(this.loadingService.lockUIUntilComplete())
|
||||||
|
.subscribe({
|
||||||
|
next: (event) => {
|
||||||
|
if (event.type === HttpEventType.UploadProgress) {
|
||||||
|
this.firmwareUpdateProgress = Math.round((event.loaded / (event.total as number)) * 100);
|
||||||
|
} else if (event.type === HttpEventType.Response) {
|
||||||
|
if (event.ok) {
|
||||||
|
this.toastrService.success('Firmware updated', 'Success!');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.toastrService.error(event.statusText, 'Error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
this.toastrService.error(event.statusText, 'Error');
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
this.firmwareUpdateProgress = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
otaWWWUpdate(event: any) {
|
||||||
|
const file = event.target?.files.item(0) as File;
|
||||||
|
if (file.name != 'www.bin') {
|
||||||
|
this.toastrService.error('Incorrect file, looking for www.bin.', 'Error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.systemService.performWWWOTAUpdate(file)
|
||||||
|
.pipe(this.loadingService.lockUIUntilComplete())
|
||||||
|
.subscribe({
|
||||||
|
next: (event) => {
|
||||||
|
if (event.type === HttpEventType.UploadProgress) {
|
||||||
|
this.websiteUpdateProgress = Math.round((event.loaded / (event.total as number)) * 100);
|
||||||
|
} else if (event.type === HttpEventType.Response) {
|
||||||
|
if (event.ok) {
|
||||||
|
this.toastrService.success('Website updated', 'Success!');
|
||||||
|
window.location.reload();
|
||||||
|
} else {
|
||||||
|
this.toastrService.error(event.statusText, 'Error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
this.toastrService.error(event.statusText, 'Error');
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
this.websiteUpdateProgress = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
<div [routerLink]="['/']" class="header-text">AxeOS</div>
|
@ -0,0 +1,16 @@
|
|||||||
|
:host {
|
||||||
|
height: 70px;
|
||||||
|
background-color: #1f2d40;
|
||||||
|
border-bottom: 1px solid #304562;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-text {
|
||||||
|
font-size: 30pt;
|
||||||
|
padding: 6px;
|
||||||
|
margin-left: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { HeaderComponent } from './header.component';
|
||||||
|
|
||||||
|
describe('HeaderComponent', () => {
|
||||||
|
let component: HeaderComponent;
|
||||||
|
let fixture: ComponentFixture<HeaderComponent>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [HeaderComponent]
|
||||||
|
});
|
||||||
|
fixture = TestBed.createComponent(HeaderComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,10 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-header',
|
||||||
|
templateUrl: './header.component.html',
|
||||||
|
styleUrls: ['./header.component.scss']
|
||||||
|
})
|
||||||
|
export class HeaderComponent {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
<ng-container *ngIf="info$ | async as info">
|
||||||
|
<div class="button-row">
|
||||||
|
<button [routerLink]="['edit']" class="btn btn-primary edit">Edit</button>
|
||||||
|
<button (click)="restart()" class="btn btn-danger restart">Restart</button>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<h2>Pool Information</h2>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>URL:</td>
|
||||||
|
<td>{{info.stratumURL}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Port:</td>
|
||||||
|
<td>{{info.stratumPort}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>User:</td>
|
||||||
|
<td>{{info.stratumUser}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Shares Accepted:</td>
|
||||||
|
<td>{{info.sharesAccepted}}</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Shares Rejected:</td>
|
||||||
|
<td>{{info.sharesRejected}}</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
<div>
|
||||||
|
<div class="card">
|
||||||
|
<h2>Overview</h2>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Model:</td>
|
||||||
|
<td>{{info.ASICModel}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uptime (seconds):</td>
|
||||||
|
<td>{{info.uptimeSeconds}}</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>WiFi Status:</td>
|
||||||
|
<td>{{info.wifiStatus}}</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Free Heap Memory:</td>
|
||||||
|
<td>{{info.freeHeap}}</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="card">
|
||||||
|
<h2>Power</h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Power Consumption:</td>
|
||||||
|
<td>{{info.power | number: '1.2-2'}} <small>W</small></td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Input Voltage:</td>
|
||||||
|
<td>{{info.voltage | number: '0.0-0'}} <small>mV</small></td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Input Current:</td>
|
||||||
|
<td>{{info.current | number: '0.0-0'}} <small>mA</small></td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Core Voltage:</td>
|
||||||
|
<td>{{info.coreVoltage}} <small>mV</small></td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Fan Speed:</td>
|
||||||
|
<td>{{info.fanSpeed}} <small>RPM</small></td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<h2>Results</h2>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td> Hash Rate:</td>
|
||||||
|
<td>{{info.hashRate | number: '1.2-2'}}Gh/s</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Best Difficulty:</td>
|
||||||
|
<td>{{info.bestDiff}}</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
@ -0,0 +1,39 @@
|
|||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 2fr 2fr;
|
||||||
|
grid-gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
table>tr>td {
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
text-align: right;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(2) {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width:900px) {
|
||||||
|
.container {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.restart {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { HomeComponent } from './home.component';
|
||||||
|
|
||||||
|
describe('HomeComponent', () => {
|
||||||
|
let component: HomeComponent;
|
||||||
|
let fixture: ComponentFixture<HomeComponent>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [HomeComponent]
|
||||||
|
});
|
||||||
|
fixture = TestBed.createComponent(HomeComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,33 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { ToastrService } from 'ngx-toastr';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { LoadingService } from 'src/app/services/loading.service';
|
||||||
|
import { SystemService } from 'src/app/services/system.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-home',
|
||||||
|
templateUrl: './home.component.html',
|
||||||
|
styleUrls: ['./home.component.scss']
|
||||||
|
})
|
||||||
|
export class HomeComponent {
|
||||||
|
|
||||||
|
public info$: Observable<any>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private systemService: SystemService,
|
||||||
|
private toastr: ToastrService,
|
||||||
|
private loadingService: LoadingService
|
||||||
|
) {
|
||||||
|
this.info$ = this.systemService.getInfo().pipe(
|
||||||
|
this.loadingService.lockUIUntilComplete()
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public restart() {
|
||||||
|
this.systemService.restart().subscribe(res => {
|
||||||
|
|
||||||
|
});
|
||||||
|
this.toastr.success('Success!', 'Bitaxe restarted');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
<div id="loading" *ngIf="loading$ | async">
|
||||||
|
<div id="loading-text">Working...</div>
|
||||||
|
</div>
|
@ -0,0 +1,16 @@
|
|||||||
|
#loading {
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
pointer-events: none;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loading-text {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 40vh;
|
||||||
|
font-size: 20pt;
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { LoadingComponent } from './loading.component';
|
||||||
|
|
||||||
|
describe('LoadingComponent', () => {
|
||||||
|
let component: LoadingComponent;
|
||||||
|
let fixture: ComponentFixture<LoadingComponent>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [LoadingComponent]
|
||||||
|
});
|
||||||
|
fixture = TestBed.createComponent(LoadingComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,17 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { LoadingService } from 'src/app/services/loading.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-loading',
|
||||||
|
templateUrl: './loading.component.html',
|
||||||
|
styleUrls: ['./loading.component.scss']
|
||||||
|
})
|
||||||
|
export class LoadingComponent {
|
||||||
|
|
||||||
|
public loading$: Observable<boolean>;
|
||||||
|
|
||||||
|
constructor(private loadingService: LoadingService) {
|
||||||
|
this.loading$ = this.loadingService.loading$.asObservable();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { LoadingService } from './loading.service';
|
||||||
|
|
||||||
|
describe('LoadingService', () => {
|
||||||
|
let service: LoadingService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(LoadingService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
33
main/http_server/axe-os/src/app/services/loading.service.ts
Normal file
33
main/http_server/axe-os/src/app/services/loading.service.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class LoadingService {
|
||||||
|
|
||||||
|
public loading$: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
public lockUIUntilComplete() {
|
||||||
|
return <T>(source: Observable<T>): Observable<T> => {
|
||||||
|
return new Observable(subscriber => {
|
||||||
|
this.loading$.next(true);
|
||||||
|
source.subscribe({
|
||||||
|
next: (value) => {
|
||||||
|
subscriber.next(value);
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
subscriber.next(err);
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
this.loading$.next(false);
|
||||||
|
subscriber.complete();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { SystemService } from './system.service';
|
||||||
|
|
||||||
|
describe('SystemService', () => {
|
||||||
|
let service: SystemService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(SystemService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
93
main/http_server/axe-os/src/app/services/system.service.ts
Normal file
93
main/http_server/axe-os/src/app/services/system.service.ts
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import { HttpClient, HttpEvent } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { delay, Observable, of } from 'rxjs';
|
||||||
|
import { ISystemInfo } from 'src/models/ISystemInfo';
|
||||||
|
|
||||||
|
import { environment } from '../../environments/environment';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class SystemService {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private httpClient: HttpClient
|
||||||
|
) { }
|
||||||
|
|
||||||
|
public getInfo(): Observable<ISystemInfo> {
|
||||||
|
if (environment.production) {
|
||||||
|
return this.httpClient.get(`/api/system/info`) as Observable<ISystemInfo>;
|
||||||
|
} else {
|
||||||
|
return of(
|
||||||
|
{
|
||||||
|
"power": 11.670000076293945,
|
||||||
|
"voltage": 5208.75,
|
||||||
|
"current": 2237.5,
|
||||||
|
"fanSpeed": 82,
|
||||||
|
"hashRate": 0,
|
||||||
|
"bestDiff": "0",
|
||||||
|
"freeHeap": 200504,
|
||||||
|
"coreVoltage": 1188,
|
||||||
|
"ssid": "skimadtrees-secure",
|
||||||
|
"wifiPass": "password",
|
||||||
|
"wifiStatus": "Connected!",
|
||||||
|
"sharesAccepted": 1,
|
||||||
|
"sharesRejected": 0,
|
||||||
|
"uptimeSeconds": 38,
|
||||||
|
"ASICModel": "BM1366",
|
||||||
|
"stratumURL": "192.168.1.242",
|
||||||
|
"stratumPort": 3333,
|
||||||
|
"stratumUser": "bc1q99n3pu025yyu0jlywpmwzalyhm36tg5u37w20d.bitaxe-U1"
|
||||||
|
}
|
||||||
|
).pipe(delay(1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public restart() {
|
||||||
|
return this.httpClient.post(`/api/system/restart`, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateSystem(update: any) {
|
||||||
|
return this.httpClient.patch(`/api/system`, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private otaUpdate(file: File, url: string) {
|
||||||
|
return new Observable<HttpEvent<string>>((subscriber) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onload = (event: any) => {
|
||||||
|
const fileContent = event.target.result;
|
||||||
|
|
||||||
|
return this.httpClient.post(url, fileContent, {
|
||||||
|
reportProgress: true,
|
||||||
|
observe: 'events',
|
||||||
|
responseType: 'text', // Specify the response type
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/octet-stream', // Set the content type
|
||||||
|
},
|
||||||
|
}).subscribe({
|
||||||
|
next: (e) => {
|
||||||
|
subscriber.next(e)
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
subscriber.error(err)
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
subscriber.complete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
reader.readAsArrayBuffer(file);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public performOTAUpdate(file: File) {
|
||||||
|
return this.otaUpdate(file, `/api/system/OTA`);
|
||||||
|
}
|
||||||
|
public performWWWOTAUpdate(file: File) {
|
||||||
|
return this.otaUpdate(file, `/api/system/OTAWWW`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
0
main/http_server/axe-os/src/assets/.gitkeep
Normal file
0
main/http_server/axe-os/src/assets/.gitkeep
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const environment = {
|
||||||
|
production: true
|
||||||
|
};
|
3
main/http_server/axe-os/src/environments/environment.ts
Normal file
3
main/http_server/axe-os/src/environments/environment.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const environment = {
|
||||||
|
production: false
|
||||||
|
};
|
BIN
main/http_server/axe-os/src/favicon.ico
Normal file
BIN
main/http_server/axe-os/src/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
13
main/http_server/axe-os/src/index.html
Normal file
13
main/http_server/axe-os/src/index.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>AxeOs</title>
|
||||||
|
<base href="/">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<app-root></app-root>
|
||||||
|
</body>
|
||||||
|
</html>
|
7
main/http_server/axe-os/src/main.ts
Normal file
7
main/http_server/axe-os/src/main.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
|
import { AppModule } from './app/app.module';
|
||||||
|
|
||||||
|
|
||||||
|
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||||
|
.catch(err => console.error(err));
|
21
main/http_server/axe-os/src/models/ISystemInfo.ts
Normal file
21
main/http_server/axe-os/src/models/ISystemInfo.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
export interface ISystemInfo {
|
||||||
|
|
||||||
|
power: number,
|
||||||
|
voltage: number,
|
||||||
|
current: number,
|
||||||
|
fanSpeed: number,
|
||||||
|
hashRate: number,
|
||||||
|
bestDiff: string,
|
||||||
|
freeHeap: number,
|
||||||
|
coreVoltage: number,
|
||||||
|
ssid: string,
|
||||||
|
wifiPass: string,
|
||||||
|
wifiStatus: string,
|
||||||
|
sharesAccepted: number,
|
||||||
|
sharesRejected: number,
|
||||||
|
uptimeSeconds: number,
|
||||||
|
ASICModel: string,
|
||||||
|
stratumURL: string,
|
||||||
|
stratumPort: number,
|
||||||
|
stratumUser: string
|
||||||
|
}
|
161
main/http_server/axe-os/src/styles.scss
Normal file
161
main/http_server/axe-os/src/styles.scss
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/* You can add global styles to this file, and also import other style files */
|
||||||
|
body {
|
||||||
|
background-color: #17212f;
|
||||||
|
margin: 0;
|
||||||
|
color: white;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background-color: #1f2d40;
|
||||||
|
border: 1px solid #304562;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 1.5rem;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
line-break: anywhere;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin: 0;
|
||||||
|
display: inline-flex;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
align-items: center;
|
||||||
|
vertical-align: bottom;
|
||||||
|
text-align: center;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: background-color 0.2s, color 0.2s, border-color 0.2s, box-shadow 0.2s;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
&.btn-primary {
|
||||||
|
color: #212529;
|
||||||
|
background: #64B5F6;
|
||||||
|
border: 1px solid #64B5F6;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #43a5f4;
|
||||||
|
color: #212529;
|
||||||
|
border-color: #43a5f4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.btn-danger {
|
||||||
|
color: #121212;
|
||||||
|
background: #F48FB1;
|
||||||
|
border: 1px solid #F48FB1;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #f16c98;
|
||||||
|
color: #121212;
|
||||||
|
border-color: #f16c98;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.btn-secondary {
|
||||||
|
color: #ffffff;
|
||||||
|
background: #78909C;
|
||||||
|
border: 1px solid #78909C;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #69838f;
|
||||||
|
color: #ffffff;
|
||||||
|
border-color: #69838f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.btn-warning {
|
||||||
|
color: #121212;
|
||||||
|
background: #FFE082;
|
||||||
|
border: 1px solid #FFE082;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #ffd65c;
|
||||||
|
color: #121212;
|
||||||
|
border-color: #ffd65c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
|
||||||
|
font-size: 1rem;
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
background: #17212f;
|
||||||
|
padding: 0.5rem 0.5rem;
|
||||||
|
border: 1px solid #304562;
|
||||||
|
transition: background-color 0.2s, color 0.2s, border-color 0.2s, box-shadow 0.2s;
|
||||||
|
appearance: none;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
label,
|
||||||
|
input {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr-2 {
|
||||||
|
margin-right: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml-2 {
|
||||||
|
margin-left: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-2 {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-2 {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-fileupload-choose {
|
||||||
|
margin: 0;
|
||||||
|
display: inline-flex;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
align-items: center;
|
||||||
|
vertical-align: bottom;
|
||||||
|
text-align: center;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: background-color 0.2s, color 0.2s, border-color 0.2s, box-shadow 0.2s;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: #212529;
|
||||||
|
background: #64B5F6;
|
||||||
|
border: 1px solid #64B5F6;
|
||||||
|
}
|
14
main/http_server/axe-os/tsconfig.app.json
Normal file
14
main/http_server/axe-os/tsconfig.app.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/app",
|
||||||
|
"types": []
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/main.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
33
main/http_server/axe-os/tsconfig.json
Normal file
33
main/http_server/axe-os/tsconfig.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"compileOnSave": false,
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "./",
|
||||||
|
"outDir": "./dist/out-tsc",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": false,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"importHelpers": true,
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ES2022",
|
||||||
|
"useDefineForClassFields": false,
|
||||||
|
"lib": [
|
||||||
|
"ES2022",
|
||||||
|
"dom"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"enableI18nLegacyMessageIdFormat": false,
|
||||||
|
"strictInjectionParameters": true,
|
||||||
|
"strictInputAccessModifiers": true,
|
||||||
|
"strictTemplates": true
|
||||||
|
}
|
||||||
|
}
|
14
main/http_server/axe-os/tsconfig.spec.json
Normal file
14
main/http_server/axe-os/tsconfig.spec.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/spec",
|
||||||
|
"types": [
|
||||||
|
"jasmine"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
419
main/http_server/http_server.c
Normal file
419
main/http_server/http_server.c
Normal file
@ -0,0 +1,419 @@
|
|||||||
|
#include "http_server.h"
|
||||||
|
#include "global_state.h"
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/event_groups.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "esp_http_server.h"
|
||||||
|
#include "esp_chip_info.h"
|
||||||
|
#include "esp_random.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_vfs.h"
|
||||||
|
#include "cJSON.h"
|
||||||
|
#include "esp_spiffs.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "adc.h"
|
||||||
|
#include "esp_timer.h"
|
||||||
|
#include "nvs_config.h"
|
||||||
|
|
||||||
|
#include "esp_netif.h"
|
||||||
|
#include "esp_mac.h"
|
||||||
|
#include "esp_wifi.h"
|
||||||
|
#include "lwip/inet.h"
|
||||||
|
#include "lwip/netdb.h"
|
||||||
|
#include "lwip/sockets.h"
|
||||||
|
#include "lwip/lwip_napt.h"
|
||||||
|
#include "lwip/err.h"
|
||||||
|
#include "lwip/sys.h"
|
||||||
|
#include "esp_ota_ops.h"
|
||||||
|
|
||||||
|
static const char *TAG = "http_server";
|
||||||
|
|
||||||
|
static GlobalState *GLOBAL_STATE;
|
||||||
|
|
||||||
|
|
||||||
|
#define REST_CHECK(a, str, goto_tag, ...) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (!(a)) \
|
||||||
|
{ \
|
||||||
|
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||||
|
goto goto_tag; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128)
|
||||||
|
#define SCRATCH_BUFSIZE (10240)
|
||||||
|
|
||||||
|
typedef struct rest_server_context {
|
||||||
|
char base_path[ESP_VFS_PATH_MAX + 1];
|
||||||
|
char scratch[SCRATCH_BUFSIZE];
|
||||||
|
} rest_server_context_t;
|
||||||
|
|
||||||
|
#define CHECK_FILE_EXTENSION(filename, ext) (strcasecmp(&filename[strlen(filename) - strlen(ext)], ext) == 0)
|
||||||
|
|
||||||
|
|
||||||
|
esp_err_t init_fs(void)
|
||||||
|
{
|
||||||
|
esp_vfs_spiffs_conf_t conf = {
|
||||||
|
.base_path = "",
|
||||||
|
.partition_label = NULL,
|
||||||
|
.max_files = 5,
|
||||||
|
.format_if_mount_failed = false
|
||||||
|
};
|
||||||
|
esp_err_t ret = esp_vfs_spiffs_register(&conf);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
if (ret == ESP_FAIL) {
|
||||||
|
ESP_LOGE(TAG, "Failed to mount or format filesystem");
|
||||||
|
} else if (ret == ESP_ERR_NOT_FOUND) {
|
||||||
|
ESP_LOGE(TAG, "Failed to find SPIFFS partition");
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t total = 0, used = 0;
|
||||||
|
ret = esp_spiffs_info(NULL, &total, &used);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret));
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function for stopping the webserver */
|
||||||
|
void stop_webserver(httpd_handle_t server)
|
||||||
|
{
|
||||||
|
if (server) {
|
||||||
|
/* Stop the httpd server */
|
||||||
|
httpd_stop(server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set HTTP response content type according to file extension */
|
||||||
|
static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filepath)
|
||||||
|
{
|
||||||
|
const char *type = "text/plain";
|
||||||
|
if (CHECK_FILE_EXTENSION(filepath, ".html")) {
|
||||||
|
type = "text/html";
|
||||||
|
} else if (CHECK_FILE_EXTENSION(filepath, ".js")) {
|
||||||
|
type = "application/javascript";
|
||||||
|
} else if (CHECK_FILE_EXTENSION(filepath, ".css")) {
|
||||||
|
type = "text/css";
|
||||||
|
} else if (CHECK_FILE_EXTENSION(filepath, ".png")) {
|
||||||
|
type = "image/png";
|
||||||
|
} else if (CHECK_FILE_EXTENSION(filepath, ".ico")) {
|
||||||
|
type = "image/x-icon";
|
||||||
|
} else if (CHECK_FILE_EXTENSION(filepath, ".svg")) {
|
||||||
|
type = "text/xml";
|
||||||
|
}
|
||||||
|
return httpd_resp_set_type(req, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send HTTP response with the contents of the requested file */
|
||||||
|
static esp_err_t rest_common_get_handler(httpd_req_t *req)
|
||||||
|
{
|
||||||
|
char filepath[FILE_PATH_MAX];
|
||||||
|
|
||||||
|
rest_server_context_t *rest_context = (rest_server_context_t *)req->user_ctx;
|
||||||
|
strlcpy(filepath, rest_context->base_path, sizeof(filepath));
|
||||||
|
if (req->uri[strlen(req->uri) - 1] == '/') {
|
||||||
|
strlcat(filepath, "/index.html", sizeof(filepath));
|
||||||
|
} else {
|
||||||
|
strlcat(filepath, req->uri, sizeof(filepath));
|
||||||
|
}
|
||||||
|
int fd = open(filepath, O_RDONLY, 0);
|
||||||
|
if (fd == -1) {
|
||||||
|
ESP_LOGE(TAG, "Failed to open file : %s", filepath);
|
||||||
|
/* Respond with 500 Internal Server Error */
|
||||||
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to read existing file");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_content_type_from_file(req, filepath);
|
||||||
|
|
||||||
|
char *chunk = rest_context->scratch;
|
||||||
|
ssize_t read_bytes;
|
||||||
|
do {
|
||||||
|
/* Read file in chunks into the scratch buffer */
|
||||||
|
read_bytes = read(fd, chunk, SCRATCH_BUFSIZE);
|
||||||
|
if (read_bytes == -1) {
|
||||||
|
ESP_LOGE(TAG, "Failed to read file : %s", filepath);
|
||||||
|
} else if (read_bytes > 0) {
|
||||||
|
/* Send the buffer contents as HTTP response chunk */
|
||||||
|
if (httpd_resp_send_chunk(req, chunk, read_bytes) != ESP_OK) {
|
||||||
|
close(fd);
|
||||||
|
ESP_LOGE(TAG, "File sending failed!");
|
||||||
|
/* Abort sending file */
|
||||||
|
httpd_resp_sendstr_chunk(req, NULL);
|
||||||
|
/* Respond with 500 Internal Server Error */
|
||||||
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to send file");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (read_bytes > 0);
|
||||||
|
/* Close file after sending complete */
|
||||||
|
close(fd);
|
||||||
|
ESP_LOGI(TAG, "File sending complete");
|
||||||
|
/* Respond with an empty chunk to signal HTTP response completion */
|
||||||
|
httpd_resp_send_chunk(req, NULL, 0);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static esp_err_t PATCH_update_settings(httpd_req_t *req)
|
||||||
|
{
|
||||||
|
int total_len = req->content_len;
|
||||||
|
int cur_len = 0;
|
||||||
|
char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch;
|
||||||
|
int received = 0;
|
||||||
|
if (total_len >= SCRATCH_BUFSIZE) {
|
||||||
|
/* Respond with 500 Internal Server Error */
|
||||||
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
while (cur_len < total_len) {
|
||||||
|
received = httpd_req_recv(req, buf + cur_len, total_len);
|
||||||
|
if (received <= 0) {
|
||||||
|
/* Respond with 500 Internal Server Error */
|
||||||
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to post control value");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
cur_len += received;
|
||||||
|
}
|
||||||
|
buf[total_len] = '\0';
|
||||||
|
|
||||||
|
cJSON *root = cJSON_Parse(buf);
|
||||||
|
char *stratumURL = cJSON_GetObjectItem(root, "stratumURL")->valuestring;
|
||||||
|
char *stratumUser = cJSON_GetObjectItem(root, "stratumUser")->valuestring;
|
||||||
|
uint16_t stratumPort = cJSON_GetObjectItem(root, "stratumPort")->valueint;
|
||||||
|
char *ssid = cJSON_GetObjectItem(root, "ssid")->valuestring;
|
||||||
|
char *wifiPass = cJSON_GetObjectItem(root, "wifiPass")->valuestring;
|
||||||
|
|
||||||
|
|
||||||
|
nvs_config_set_string(NVS_CONFIG_STRATUM_URL, stratumURL);
|
||||||
|
nvs_config_set_string(NVS_CONFIG_STRATUM_USER, stratumUser);
|
||||||
|
nvs_config_set_u16(NVS_CONFIG_STRATUM_PORT, stratumPort);
|
||||||
|
nvs_config_set_string(NVS_CONFIG_WIFI_SSID, ssid);
|
||||||
|
nvs_config_set_string(NVS_CONFIG_WIFI_PASS, wifiPass);
|
||||||
|
|
||||||
|
cJSON_Delete(root);
|
||||||
|
httpd_resp_send_chunk(req, NULL, 0);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static esp_err_t POST_restart(httpd_req_t *req)
|
||||||
|
{
|
||||||
|
esp_restart();
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple handler for getting system handler */
|
||||||
|
static esp_err_t GET_system_info(httpd_req_t *req)
|
||||||
|
{
|
||||||
|
httpd_resp_set_type(req, "application/json");
|
||||||
|
|
||||||
|
// Add CORS headers
|
||||||
|
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||||
|
httpd_resp_set_hdr(req, "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
||||||
|
httpd_resp_set_hdr(req, "Access-Control-Allow-Headers", "Content-Type");
|
||||||
|
httpd_resp_set_hdr(req, "Access-Control-Allow-Credentials", "true");
|
||||||
|
|
||||||
|
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, "fanSpeed", GLOBAL_STATE->POWER_MANAGEMENT_MODULE.fan_speed);
|
||||||
|
cJSON_AddNumberToObject(root, "hashRate", GLOBAL_STATE->SYSTEM_MODULE.current_hashrate);
|
||||||
|
cJSON_AddStringToObject(root, "bestDiff", GLOBAL_STATE->SYSTEM_MODULE.best_diff_string);
|
||||||
|
cJSON_AddNumberToObject(root, "freeHeap", esp_get_free_heap_size());
|
||||||
|
cJSON_AddNumberToObject(root, "coreVoltage", ADC_get_vcore());
|
||||||
|
cJSON_AddStringToObject(root, "ssid", nvs_config_get_string(NVS_CONFIG_WIFI_SSID, CONFIG_ESP_WIFI_SSID));
|
||||||
|
cJSON_AddStringToObject(root, "wifiPass", nvs_config_get_string(NVS_CONFIG_WIFI_PASS, CONFIG_ESP_WIFI_PASSWORD));
|
||||||
|
cJSON_AddStringToObject(root, "wifiStatus", GLOBAL_STATE->SYSTEM_MODULE.wifi_status);
|
||||||
|
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_AddStringToObject(root, "ASICModel", CONFIG_ASIC_MODEL);
|
||||||
|
cJSON_AddStringToObject(root, "stratumURL", nvs_config_get_string(NVS_CONFIG_STRATUM_URL, CONFIG_STRATUM_URL));
|
||||||
|
cJSON_AddNumberToObject(root, "stratumPort", nvs_config_get_u16(NVS_CONFIG_STRATUM_PORT, CONFIG_STRATUM_PORT));
|
||||||
|
cJSON_AddStringToObject(root, "stratumUser", nvs_config_get_string(NVS_CONFIG_STRATUM_USER, CONFIG_STRATUM_USER));
|
||||||
|
|
||||||
|
const char *sys_info = cJSON_Print(root);
|
||||||
|
httpd_resp_sendstr(req, sys_info);
|
||||||
|
free((void *)sys_info);
|
||||||
|
cJSON_Delete(root);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t POST_WWW_update(httpd_req_t *req)
|
||||||
|
{
|
||||||
|
char buf[1000];
|
||||||
|
int remaining = req->content_len;
|
||||||
|
|
||||||
|
const esp_partition_t *www_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, "www");
|
||||||
|
if (www_partition == NULL) {
|
||||||
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "WWW partition not found");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erase the entire www partition before writing
|
||||||
|
ESP_ERROR_CHECK(esp_partition_erase_range(www_partition, 0, www_partition->size));
|
||||||
|
|
||||||
|
while (remaining > 0) {
|
||||||
|
int recv_len = httpd_req_recv(req, buf, MIN(remaining, sizeof(buf)));
|
||||||
|
|
||||||
|
if (recv_len == HTTPD_SOCK_ERR_TIMEOUT) {
|
||||||
|
continue;
|
||||||
|
} else if (recv_len <= 0) {
|
||||||
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Protocol Error");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (esp_partition_write(www_partition, www_partition->size - remaining, (const void *)buf, recv_len) != ESP_OK) {
|
||||||
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Write Error");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining -= recv_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
httpd_resp_sendstr(req, "WWW update complete\n");
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle OTA file upload
|
||||||
|
*/
|
||||||
|
esp_err_t POST_OTA_update(httpd_req_t *req)
|
||||||
|
{
|
||||||
|
char buf[1000];
|
||||||
|
esp_ota_handle_t ota_handle;
|
||||||
|
int remaining = req->content_len;
|
||||||
|
|
||||||
|
const esp_partition_t *ota_partition = esp_ota_get_next_update_partition(NULL);
|
||||||
|
ESP_ERROR_CHECK(esp_ota_begin(ota_partition, OTA_SIZE_UNKNOWN, &ota_handle));
|
||||||
|
|
||||||
|
while (remaining > 0) {
|
||||||
|
int recv_len = httpd_req_recv(req, buf, MIN(remaining, sizeof(buf)));
|
||||||
|
|
||||||
|
// Timeout Error: Just retry
|
||||||
|
if (recv_len == HTTPD_SOCK_ERR_TIMEOUT) {
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Serious Error: Abort OTA
|
||||||
|
} else if (recv_len <= 0) {
|
||||||
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Protocol Error");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Validation / Activation Error");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
httpd_resp_sendstr(req, "Firmware update complete, rebooting now!\n");
|
||||||
|
|
||||||
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
|
esp_restart();
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
esp_err_t start_rest_server(void *pvParameters)
|
||||||
|
{
|
||||||
|
GLOBAL_STATE = (GlobalState*)pvParameters;
|
||||||
|
const char *base_path = "";
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(init_fs());
|
||||||
|
|
||||||
|
REST_CHECK(base_path, "wrong base path", err);
|
||||||
|
rest_server_context_t *rest_context = calloc(1, sizeof(rest_server_context_t));
|
||||||
|
REST_CHECK(rest_context, "No memory for rest context", err);
|
||||||
|
strlcpy(rest_context->base_path, base_path, sizeof(rest_context->base_path));
|
||||||
|
|
||||||
|
httpd_handle_t server = NULL;
|
||||||
|
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||||
|
config.uri_match_fn = httpd_uri_match_wildcard;
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Starting HTTP Server");
|
||||||
|
REST_CHECK(httpd_start(&server, &config) == ESP_OK, "Start server failed", err_start);
|
||||||
|
|
||||||
|
/* URI handler for fetching system info */
|
||||||
|
httpd_uri_t system_info_get_uri = {
|
||||||
|
.uri = "/api/system/info",
|
||||||
|
.method = HTTP_GET,
|
||||||
|
.handler = GET_system_info,
|
||||||
|
.user_ctx = rest_context
|
||||||
|
};
|
||||||
|
httpd_register_uri_handler(server, &system_info_get_uri);
|
||||||
|
|
||||||
|
|
||||||
|
httpd_uri_t system_restart_uri = {
|
||||||
|
.uri = "/api/system/restart",
|
||||||
|
.method = HTTP_POST,
|
||||||
|
.handler = POST_restart,
|
||||||
|
.user_ctx = rest_context
|
||||||
|
};
|
||||||
|
httpd_register_uri_handler(server, &system_restart_uri);
|
||||||
|
|
||||||
|
httpd_uri_t update_system_settings_uri = {
|
||||||
|
.uri = "/api/system",
|
||||||
|
.method = HTTP_PATCH,
|
||||||
|
.handler = PATCH_update_settings,
|
||||||
|
.user_ctx = rest_context
|
||||||
|
};
|
||||||
|
httpd_register_uri_handler(server, &update_system_settings_uri);
|
||||||
|
|
||||||
|
|
||||||
|
httpd_uri_t update_post_ota_firmware = {
|
||||||
|
.uri = "/api/system/OTA",
|
||||||
|
.method = HTTP_POST,
|
||||||
|
.handler = POST_OTA_update,
|
||||||
|
.user_ctx = NULL
|
||||||
|
};
|
||||||
|
httpd_register_uri_handler(server, &update_post_ota_firmware);
|
||||||
|
|
||||||
|
httpd_uri_t update_post_ota_www = {
|
||||||
|
.uri = "/api/system/OTAWWW",
|
||||||
|
.method = HTTP_POST,
|
||||||
|
.handler = POST_WWW_update,
|
||||||
|
.user_ctx = NULL
|
||||||
|
};
|
||||||
|
httpd_register_uri_handler(server, &update_post_ota_www);
|
||||||
|
|
||||||
|
|
||||||
|
/* URI handler for getting web server files */
|
||||||
|
httpd_uri_t common_get_uri = {
|
||||||
|
.uri = "/*",
|
||||||
|
.method = HTTP_GET,
|
||||||
|
.handler = rest_common_get_handler,
|
||||||
|
.user_ctx = rest_context
|
||||||
|
};
|
||||||
|
httpd_register_uri_handler(server, &common_get_uri);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
err_start:
|
||||||
|
free(rest_context);
|
||||||
|
err:
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
7
main/http_server/http_server.h
Normal file
7
main/http_server/http_server.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef HTTP_SERVER_H_
|
||||||
|
#define HTTP_SERVER_H_
|
||||||
|
#include <esp_http_server.h>
|
||||||
|
|
||||||
|
esp_err_t start_rest_server(void *pvParameters);
|
||||||
|
|
||||||
|
#endif
|
6
main/http_server/package-lock.json
generated
Normal file
6
main/http_server/package-lock.json
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "http_server",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {}
|
||||||
|
}
|
35
main/miner.c → main/main.c
Executable file → Normal file
35
main/miner.c → main/main.c
Executable file → Normal file
@ -4,7 +4,7 @@
|
|||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
|
|
||||||
//#include "protocol_examples_common.h"
|
//#include "protocol_examples_common.h"
|
||||||
#include "miner.h"
|
#include "main.h"
|
||||||
|
|
||||||
|
|
||||||
#include "stratum_task.h"
|
#include "stratum_task.h"
|
||||||
@ -14,11 +14,15 @@
|
|||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "asic_result_task.h"
|
#include "asic_result_task.h"
|
||||||
#include "nvs_config.h"
|
#include "nvs_config.h"
|
||||||
|
#include "http_server.h"
|
||||||
|
#include "esp_netif.h"
|
||||||
|
#include "user_input_task.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define ASIC_MODEL CONFIG_ASIC_MODEL
|
#define ASIC_MODEL CONFIG_ASIC_MODEL
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static GlobalState GLOBAL_STATE = {
|
static GlobalState GLOBAL_STATE = {
|
||||||
.extranonce_str = NULL,
|
.extranonce_str = NULL,
|
||||||
.extranonce_2_len = 0,
|
.extranonce_2_len = 0,
|
||||||
@ -64,9 +68,6 @@ void app_main(void)
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Welcome to the bitaxe!");
|
ESP_LOGI(TAG, "Welcome to the bitaxe!");
|
||||||
//wait between 0 and 5 seconds for multiple units
|
//wait between 0 and 5 seconds for multiple units
|
||||||
vTaskDelay(rand() % 5001 / portTICK_PERIOD_MS);
|
vTaskDelay(rand() % 5001 / portTICK_PERIOD_MS);
|
||||||
@ -74,8 +75,6 @@ void app_main(void)
|
|||||||
|
|
||||||
xTaskCreate(SYSTEM_task, "SYSTEM_task", 4096, (void*)&GLOBAL_STATE, 3, NULL);
|
xTaskCreate(SYSTEM_task, "SYSTEM_task", 4096, (void*)&GLOBAL_STATE, 3, NULL);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
|
|
||||||
|
|
||||||
//pull the wifi credentials out of NVS
|
//pull the wifi credentials out of NVS
|
||||||
char * wifi_ssid = nvs_config_get_string(NVS_CONFIG_WIFI_SSID, WIFI_SSID);
|
char * wifi_ssid = nvs_config_get_string(NVS_CONFIG_WIFI_SSID, WIFI_SSID);
|
||||||
char * wifi_pass = nvs_config_get_string(NVS_CONFIG_WIFI_PASS, WIFI_PASS);
|
char * wifi_pass = nvs_config_get_string(NVS_CONFIG_WIFI_PASS, WIFI_PASS);
|
||||||
@ -84,7 +83,9 @@ void app_main(void)
|
|||||||
strncpy(GLOBAL_STATE.SYSTEM_MODULE.ssid, wifi_ssid, 20);
|
strncpy(GLOBAL_STATE.SYSTEM_MODULE.ssid, wifi_ssid, 20);
|
||||||
|
|
||||||
//init and connect to wifi
|
//init and connect to wifi
|
||||||
EventBits_t result_bits = wifi_init_sta(wifi_ssid, wifi_pass);
|
wifi_init(wifi_ssid, wifi_pass);
|
||||||
|
start_rest_server((void*)&GLOBAL_STATE);
|
||||||
|
EventBits_t result_bits = wifi_connect();
|
||||||
|
|
||||||
if (result_bits & WIFI_CONNECTED_BIT) {
|
if (result_bits & WIFI_CONNECTED_BIT) {
|
||||||
ESP_LOGI(TAG, "Connected to SSID: %s", wifi_ssid);
|
ESP_LOGI(TAG, "Connected to SSID: %s", wifi_ssid);
|
||||||
@ -92,12 +93,22 @@ void app_main(void)
|
|||||||
} else if (result_bits & WIFI_FAIL_BIT) {
|
} else if (result_bits & WIFI_FAIL_BIT) {
|
||||||
ESP_LOGE(TAG, "Failed to connect to SSID: %s", wifi_ssid);
|
ESP_LOGE(TAG, "Failed to connect to SSID: %s", wifi_ssid);
|
||||||
strncpy(GLOBAL_STATE.SYSTEM_MODULE.wifi_status, "Failed to connect", 20);
|
strncpy(GLOBAL_STATE.SYSTEM_MODULE.wifi_status, "Failed to connect", 20);
|
||||||
esp_restart(); //this is pretty much fatal, so just restart
|
// User might be trying to configure with AP, just chill here
|
||||||
|
ESP_LOGI(TAG,"Finished, waiting for user input.");
|
||||||
|
while(1){
|
||||||
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(TAG, "UNEXPECTED EVENT");
|
ESP_LOGE(TAG, "UNEXPECTED EVENT");
|
||||||
strncpy(GLOBAL_STATE.SYSTEM_MODULE.wifi_status, "unexpected error", 20);
|
strncpy(GLOBAL_STATE.SYSTEM_MODULE.wifi_status, "unexpected error", 20);
|
||||||
esp_restart(); //this is pretty much fatal, so just restart
|
// User might be trying to configure with AP, just chill here
|
||||||
|
ESP_LOGI(TAG,"Finished, waiting for user input.");
|
||||||
|
while(1){
|
||||||
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wifi_softap_off();
|
||||||
|
|
||||||
free(wifi_ssid);
|
free(wifi_ssid);
|
||||||
free(wifi_pass);
|
free(wifi_pass);
|
||||||
@ -118,6 +129,9 @@ void app_main(void)
|
|||||||
xTaskCreate(ASIC_task, "asic", 8192, (void*)&GLOBAL_STATE, 10, NULL);
|
xTaskCreate(ASIC_task, "asic", 8192, (void*)&GLOBAL_STATE, 10, NULL);
|
||||||
xTaskCreate(ASIC_result_task, "asic result", 8192, (void*)&GLOBAL_STATE, 15, NULL);
|
xTaskCreate(ASIC_result_task, "asic result", 8192, (void*)&GLOBAL_STATE, 15, NULL);
|
||||||
|
|
||||||
|
xTaskCreate(USER_INPUT_task, "user input", 8192, (void*)&GLOBAL_STATE, 5, NULL);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MINER_set_wifi_status(wifi_status_t status, uint16_t retry_count) {
|
void MINER_set_wifi_status(wifi_status_t status, uint16_t retry_count) {
|
||||||
@ -129,4 +143,3 @@ void MINER_set_wifi_status(wifi_status_t status, uint16_t retry_count) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
|||||||
#ifndef MINER_H_
|
#ifndef MAIN_H_
|
||||||
#define MINER_H_
|
#define MAIN_H_
|
||||||
|
|
||||||
#include "connect.h"
|
#include "connect.h"
|
||||||
|
|
||||||
void MINER_set_wifi_status(wifi_status_t status, uint16_t retry_count);
|
void MINER_set_wifi_status(wifi_status_t status, uint16_t retry_count);
|
||||||
|
|
||||||
#endif /* MINER_H_ */
|
#endif /* MAIN_H_ */
|
@ -40,6 +40,29 @@ char * nvs_config_get_string(const char * key, const char * default_value)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nvs_config_set_string(const char * key, const char * value)
|
||||||
|
{
|
||||||
|
|
||||||
|
nvs_handle handle;
|
||||||
|
esp_err_t err;
|
||||||
|
err = nvs_open(NVS_CONFIG_NAMESPACE, NVS_READWRITE, &handle);
|
||||||
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "Could not open nvs");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nvs_set_str(handle, key, value);
|
||||||
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "Could not write nvs key: %s, value: %s", key, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t nvs_config_get_u16(const char * key, const uint16_t default_value)
|
uint16_t nvs_config_get_u16(const char * key, const uint16_t default_value)
|
||||||
{
|
{
|
||||||
nvs_handle handle;
|
nvs_handle handle;
|
||||||
@ -63,3 +86,26 @@ uint16_t nvs_config_get_u16(const char * key, const uint16_t default_value)
|
|||||||
nvs_close(handle);
|
nvs_close(handle);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nvs_config_set_u16(const char * key, const uint16_t value)
|
||||||
|
{
|
||||||
|
|
||||||
|
nvs_handle handle;
|
||||||
|
esp_err_t err;
|
||||||
|
err = nvs_open(NVS_CONFIG_NAMESPACE, NVS_READWRITE, &handle);
|
||||||
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "Could not open nvs");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nvs_set_u16(handle, key, value);
|
||||||
|
if (err != ESP_OK)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "Could not write nvs key: %s, value: %u", key, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_close(handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#define NVS_CONFIG_ASIC_MODEL "asicModel"
|
#define NVS_CONFIG_ASIC_MODEL "asicModel"
|
||||||
|
|
||||||
char * nvs_config_get_string(const char * key, const char * default_value);
|
char * nvs_config_get_string(const char * key, const char * default_value);
|
||||||
|
void nvs_config_set_string(const char * key, const char * default_value);
|
||||||
uint16_t nvs_config_get_u16(const char * key, const uint16_t default_value);
|
uint16_t nvs_config_get_u16(const char * key, const uint16_t default_value);
|
||||||
|
void nvs_config_set_u16(const char * key, const uint16_t value);
|
||||||
|
|
||||||
#endif // MAIN_NVS_CONFIG_H
|
#endif // MAIN_NVS_CONFIG_H
|
||||||
|
@ -32,91 +32,92 @@ static float _fbound(float value, float lower_bound, float upper_bound)
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// void _power_init(PowerManagementModule * power_management){
|
void POWER_MANAGEMENT_task(void *pvParameters)
|
||||||
// power_management->frequency_multiplier = 1;
|
{
|
||||||
// power_management->frequency_value = ASIC_FREQUENCY;
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
void POWER_MANAGEMENT_task(void * pvParameters){
|
|
||||||
|
|
||||||
GlobalState *GLOBAL_STATE = (GlobalState *)pvParameters;
|
GlobalState *GLOBAL_STATE = (GlobalState *)pvParameters;
|
||||||
//bm1397Module * bm1397 = &GLOBAL_STATE->BM1397_MODULE;
|
|
||||||
PowerManagementModule *power_management = &GLOBAL_STATE->POWER_MANAGEMENT_MODULE;
|
PowerManagementModule *power_management = &GLOBAL_STATE->POWER_MANAGEMENT_MODULE;
|
||||||
// _power_init(power_management);
|
|
||||||
|
|
||||||
int last_frequency_increase = 0;
|
int last_frequency_increase = 0;
|
||||||
while(1){
|
while (1)
|
||||||
|
{
|
||||||
|
|
||||||
power_management->voltage = INA260_read_voltage();
|
power_management->voltage = INA260_read_voltage();
|
||||||
power_management->power = INA260_read_power() / 1000;
|
power_management->power = INA260_read_power() / 1000;
|
||||||
power_management->current = INA260_read_current();
|
power_management->current = INA260_read_current();
|
||||||
power_management->fan_speed = EMC2101_get_fan_speed();
|
power_management->fan_speed = EMC2101_get_fan_speed();
|
||||||
|
|
||||||
if(strcmp(ASIC_MODEL, "BM1397") == 0){
|
if (strcmp(ASIC_MODEL, "BM1397") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
power_management->chip_temp = EMC2101_get_chip_temp();
|
power_management->chip_temp = EMC2101_get_chip_temp();
|
||||||
|
|
||||||
// Voltage
|
// Voltage
|
||||||
// We'll throttle between 4.9v and 3.5v
|
// We'll throttle between 4.9v and 3.5v
|
||||||
float voltage_multiplier = _fbound((power_management->voltage - VOLTAGE_MIN_THROTTLE) * (1 / (float)VOLTAGE_RANGE), 0, 1);
|
float voltage_multiplier = _fbound((power_management->voltage - VOLTAGE_MIN_THROTTLE) * (1 / (float)VOLTAGE_RANGE), 0, 1);
|
||||||
|
|
||||||
|
|
||||||
// Temperature
|
// Temperature
|
||||||
float temperature_multiplier = 1;
|
float temperature_multiplier = 1;
|
||||||
float over_temp = -(THROTTLE_TEMP - power_management->chip_temp);
|
float over_temp = -(THROTTLE_TEMP - power_management->chip_temp);
|
||||||
if(over_temp > 0){
|
if (over_temp > 0)
|
||||||
|
{
|
||||||
temperature_multiplier = (THROTTLE_TEMP_RANGE - over_temp) / THROTTLE_TEMP_RANGE;
|
temperature_multiplier = (THROTTLE_TEMP_RANGE - over_temp) / THROTTLE_TEMP_RANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
float lowest_multiplier = 1;
|
float lowest_multiplier = 1;
|
||||||
float multipliers[2] = {voltage_multiplier, temperature_multiplier};
|
float multipliers[2] = {voltage_multiplier, temperature_multiplier};
|
||||||
|
|
||||||
for(int i = 0; i < 2; i++){
|
for (int i = 0; i < 2; i++)
|
||||||
if(multipliers[i] < lowest_multiplier){
|
{
|
||||||
|
if (multipliers[i] < lowest_multiplier)
|
||||||
|
{
|
||||||
lowest_multiplier = multipliers[i];
|
lowest_multiplier = multipliers[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
power_management->frequency_multiplier = lowest_multiplier;
|
power_management->frequency_multiplier = lowest_multiplier;
|
||||||
|
|
||||||
|
|
||||||
float target_frequency = _fbound(power_management->frequency_multiplier * ASIC_FREQUENCY, 0, ASIC_FREQUENCY);
|
float target_frequency = _fbound(power_management->frequency_multiplier * ASIC_FREQUENCY, 0, ASIC_FREQUENCY);
|
||||||
|
|
||||||
if(target_frequency < 50){
|
if (target_frequency < 50)
|
||||||
|
{
|
||||||
// TODO: Turn the chip off
|
// TODO: Turn the chip off
|
||||||
}
|
}
|
||||||
|
|
||||||
// chip is coming back from a low/no voltage event
|
// chip is coming back from a low/no voltage event
|
||||||
if(power_management->frequency_value < 50 && target_frequency > 50){
|
if (power_management->frequency_value < 50 && target_frequency > 50)
|
||||||
|
{
|
||||||
// TODO recover gracefully?
|
// TODO recover gracefully?
|
||||||
esp_restart();
|
esp_restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (power_management->frequency_value > target_frequency)
|
||||||
if(power_management->frequency_value > target_frequency){
|
{
|
||||||
power_management->frequency_value = target_frequency;
|
power_management->frequency_value = target_frequency;
|
||||||
last_frequency_increase = 0;
|
last_frequency_increase = 0;
|
||||||
BM1397_send_hash_frequency(power_management->frequency_value);
|
BM1397_send_hash_frequency(power_management->frequency_value);
|
||||||
ESP_LOGI(TAG, "target %f, Freq %f, Temp %f, Power %f", target_frequency, power_management->frequency_value, power_management->chip_temp, power_management->power);
|
ESP_LOGI(TAG, "target %f, Freq %f, Temp %f, Power %f", target_frequency, power_management->frequency_value, power_management->chip_temp, power_management->power);
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (
|
if (
|
||||||
last_frequency_increase > 120 &&
|
last_frequency_increase > 120 &&
|
||||||
power_management->frequency_value != ASIC_FREQUENCY
|
power_management->frequency_value != ASIC_FREQUENCY)
|
||||||
){
|
{
|
||||||
float add = (target_frequency + power_management->frequency_value) / 2;
|
float add = (target_frequency + power_management->frequency_value) / 2;
|
||||||
power_management->frequency_value += _fbound(add, 2, 20);
|
power_management->frequency_value += _fbound(add, 2, 20);
|
||||||
BM1397_send_hash_frequency(power_management->frequency_value);
|
BM1397_send_hash_frequency(power_management->frequency_value);
|
||||||
ESP_LOGI(TAG, "target %f, Freq %f, Temp %f, Power %f", target_frequency, power_management->frequency_value, power_management->chip_temp, power_management->power);
|
ESP_LOGI(TAG, "target %f, Freq %f, Temp %f, Power %f", target_frequency, power_management->frequency_value, power_management->chip_temp, power_management->power);
|
||||||
last_frequency_increase = 60;
|
last_frequency_increase = 60;
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
last_frequency_increase++;
|
last_frequency_increase++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ESP_LOGI(TAG, "target %f, Freq %f, Volt %f, Power %f", target_frequency, power_management->frequency_value, power_management->voltage, power_management->power);
|
// ESP_LOGI(TAG, "target %f, Freq %f, Volt %f, Power %f", target_frequency, power_management->frequency_value, power_management->voltage, power_management->power);
|
||||||
vTaskDelay(POLL_RATE / portTICK_PERIOD_MS);
|
vTaskDelay(POLL_RATE / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
|
27
main/tasks/user_input_task.c
Normal file
27
main/tasks/user_input_task.c
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "connect.h"
|
||||||
|
|
||||||
|
#define BUTTON_BOOT GPIO_NUM_0
|
||||||
|
|
||||||
|
static const char * TAG = "user_input";
|
||||||
|
static bool button_being_pressed = false;
|
||||||
|
|
||||||
|
void USER_INPUT_task(void * pvParameters){
|
||||||
|
|
||||||
|
gpio_set_direction(BUTTON_BOOT, GPIO_MODE_INPUT);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
if (gpio_get_level(BUTTON_BOOT) == 0 && button_being_pressed == false) { // If button is pressed
|
||||||
|
ESP_LOGI(TAG, "BUTTON PRESSED");
|
||||||
|
button_being_pressed = true;
|
||||||
|
toggle_wifi_softap();
|
||||||
|
} else if (gpio_get_level(BUTTON_BOOT) == 1 && button_being_pressed == true){
|
||||||
|
button_being_pressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(30/portTICK_PERIOD_MS); // Add delay so that current task does not starve idle task and trigger watchdog timer
|
||||||
|
}
|
||||||
|
}
|
7
main/tasks/user_input_task.h
Normal file
7
main/tasks/user_input_task.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef USER_INPUT_TASK_H_
|
||||||
|
#define USER_INPUT_TASK_H_
|
||||||
|
|
||||||
|
|
||||||
|
void USER_INPUT_task(void * pvParameters);
|
||||||
|
|
||||||
|
#endif
|
9
partitions.csv
Normal file
9
partitions.csv
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||||
|
nvs, data, nvs, 0x9000, 0x6000
|
||||||
|
phy_init, data, phy, 0xf000, 0x1000
|
||||||
|
factory, app, factory, 0x10000, 1M
|
||||||
|
www, data, spiffs, 0x110000, 2M
|
||||||
|
ota_0, app, ota_0, 0x310000, 1M
|
||||||
|
ota_1, app, ota_1, 0x410000, 1M
|
||||||
|
otadata, data, ota, 0x510000, 8k
|
|
18
readme.md
18
readme.md
@ -51,6 +51,24 @@ Set following parameters under Example Connection Configuration Options:
|
|||||||
|
|
||||||
For more information about the example_connect() method used here, check out <https://github.com/espressif/esp-idf/blob/master/examples/protocols/README.md>.
|
For more information about the example_connect() method used here, check out <https://github.com/espressif/esp-idf/blob/master/examples/protocols/README.md>.
|
||||||
|
|
||||||
|
## Build website
|
||||||
|
|
||||||
|
To build the website for viewing and OTA updates open the Angular project found in
|
||||||
|
```
|
||||||
|
ESP-Miner\main\http_server\axe-os
|
||||||
|
```
|
||||||
|
|
||||||
|
Then install dependencies and build.
|
||||||
|
|
||||||
|
```
|
||||||
|
npm i
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
When the esp-idf project is built it will bundle the website in www.bin
|
||||||
|
|
||||||
|
|
||||||
## Build and Flash
|
## Build and Flash
|
||||||
|
|
||||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||||
|
0
sdkconfig.ci
Executable file → Normal file
0
sdkconfig.ci
Executable file → Normal file
8
sdkconfig.defaults
Normal file
8
sdkconfig.defaults
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||||
|
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||||
|
CONFIG_PARTITION_TABLE_OFFSET=0x8000
|
||||||
|
CONFIG_PARTITION_TABLE_MD5=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
|
||||||
|
CONFIG_ESP_MAXIMUM_RETRY=3
|
Loading…
x
Reference in New Issue
Block a user