├── .clang-format ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── build.yml ├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── components ├── asic │ ├── CMakeLists.txt │ ├── bm1366.c │ ├── crc.c │ ├── include │ │ ├── bm1366.h │ │ ├── common.h │ │ ├── crc.h │ │ └── serial.h │ └── serial.c ├── connect │ ├── CMakeLists.txt │ ├── Kconfig.projbuild │ ├── connect.c │ └── include │ │ └── connect.h ├── dns_server │ ├── CMakeLists.txt │ ├── dns_server.c │ └── include │ │ └── dns_server.h └── stratum │ ├── CMakeLists.txt │ ├── include │ ├── mining.h │ ├── stratum_api.h │ └── utils.h │ ├── mining.c │ ├── stratum_api.c │ └── utils.c ├── config.cvs.example ├── main ├── CMakeLists.txt ├── EMC2302.c ├── EMC2302.h ├── Kconfig.projbuild ├── TMP1075.c ├── TMP1075.h ├── TPS546.c ├── TPS546.h ├── adc.c ├── adc.h ├── component.mk ├── fonts.c ├── global_state.h ├── history.c ├── history.h ├── http_server │ ├── axe-os │ │ ├── .editorconfig │ │ ├── .gitignore │ │ ├── .vscode │ │ │ ├── extensions.json │ │ │ ├── launch.json │ │ │ └── tasks.json │ │ ├── README.md │ │ ├── angular.json │ │ ├── only-gzip.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── src │ │ │ ├── app │ │ │ │ ├── app-routing.module.ts │ │ │ │ ├── app.component.html │ │ │ │ ├── app.component.scss │ │ │ │ ├── app.component.spec.ts │ │ │ │ ├── app.component.ts │ │ │ │ ├── app.module.ts │ │ │ │ ├── components │ │ │ │ │ ├── edit │ │ │ │ │ │ ├── edit.component.html │ │ │ │ │ │ ├── edit.component.scss │ │ │ │ │ │ ├── edit.component.spec.ts │ │ │ │ │ │ └── edit.component.ts │ │ │ │ │ ├── home │ │ │ │ │ │ ├── home.component.html │ │ │ │ │ │ ├── home.component.scss │ │ │ │ │ │ ├── home.component.spec.ts │ │ │ │ │ │ └── home.component.ts │ │ │ │ │ ├── loading │ │ │ │ │ │ ├── loading.component.html │ │ │ │ │ │ ├── loading.component.scss │ │ │ │ │ │ ├── loading.component.spec.ts │ │ │ │ │ │ └── loading.component.ts │ │ │ │ │ ├── logs │ │ │ │ │ │ ├── logs.component.html │ │ │ │ │ │ ├── logs.component.scss │ │ │ │ │ │ ├── logs.component.spec.ts │ │ │ │ │ │ └── logs.component.ts │ │ │ │ │ ├── settings │ │ │ │ │ │ ├── settings.component.html │ │ │ │ │ │ ├── settings.component.scss │ │ │ │ │ │ ├── settings.component.spec.ts │ │ │ │ │ │ └── settings.component.ts │ │ │ │ │ └── swarm │ │ │ │ │ │ ├── swarm.component.html │ │ │ │ │ │ ├── swarm.component.scss │ │ │ │ │ │ ├── swarm.component.spec.ts │ │ │ │ │ │ └── swarm.component.ts │ │ │ │ ├── layout │ │ │ │ │ ├── api │ │ │ │ │ │ └── menuchangeevent.ts │ │ │ │ │ ├── app.footer.component.html │ │ │ │ │ ├── app.footer.component.ts │ │ │ │ │ ├── app.layout.component.html │ │ │ │ │ ├── app.layout.component.ts │ │ │ │ │ ├── app.layout.module.ts │ │ │ │ │ ├── app.menu.component.html │ │ │ │ │ ├── app.menu.component.ts │ │ │ │ │ ├── app.menu.service.ts │ │ │ │ │ ├── app.menuitem.component.ts │ │ │ │ │ ├── app.sidebar.component.html │ │ │ │ │ ├── app.sidebar.component.ts │ │ │ │ │ ├── app.topbar.component.html │ │ │ │ │ ├── app.topbar.component.ts │ │ │ │ │ ├── service │ │ │ │ │ │ └── app.layout.service.ts │ │ │ │ │ └── styles │ │ │ │ │ │ ├── layout │ │ │ │ │ │ ├── _config.scss │ │ │ │ │ │ ├── _content.scss │ │ │ │ │ │ ├── _footer.scss │ │ │ │ │ │ ├── _main.scss │ │ │ │ │ │ ├── _menu.scss │ │ │ │ │ │ ├── _mixins.scss │ │ │ │ │ │ ├── _preloading.scss │ │ │ │ │ │ ├── _responsive.scss │ │ │ │ │ │ ├── _topbar.scss │ │ │ │ │ │ ├── _typography.scss │ │ │ │ │ │ ├── _utils.scss │ │ │ │ │ │ ├── _variables.scss │ │ │ │ │ │ └── layout.scss │ │ │ │ │ │ └── theme │ │ │ │ │ │ └── vela-blue │ │ │ │ │ │ └── theme.css │ │ │ │ ├── pipes │ │ │ │ │ ├── ansi.pipe.spec.ts │ │ │ │ │ ├── ansi.pipe.ts │ │ │ │ │ ├── date-ago.pipe.spec.ts │ │ │ │ │ ├── date-ago.pipe.ts │ │ │ │ │ ├── hash-suffix.pipe.spec.ts │ │ │ │ │ └── hash-suffix.pipe.ts │ │ │ │ ├── prime-ng.module.ts │ │ │ │ └── services │ │ │ │ │ ├── github-update.service.spec.ts │ │ │ │ │ ├── github-update.service.ts │ │ │ │ │ ├── loading.service.spec.ts │ │ │ │ │ ├── loading.service.ts │ │ │ │ │ ├── system.service.spec.ts │ │ │ │ │ ├── system.service.ts │ │ │ │ │ ├── web-socket.service.spec.ts │ │ │ │ │ └── web-socket.service.ts │ │ │ ├── assets │ │ │ │ └── .gitkeep │ │ │ ├── environments │ │ │ │ ├── environment.prod.ts │ │ │ │ └── environment.ts │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ ├── main.ts │ │ │ ├── models │ │ │ │ ├── IHistory.ts │ │ │ │ ├── ISystemInfo.ts │ │ │ │ └── enum │ │ │ │ │ ├── eASICModel.ts │ │ │ │ │ └── eDeviceModel.ts │ │ │ └── styles.scss │ │ ├── tsconfig.app.json │ │ ├── tsconfig.json │ │ └── tsconfig.spec.json │ ├── http_server.c │ ├── http_server.h │ ├── package-lock.json │ └── recovery_page.h ├── i2c_master.c ├── i2c_master.h ├── main.c ├── main.h ├── nvs_config.c ├── nvs_config.h ├── oled.c ├── oled.h ├── pmbus_commands.h ├── self_test │ ├── self_test.c │ └── self_text.h ├── system.c ├── system.h ├── tasks │ ├── asic_result_task.c │ ├── asic_result_task.h │ ├── asic_task.c │ ├── asic_task.h │ ├── create_jobs_task.c │ ├── create_jobs_task.h │ ├── power_management_task.c │ ├── power_management_task.h │ ├── stratum_task.c │ ├── stratum_task.h │ ├── user_input_task.c │ └── user_input_task.h ├── vcore.c ├── vcore.h ├── work_queue.c └── work_queue.h ├── merge_bin.sh ├── merge_bin_update.sh ├── merge_bin_with_config.sh ├── partitions.csv ├── readme.md ├── sdkconfig.ci └── sdkconfig.defaults /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | UseTab: false 3 | IndentWidth: 4 4 | AllowShortIfStatementsOnASingleLine: false 5 | IndentCaseLabels: false 6 | ColumnLimit: 132 7 | DerivePointerAlignment: false 8 | PointerAlignment: Middle 9 | AllowShortFunctionsOnASingleLine: None 10 | BreakBeforeBraces: Custom 11 | BraceWrapping: 12 | AfterEnum: true 13 | AfterStruct: true 14 | AfterFunction: true 15 | AfterNamespace: true 16 | AfterUnion: true 17 | AfterExternBlock: true 18 | SplitEmptyFunction: false 19 | SpaceAfterCStyleCast: true 20 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM espressif/idf 2 | 3 | ARG DEBIAN_FRONTEND=nointeractive 4 | 5 | RUN apt-get update \ 6 | && apt install -y -q \ 7 | cmake \ 8 | git \ 9 | hwdata \ 10 | libglib2.0-0 \ 11 | libnuma1 \ 12 | libpixman-1-0 \ 13 | linux-tools-virtual \ 14 | && rm -rf /var/lib/apt/lists/* 15 | 16 | RUN update-alternatives --install /usr/local/bin/usbip usbip `ls /usr/lib/linux-tools/*/usbip | tail -n1` 20 17 | 18 | # QEMU 19 | ENV QEMU_REL=esp-develop-20220919 20 | ENV QEMU_SHA256=f6565d3f0d1e463a63a7f81aec94cce62df662bd42fc7606de4b4418ed55f870 21 | ENV QEMU_DIST=qemu-${QEMU_REL}.tar.bz2 22 | ENV QEMU_URL=https://github.com/espressif/qemu/releases/download/${QEMU_REL}/${QEMU_DIST} 23 | 24 | ENV LC_ALL=C.UTF-8 25 | ENV LANG=C.UTF-8 26 | 27 | RUN wget --no-verbose ${QEMU_URL} \ 28 | && echo "${QEMU_SHA256} *${QEMU_DIST}" | sha256sum --check --strict - \ 29 | && tar -xf $QEMU_DIST -C /opt \ 30 | && rm ${QEMU_DIST} 31 | 32 | ENV PATH=/opt/qemu/bin:${PATH} 33 | 34 | RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc 35 | 36 | ENTRYPOINT [ "/opt/esp/entrypoint.sh" ] 37 | 38 | CMD ["/bin/bash"] -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.183.0/containers/ubuntu 3 | { 4 | "name": "ESP-IDF QEMU", 5 | "build": { 6 | "dockerfile": "Dockerfile" 7 | }, 8 | // Add the IDs of extensions you want installed when the container is created. 9 | "extensions": [ 10 | "ms-vscode.cpptools", 11 | "espressif.esp-idf-extension" 12 | ], 13 | "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces,type=bind", 14 | /* the path of workspace folder to be opened after container is running 15 | */ 16 | "workspaceFolder": "/workspaces", 17 | "mounts": [ 18 | "source=extensionCache,target=/root/.vscode-server/extensions,type=volume" 19 | ], 20 | "settings": { 21 | "terminal.integrated.defaultProfile.linux": "bash", 22 | "idf.espIdfPath": "/opt/esp/idf", 23 | "idf.customExtraPaths": "", 24 | "idf.pythonBinPath": "/opt/esp/python_env/idf5.1_py3.8_env/bin/python", 25 | "idf.toolsPath": "/opt/esp", 26 | "idf.gitPath": "/usr/bin/git" 27 | }, 28 | "runArgs": ["--privileged"] 29 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report to track and resolve issues -- support requests will be 4 | deleted 5 | title: '' 6 | labels: '' 7 | assignees: '' 8 | 9 | --- 10 | 11 | Note: Issues are not for customer support, configuration or discussion. For those topics please consult with your HW vendor or the OSMU Discord at: https://osmu.bitaxe.org 12 | 13 | **Describe the bug** 14 | A clear and concise description of what the bug is. 15 | 16 | **To Reproduce** 17 | Steps to reproduce the behavior: 18 | 1. Go to '...' 19 | 2. Click on '....' 20 | 3. Scroll down to '....' 21 | 4. See error 22 | 23 | **Expected behavior** 24 | A clear and concise description of what you expected to happen. 25 | 26 | **Screenshots & Photos** 27 | If applicable, add AxeOS screenshots and/or photos of your Bitaxe to help explain your problem. 28 | 29 | **Hardware (please complete the following information):** 30 | - Bitaxe HW version: [e.g. Hex 303, etc] 31 | - Bitaxe HW vendor: [Where you purchased the Bitaxe, or self-built] 32 | - ESP-Miner FW version: [e.g. 2.1.1, etc] 33 | - Hash Frequency: 34 | - Voltage: 35 | - Pool URL, Port, User: 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build-target 2 | on: [push, pull_request] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Checkout repo 8 | uses: actions/checkout@v4 9 | with: 10 | submodules: 'recursive' 11 | - name: Setup Node.js 12 | uses: actions/setup-node@v3 13 | with: 14 | node-version: '20' 15 | - name: Build web dist 16 | working-directory: ./main/http_server/axe-os 17 | run: | 18 | npm ci 19 | npm run build 20 | - name: esp-idf build 21 | uses: espressif/esp-idf-ci-action@v1 22 | with: 23 | esp_idf_version: v5.1 24 | target: esp32s3 25 | command: GITHUB_ACTIONS="true" idf.py build 26 | path: '.' 27 | - uses: actions/setup-python@v4 28 | with: 29 | python-version: '3.9' 30 | cache: 'pip' # caching pip dependencies 31 | - run: pip install esptool 32 | - name: "Create factory/merged image" 33 | run: "./merge_bin.sh ./esp-miner-merged.bin" 34 | - name: upload esp-miner-merged.bin 35 | uses: actions/upload-artifact@v3 36 | with: 37 | name: esp-miner-factory.bin 38 | path: ./esp-miner-merged.bin 39 | - name: upload esp-miner-multichip.bin 40 | uses: actions/upload-artifact@v3 41 | with: 42 | name: esp-miner-ota.bin 43 | path: ./build/esp-miner-multichip.bin 44 | - name: upload www.bin 45 | uses: actions/upload-artifact@v3 46 | with: 47 | name: www.bin 48 | path: ./build/www.bin 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Configuration files 2 | sdkconfig 3 | sdkconfig.old 4 | dependencies.lock 5 | 6 | # Visual Studio Code 7 | .vscode/* 8 | !.vscode/settings.json 9 | !.vscode/tasks.json 10 | !.vscode/launch.json 11 | !.vscode/extensions.json 12 | .history/* 13 | 14 | # Production folder 15 | build/ 16 | **/build/ 17 | !build/config 18 | build/config/* 19 | !build/config/kconfig_menus.json 20 | !build/config/sdkconfig.json 21 | 22 | # Test folder 23 | test/build/* 24 | 25 | # HTML documentation 26 | html_doc/ 27 | 28 | components/components/* 29 | config.bin 30 | config.cvs 31 | managed_components/* 32 | 33 | # System files 34 | .DS_Store -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "espidf", 6 | "name": "Launch", 7 | "request": "launch" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "idf.flashType": "UART", 3 | "idf.portWin": "COM3", 4 | "idf.adapterTargetName": "esp32s3", 5 | "idf.openOcdConfigs": [ 6 | "interface/ftdi/esp32_devkitj_v1.cfg", 7 | "target/esp32s3.cfg" 8 | ], 9 | "files.associations": { 10 | "freertos.h": "c", 11 | "esp_netif.h": "c", 12 | "esp_http_server.h": "c", 13 | "esp_chip_info.h": "c", 14 | "xtensa_context.h": "c", 15 | "sys.h": "c", 16 | "array": "c", 17 | "string": "c", 18 | "string_view": "c", 19 | "system_error": "c", 20 | "random": "c", 21 | "leak_tracker.h": "c", 22 | "history.h": "c", 23 | "system.h": "c", 24 | "*.tcc": "c" 25 | }, 26 | "editor.formatOnSave": false, 27 | "cSpell.words": [ 28 | "ssid" 29 | ], 30 | "idf.port": "/dev/cu.usbmodem1434301", 31 | "C_Cpp.intelliSenseEngine": "Tag Parser" 32 | } 33 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following lines of boilerplate have to be in your project's CMakeLists 2 | # in this exact order for cmake to work correctly 3 | cmake_minimum_required(VERSION 3.5) 4 | 5 | # (Not part of the boilerplate) 6 | # This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. 7 | # set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) 8 | 9 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 10 | 11 | 12 | project(esp-miner-multichip) 13 | 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := i2c-simple 7 | 8 | include $(IDF_PATH)/make/project.mk 9 | -------------------------------------------------------------------------------- /components/asic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register( 2 | SRCS 3 | "bm1366.c" 4 | "serial.c" 5 | "crc.c" 6 | 7 | INCLUDE_DIRS 8 | "include" 9 | 10 | REQUIRES 11 | "freertos" 12 | "driver" 13 | "stratum" 14 | ) 15 | 16 | 17 | # Include the header files from "main" directory 18 | target_include_directories(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../main") 19 | 20 | # Include the header files from "main/tasks" directory 21 | target_include_directories(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../main/tasks") -------------------------------------------------------------------------------- /components/asic/crc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "bm1366.h" 6 | 7 | /* compute crc5 over given number of bytes */ 8 | // adapted from https://mightydevices.com/index.php/2018/02/reverse-engineering-antminer-s1/ 9 | uint8_t crc5(uint8_t *data, uint8_t len) 10 | { 11 | uint8_t i, j, k, index = 0; 12 | uint8_t crc = CRC5_MASK; 13 | /* registers */ 14 | uint8_t crcin[5] = {1, 1, 1, 1, 1}; 15 | uint8_t crcout[5] = {1, 1, 1, 1, 1}; 16 | uint8_t din = 0; 17 | 18 | len *= 8; 19 | 20 | /* push data bits */ 21 | for (j = 0x80, k = 0, i = 0; i < len; i++) 22 | { 23 | /* input bit */ 24 | din = (data[index] & j) != 0; 25 | /* shift register */ 26 | crcout[0] = crcin[4] ^ din; 27 | crcout[1] = crcin[0]; 28 | crcout[2] = crcin[1] ^ crcin[4] ^ din; 29 | crcout[3] = crcin[2]; 30 | crcout[4] = crcin[3]; 31 | /* next bit */ 32 | j >>= 1, k++; 33 | /* next byte */ 34 | if (k == 8) 35 | j = 0x80, k = 0, index++; 36 | /* apply new shift register value */ 37 | memcpy(crcin, crcout, 5); 38 | // crcin = crcout[0]; 39 | } 40 | 41 | crc = 0; 42 | /* extract bitmask from register */ 43 | if (crcin[4]) 44 | crc |= 0x10; 45 | if (crcin[3]) 46 | crc |= 0x08; 47 | if (crcin[2]) 48 | crc |= 0x04; 49 | if (crcin[1]) 50 | crc |= 0x02; 51 | if (crcin[0]) 52 | crc |= 0x01; 53 | 54 | return crc; 55 | } 56 | 57 | // kindly provided by cgminer 58 | unsigned int crc16_table[256] = { 59 | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 60 | 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 61 | 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 62 | 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 63 | 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 64 | 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 65 | 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 66 | 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 67 | 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 68 | 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 69 | 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 70 | 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 71 | 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 72 | 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 73 | 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 74 | 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 75 | 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 76 | 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 77 | 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 78 | 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 79 | 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 80 | 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 81 | 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 82 | 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 83 | 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 84 | 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 85 | 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 86 | 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 87 | 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 88 | 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 89 | 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 90 | 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0}; 91 | 92 | /* CRC-16/CCITT */ 93 | uint16_t crc16(uint8_t *buffer, uint16_t len) 94 | { 95 | uint16_t crc; 96 | 97 | crc = 0; 98 | while (len-- > 0) 99 | crc = crc16_table[((crc >> 8) ^ (*buffer++)) & 0xFF] ^ (crc << 8); 100 | 101 | return crc; 102 | } 103 | 104 | /* CRC-16/CCITT-FALSE */ 105 | uint16_t crc16_false(uint8_t *buffer, uint16_t len) 106 | { 107 | uint16_t crc; 108 | 109 | crc = 0xffff; 110 | while (len-- > 0) 111 | crc = crc16_table[((crc >> 8) ^ (*buffer++)) & 0xFF] ^ (crc << 8); 112 | 113 | return crc; 114 | } 115 | -------------------------------------------------------------------------------- /components/asic/include/bm1366.h: -------------------------------------------------------------------------------- 1 | #ifndef BM1366_H_ 2 | #define BM1366_H_ 3 | 4 | #include "common.h" 5 | #include "driver/gpio.h" 6 | #include "mining.h" 7 | 8 | #define CRC5_MASK 0x1F 9 | #define BM1366_INITIAL_DIFFICULTY 512 10 | 11 | #define BM1366_SERIALTX_DEBUG false 12 | #define BM1366_SERIALRX_DEBUG false 13 | #define BM1366_DEBUG_WORK false //causes insane amount of debug output 14 | #define BM1366_DEBUG_JOBS false //causes insane amount of debug output 15 | 16 | static const uint64_t BM1366_CORE_COUNT = 112; 17 | static const uint64_t BM1366_SMALL_CORE_COUNT = 894; 18 | 19 | typedef struct 20 | { 21 | float frequency; 22 | } bm1366Module; 23 | 24 | typedef enum 25 | { 26 | JOB_PACKET = 0, 27 | CMD_PACKET = 1, 28 | } packet_type_t; 29 | 30 | typedef enum 31 | { 32 | JOB_RESP = 0, 33 | CMD_RESP = 1, 34 | } response_type_t; 35 | 36 | typedef struct __attribute__((__packed__)) 37 | { 38 | uint8_t job_id; 39 | uint8_t num_midstates; 40 | uint8_t starting_nonce[4]; 41 | uint8_t nbits[4]; 42 | uint8_t ntime[4]; 43 | uint8_t merkle_root[32]; 44 | uint8_t prev_block_hash[32]; 45 | uint8_t version[4]; 46 | } BM1366_job; 47 | 48 | uint8_t BM1366_init(uint64_t frequency, uint16_t asic_count); 49 | 50 | void BM1366_send_init(void); 51 | void BM1366_send_work(void * GLOBAL_STATE, bm_job * next_bm_job); 52 | void BM1366_set_job_difficulty_mask(int); 53 | int BM1366_set_max_baud(void); 54 | int BM1366_set_default_baud(void); 55 | bool BM1366_send_hash_frequency(float frequency); 56 | bool do_frequency_transition(float target_frequency); 57 | task_result * BM1366_proccess_work(void * GLOBAL_STATE); 58 | 59 | #endif /* BM1366_H_ */ -------------------------------------------------------------------------------- /components/asic/include/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H_ 2 | #define COMMON_H_ 3 | 4 | #include 5 | 6 | typedef struct __attribute__((__packed__)) 7 | { 8 | uint8_t job_id; 9 | uint32_t nonce; 10 | uint32_t rolled_version; 11 | int asic_nr; 12 | } task_result; 13 | 14 | static unsigned char _reverse_bits(unsigned char num) 15 | { 16 | unsigned char reversed = 0; 17 | int i; 18 | 19 | for (i = 0; i < 8; i++) { 20 | reversed <<= 1; // Left shift the reversed variable by 1 21 | reversed |= num & 1; // Use bitwise OR to set the rightmost bit of reversed to the current bit of num 22 | num >>= 1; // Right shift num by 1 to get the next bit 23 | } 24 | 25 | return reversed; 26 | } 27 | 28 | static int _largest_power_of_two(int num) 29 | { 30 | int power = 0; 31 | 32 | while (num > 1) { 33 | num = num >> 1; 34 | power++; 35 | } 36 | 37 | return 1 << power; 38 | } 39 | 40 | #endif -------------------------------------------------------------------------------- /components/asic/include/crc.h: -------------------------------------------------------------------------------- 1 | #ifndef CRC_H_ 2 | #define CRC_H_ 3 | 4 | uint8_t crc5(uint8_t *data, uint8_t len); 5 | unsigned short crc16(const unsigned char *buffer, int len); 6 | unsigned short crc16_false(const unsigned char *buffer, int len); 7 | 8 | #endif // PRETTY_H_ -------------------------------------------------------------------------------- /components/asic/include/serial.h: -------------------------------------------------------------------------------- 1 | #ifndef SERIAL_H_ 2 | #define SERIAL_H_ 3 | 4 | #define SERIAL_BUF_SIZE 16 5 | 6 | int SERIAL_send(uint8_t *, int, bool); 7 | void SERIAL_init(void); 8 | void SERIAL_debug_rx(void); 9 | int16_t SERIAL_rx(uint8_t *, uint16_t, uint16_t); 10 | void SERIAL_clear_buffer(void); 11 | void SERIAL_set_baud(int baud); 12 | 13 | #endif /* SERIAL_H_ */ -------------------------------------------------------------------------------- /components/asic/serial.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "freertos/FreeRTOS.h" 5 | #include "freertos/task.h" 6 | 7 | #include "driver/uart.h" 8 | 9 | #include "esp_log.h" 10 | #include "soc/uart_struct.h" 11 | 12 | #include "serial.h" 13 | #include "utils.h" 14 | 15 | #define ECHO_TEST_TXD (17) 16 | #define ECHO_TEST_RXD (18) 17 | #define BUF_SIZE (1024) 18 | 19 | static const char *TAG = "serial"; 20 | 21 | void SERIAL_init(void) 22 | { 23 | ESP_LOGI(TAG, "Initializing serial"); 24 | // Configure UART1 parameters 25 | uart_config_t uart_config = { 26 | .baud_rate = 115200, 27 | .data_bits = UART_DATA_8_BITS, 28 | .parity = UART_PARITY_DISABLE, 29 | .stop_bits = UART_STOP_BITS_1, 30 | .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, 31 | .rx_flow_ctrl_thresh = 122, 32 | }; 33 | // Configure UART1 parameters 34 | uart_param_config(UART_NUM_1, &uart_config); 35 | // Set UART1 pins(TX: IO17, RX: I018) 36 | uart_set_pin(UART_NUM_1, ECHO_TEST_TXD, ECHO_TEST_RXD, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); 37 | 38 | // Install UART driver (we don't need an event queue here) 39 | // tx buffer 0 so the tx time doesn't overlap with the job wait time 40 | // by returning before the job is written 41 | uart_driver_install(UART_NUM_1, BUF_SIZE * 2, BUF_SIZE * 2, 0, NULL, 0); 42 | } 43 | 44 | void SERIAL_set_baud(int baud) 45 | { 46 | ESP_LOGI(TAG, "Changing UART baud to %i", baud); 47 | uart_set_baudrate(UART_NUM_1, baud); 48 | } 49 | 50 | int SERIAL_send(uint8_t *data, int len, bool debug) 51 | { 52 | if (debug) 53 | { 54 | printf("tx: "); 55 | prettyHex((unsigned char *)data, len); 56 | printf("\n"); 57 | } 58 | 59 | return uart_write_bytes(UART_NUM_1, (const char *)data, len); 60 | } 61 | 62 | /// @brief waits for a serial response from the device 63 | /// @param buf buffer to read data into 64 | /// @param buf number of ms to wait before timing out 65 | /// @return number of bytes read, or -1 on error 66 | int16_t SERIAL_rx(uint8_t *buf, uint16_t size, uint16_t timeout_ms) 67 | { 68 | int16_t bytes_read = uart_read_bytes(UART_NUM_1, buf, size, timeout_ms / portTICK_PERIOD_MS); 69 | 70 | #if BM1366_SERIALRX_DEBUG 71 | size_t buff_len = 0; 72 | if (bytes_read > 0) { 73 | uart_get_buffered_data_len(UART_NUM_1, &buff_len); 74 | printf("rx: "); 75 | prettyHex((unsigned char*) buf, bytes_read); 76 | printf(" [%d]\n", buff_len); 77 | } 78 | #endif 79 | 80 | return bytes_read; 81 | } 82 | 83 | void SERIAL_debug_rx(void) 84 | { 85 | int ret; 86 | uint8_t buf[100]; 87 | 88 | ret = SERIAL_rx(buf, 100, 20); 89 | if (ret < 0) 90 | { 91 | fprintf(stderr, "unable to read data\n"); 92 | return; 93 | } 94 | 95 | memset(buf, 0, 100); 96 | } 97 | 98 | void SERIAL_clear_buffer(void) 99 | { 100 | uart_flush(UART_NUM_1); 101 | } 102 | -------------------------------------------------------------------------------- /components/connect/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register( 2 | SRCS 3 | "connect.c" 4 | 5 | INCLUDE_DIRS 6 | "include" 7 | "../../main" 8 | 9 | REQUIRES 10 | "nvs_flash" 11 | "esp_wifi" 12 | "esp_event" 13 | ) -------------------------------------------------------------------------------- /components/connect/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "WiFi Configuration" 2 | 3 | config ESP_WIFI_SSID 4 | string "WiFi SSID" 5 | default "myssid" 6 | help 7 | SSID (network name) for the example to connect to. 8 | 9 | config ESP_WIFI_PASSWORD 10 | string "WiFi Password" 11 | default "mypassword" 12 | help 13 | WiFi password (WPA or WPA2) for the example to use. 14 | 15 | choice ESP_WIFI_SAE_MODE 16 | prompt "WPA3 SAE mode selection" 17 | default ESP_WPA3_SAE_PWE_BOTH 18 | help 19 | Select mode for SAE as Hunt and Peck, H2E or both. 20 | config ESP_WPA3_SAE_PWE_HUNT_AND_PECK 21 | bool "HUNT AND PECK" 22 | config ESP_WPA3_SAE_PWE_HASH_TO_ELEMENT 23 | bool "H2E" 24 | config ESP_WPA3_SAE_PWE_BOTH 25 | bool "BOTH" 26 | endchoice 27 | 28 | config ESP_WIFI_PW_ID 29 | string "PASSWORD IDENTIFIER" 30 | depends on ESP_WPA3_SAE_PWE_HASH_TO_ELEMENT|| ESP_WPA3_SAE_PWE_BOTH 31 | default "" 32 | help 33 | password identifier for SAE H2E 34 | 35 | config ESP_MAXIMUM_RETRY 36 | int "Maximum retry" 37 | default 420 38 | help 39 | Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent. 40 | 41 | choice ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD 42 | prompt "WiFi Scan auth mode threshold" 43 | default ESP_WIFI_AUTH_WPA2_PSK 44 | help 45 | The weakest authmode to accept in the scan mode. 46 | This value defaults to ESP_WIFI_AUTH_WPA2_PSK incase password is present and ESP_WIFI_AUTH_OPEN is used. 47 | Please select ESP_WIFI_AUTH_WEP/ESP_WIFI_AUTH_WPA_PSK incase AP is operating in WEP/WPA mode. 48 | 49 | config ESP_WIFI_AUTH_OPEN 50 | bool "OPEN" 51 | config ESP_WIFI_AUTH_WEP 52 | bool "WEP" 53 | config ESP_WIFI_AUTH_WPA_PSK 54 | bool "WPA PSK" 55 | config ESP_WIFI_AUTH_WPA2_PSK 56 | bool "WPA2 PSK" 57 | config ESP_WIFI_AUTH_WPA_WPA2_PSK 58 | bool "WPA/WPA2 PSK" 59 | config ESP_WIFI_AUTH_WPA3_PSK 60 | bool "WPA3 PSK" 61 | config ESP_WIFI_AUTH_WPA2_WPA3_PSK 62 | bool "WPA2/WPA3 PSK" 63 | config ESP_WIFI_AUTH_WAPI_PSK 64 | bool "WAPI PSK" 65 | endchoice 66 | 67 | endmenu -------------------------------------------------------------------------------- /components/connect/include/connect.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lwip/sys.h" 4 | #include 5 | #include 6 | 7 | #include "freertos/event_groups.h" 8 | 9 | #define WIFI_SSID CONFIG_ESP_WIFI_SSID 10 | #define WIFI_PASS CONFIG_ESP_WIFI_PASSWORD 11 | #define HOSTNAME CONFIG_LWIP_LOCAL_HOSTNAME 12 | 13 | 14 | 15 | /* The event group allows multiple bits for each event, but we only care about two events: 16 | * - we are connected to the AP with an IP 17 | * - we failed to connect after the maximum amount of retries */ 18 | #define WIFI_CONNECTED_BIT BIT0 19 | #define WIFI_FAIL_BIT BIT1 20 | 21 | // enum of wifi statuses 22 | typedef enum 23 | { 24 | WIFI_CONNECTED, 25 | WIFI_DISCONNECTED, 26 | WIFI_CONNECTING, 27 | WIFI_DISCONNECTING, 28 | WIFI_CONNECT_FAILED, 29 | WIFI_RETRYING, 30 | } wifi_status_t; 31 | 32 | void toggle_wifi_softap(void); 33 | void wifi_softap_on(void); 34 | void wifi_softap_off(void); 35 | void wifi_init(const char * wifi_ssid, const char * wifi_pass, const char * hostname); 36 | EventBits_t wifi_connect(void); 37 | void generate_ssid(char * ssid); 38 | -------------------------------------------------------------------------------- /components/dns_server/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register( 2 | SRCS 3 | "dns_server.c" 4 | 5 | INCLUDE_DIRS 6 | "include" 7 | 8 | PRIV_REQUIRES 9 | "esp_netif" 10 | ) 11 | -------------------------------------------------------------------------------- /components/dns_server/include/dns_server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD 3 | * 4 | * SPDX-License-Identifier: Unlicense OR CC0-1.0 5 | */ 6 | 7 | #pragma once 8 | 9 | #ifdef __cplusplus 10 | extern "C" 11 | { 12 | #endif 13 | 14 | #ifndef DNS_SERVER_MAX_ITEMS 15 | #define DNS_SERVER_MAX_ITEMS 1 16 | #endif 17 | 18 | #include "esp_netif.h" 19 | #include "esp_system.h" 20 | 21 | #define DNS_SERVER_CONFIG_SINGLE(queried_name, netif_key) \ 22 | { \ 23 | .num_of_entries = 1, .item = { {.name = queried_name, .if_key = netif_key} } \ 24 | } 25 | 26 | /** 27 | * @brief Definition of one DNS entry: NAME - IP (or the netif whose IP to answer) 28 | * 29 | * @note Please use string literals (or ensure they are valid during dns_server lifetime) as names, since 30 | * we don't take copies of the config values `name` and `if_key` 31 | */ 32 | typedef struct dns_entry_pair 33 | { 34 | const char * name; /** 6 | #include 7 | 8 | #define MAX_MERKLE_BRANCHES 32 9 | #define HASH_SIZE 32 10 | #define COINBASE_SIZE 100 11 | #define COINBASE2_SIZE 128 12 | 13 | typedef enum 14 | { 15 | STRATUM_UNKNOWN, 16 | MINING_NOTIFY, 17 | MINING_SET_DIFFICULTY, 18 | MINING_SET_VERSION_MASK, 19 | STRATUM_RESULT, 20 | STRATUM_RESULT_SETUP, 21 | STRATUM_RESULT_VERSION_MASK, 22 | STRATUM_RESULT_SUBSCRIBE, 23 | CLIENT_RECONNECT 24 | } stratum_method; 25 | 26 | static const int STRATUM_ID_SUBSCRIBE = 1; 27 | static const int STRATUM_ID_CONFIGURE = 2; 28 | 29 | typedef struct 30 | { 31 | char *job_id; 32 | char *prev_block_hash; 33 | char *coinbase_1; 34 | char *coinbase_2; 35 | uint8_t *merkle_branches; 36 | size_t n_merkle_branches; 37 | uint32_t version; 38 | uint32_t version_mask; 39 | uint32_t target; 40 | uint32_t ntime; 41 | uint32_t difficulty; 42 | } mining_notify; 43 | 44 | typedef struct 45 | { 46 | char * extranonce_str; 47 | int extranonce_2_len; 48 | 49 | int64_t message_id; 50 | // Indicates the type of request the message represents. 51 | stratum_method method; 52 | 53 | // mining.notify 54 | int should_abandon_work; 55 | mining_notify *mining_notification; 56 | // mining.set_difficulty 57 | uint32_t new_difficulty; 58 | // mining.set_version_mask 59 | uint32_t version_mask; 60 | // result 61 | bool response_success; 62 | } StratumApiV1Message; 63 | 64 | void STRATUM_V1_reset_uid(); 65 | 66 | void STRATUM_V1_initialize_buffer(); 67 | 68 | char *STRATUM_V1_receive_jsonrpc_line(int sockfd); 69 | 70 | int STRATUM_V1_subscribe(int socket, char * model); 71 | 72 | void STRATUM_V1_parse(StratumApiV1Message *message, const char *stratum_json); 73 | 74 | void STRATUM_V1_free_mining_notify(mining_notify *params); 75 | 76 | int STRATUM_V1_authenticate(int socket, const char *username, const char *pass); 77 | 78 | int STRATUM_V1_configure_version_rolling(int socket, uint32_t * version_mask); 79 | 80 | int STRATUM_V1_suggest_difficulty(int socket, uint32_t difficulty); 81 | 82 | int STRATUM_V1_submit_share(int socket, const char *username, const char *jobid, 83 | const char *extranonce_2, const uint32_t ntime, const uint32_t nonce, 84 | const uint32_t version); 85 | 86 | #endif // STRATUM_API_H -------------------------------------------------------------------------------- /components/stratum/include/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef STRATUM_UTILS_H 2 | #define STRATUM_UTILS_H 3 | 4 | #include 5 | #include 6 | 7 | int hex2char(uint8_t x, char *c); 8 | 9 | size_t bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen); 10 | 11 | uint8_t hex2val(char c); 12 | void flip80bytes(void *dest_p, const void *src_p); 13 | void flip32bytes(void *dest_p, const void *src_p); 14 | 15 | size_t hex2bin(const char *hex, uint8_t *bin, size_t bin_len); 16 | 17 | void print_hex(const uint8_t *b, size_t len, 18 | const size_t in_line, const char *prefix); 19 | 20 | char *double_sha256(const char *hex_string); 21 | 22 | uint8_t *double_sha256_bin(const uint8_t *data, const size_t data_len); 23 | 24 | void single_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t *dest); 25 | void midstate_sha256_bin(const uint8_t *data, const size_t data_len, uint8_t *dest); 26 | 27 | void swap_endian_words(const char *hex, uint8_t *output); 28 | 29 | void reverse_bytes(uint8_t *data, size_t len); 30 | 31 | double le256todouble(const void *target); 32 | 33 | void prettyHex(unsigned char *buf, int len); 34 | 35 | uint32_t flip32(uint32_t val); 36 | 37 | #endif // STRATUM_UTILS_H -------------------------------------------------------------------------------- /config.cvs.example: -------------------------------------------------------------------------------- 1 | key,type,encoding,value 2 | main,namespace,, 3 | hostname,data,string,bitaxe 4 | wifissid,data,string,myssid 5 | wifipass,data,string,mypass 6 | stratumurl,data,string,public-pool.io 7 | stratumport,data,u16,21496 8 | fbstratumurl,data,string,public-pool.io 9 | fbstratumport,data,u16,21496 10 | stratumuser,data,string,bc1qnp980s5fpp8l94p5cvttmtdqy8rvrq74qly2yrfmzkdsntqzlc5qkc4rkq.bitaxe 11 | stratumpass,data,string,x 12 | asicfrequency,data,u16,485 13 | asicvoltage,data,u16,1200 14 | asicmodel,data,string,BM1366 15 | devicemodel,data,string,hex 16 | boardversion,data,string,303 17 | flipscreen,data,u16,1 18 | invertfanpol,data,u16,1 19 | autofanspeed,data,u16,1 20 | fanspeed,data,u16,100 21 | selftest,data,u16,1 22 | overheat_mode,data,u16,0 -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register( 2 | SRCS 3 | "adc.c" 4 | "EMC2302.c" 5 | "fonts.c" 6 | "i2c_master.c" 7 | "main.c" 8 | "nvs_config.c" 9 | "oled.c" 10 | "system.c" 11 | "TMP1075.c" 12 | "TPS546.c" 13 | "vcore.c" 14 | "history.c" 15 | "work_queue.c" 16 | "./http_server/http_server.c" 17 | "./self_test/self_test.c" 18 | "./tasks/stratum_task.c" 19 | "./tasks/create_jobs_task.c" 20 | "./tasks/asic_task.c" 21 | "./tasks/asic_result_task.c" 22 | "./tasks/user_input_task.c" 23 | "./tasks/power_management_task.c" 24 | 25 | INCLUDE_DIRS 26 | "." 27 | "tasks" 28 | "http_server" 29 | "../components/asic/include" 30 | "../components/connect/include" 31 | "../components/dns_server/include" 32 | "../components/stratum/include" 33 | 34 | PRIV_REQUIRES 35 | "app_update" 36 | "driver" 37 | "esp_adc" 38 | "esp_app_format" 39 | "esp_event" 40 | "esp_http_server" 41 | "esp_netif" 42 | "esp_timer" 43 | "esp_wifi" 44 | "esp_psram" 45 | "json" 46 | "nvs_flash" 47 | "spiffs" 48 | "vfs" 49 | ) 50 | 51 | set(WEB_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/http_server/axe-os") 52 | 53 | if("$ENV{GITHUB_ACTIONS}" STREQUAL "true") 54 | message(STATUS "Running on GitHub Actions. Web ui will be prebuilt.") 55 | 56 | spiffs_create_partition_image(www ${WEB_SRC_DIR}/dist/axe-os FLASH_IN_PROJECT) 57 | else() 58 | find_program(NPM_EXECUTABLE npm) 59 | if(NOT NPM_EXECUTABLE AND NOT EXISTS ${WEB_SRC_DIR}/dist) 60 | message(FATAL_ERROR "npm is not found! Please install it to proceed.") 61 | endif() 62 | 63 | ExternalProject_Add( 64 | web_ui_dist 65 | PREFIX ${CMAKE_BINARY_DIR}/web_ui_dist 66 | SOURCE_DIR ${WEB_SRC_DIR} 67 | DOWNLOAD_COMMAND "" 68 | CONFIGURE_COMMAND 69 | ${NPM_EXECUTABLE} i 70 | USES_TERMINAL_BUILD true 71 | BUILD_COMMAND 72 | ${NPM_EXECUTABLE} run build 73 | INSTALL_COMMAND "" 74 | BUILD_ALWAYS OFF 75 | BUILD_IN_SOURCE TRUE 76 | BUILD_BYPRODUCTS 77 | "${WEB_SRC_DIR}/dist/axe-os/index.html" 78 | ) 79 | 80 | add_dependencies(${COMPONENT_LIB} web_ui_dist) 81 | 82 | spiffs_create_partition_image(www ${WEB_SRC_DIR}/dist/axe-os FLASH_IN_PROJECT DEPENDS web_ui_dist) 83 | endif() 84 | -------------------------------------------------------------------------------- /main/EMC2302.c: -------------------------------------------------------------------------------- 1 | #include "driver/i2c.h" 2 | #include "esp_log.h" 3 | #include 4 | 5 | #include "EMC2302.h" 6 | 7 | #define I2C_MASTER_SCL_IO 48 /*!< GPIO number used for I2C master clock */ 8 | #define I2C_MASTER_SDA_IO 47 /*!< GPIO number used for I2C master data */ 9 | #define I2C_MASTER_NUM \ 10 | 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */ 11 | #define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency */ 12 | #define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ 13 | #define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ 14 | #define I2C_MASTER_TIMEOUT_MS 1000 15 | 16 | static const char *TAG = "EMC2302.c"; 17 | 18 | /** 19 | * @brief Read a sequence of I2C bytes 20 | */ 21 | static esp_err_t register_read(uint8_t reg_addr, uint8_t * data, size_t len) 22 | { 23 | return i2c_master_write_read_device(I2C_MASTER_NUM, EMC2302_I2CADDR_DEFAULT, ®_addr, 1, data, len, 24 | I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); 25 | } 26 | 27 | /** 28 | * @brief Write a byte to a I2C register 29 | */ 30 | static esp_err_t register_write_byte(uint8_t reg_addr, uint8_t data) 31 | { 32 | int ret; 33 | uint8_t write_buf[2] = {reg_addr, data}; 34 | 35 | ret = i2c_master_write_to_device(I2C_MASTER_NUM, EMC2302_I2CADDR_DEFAULT, write_buf, sizeof(write_buf), 36 | I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); 37 | 38 | return ret; 39 | } 40 | 41 | // run this first. sets up the PWM polarity register 42 | void EMC2302_init(bool invertPolarity) 43 | { 44 | if (invertPolarity) { 45 | ESP_ERROR_CHECK(register_write_byte(EMC2302_PWM_POLARITY, 0b00011111)); 46 | } 47 | } 48 | 49 | // Sets the fan speed to a given percent 50 | void EMC2302_set_fan_speed(uint8_t devicenum, float percent) 51 | { 52 | uint8_t speed; 53 | uint8_t FAN_SETTING_REG = EMC2302_FAN1_SETTING + (devicenum * 0x10); 54 | 55 | speed = (uint8_t) (255.0 * (1.0f-percent)); 56 | ESP_ERROR_CHECK(register_write_byte(FAN_SETTING_REG, speed)); 57 | } 58 | 59 | float EMC2302_get_external_temp(void) 60 | { 61 | // We don't have temperature on this chip, so fake it 62 | return 0; 63 | } 64 | 65 | uint8_t EMC2302_get_internal_temp(void) 66 | { 67 | // We don't have temperature on this chip, so fake it 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /main/EMC2302.h: -------------------------------------------------------------------------------- 1 | #ifndef EMC2302_H_ 2 | #define EMC2302_H_ 3 | 4 | #include 5 | 6 | #define EMC2302_I2CADDR_DEFAULT 0x2F ///< EMC2302-2 default i2c address 7 | #define EMC2302_1_I2CADDR_DEFAULT 0x2E ///< EMC2302-2 default i2c address 8 | #define EMC2302_WHOAMI 0xFD ///< Chip ID register 9 | #define EMC2302_MANUFACTURER_ID 0xFE ///< Manufacturer ID 10 | #define EMC2302_REVISION 0xFF ///< Chip revision 11 | 12 | #define EMC2302_CONFIG 0x20 ///< configuration register 13 | #define EMC2302_STATUS 0x24 ///< status register 14 | #define EMC2302_STALL_STATUS 0x25 ///< fan stall status 15 | #define EMC2302_SPIN_STATUS 0x26 ///< fan spin status 16 | #define EMC2302_DRIVE_FAIL_STATUS 0x27 ///< drive fail status 17 | #define EMC2302_INT_ENABLE 0x29 ///< interrupt enable register 18 | #define EMC2302_PWM_POLARITY 0x2A ///< PWM polarity config 19 | #define EMC2302_PWM_OUTPUT 0x2B ///< PWM output config 20 | #define EMC2302_PWM_BASEF45 0x2C ///< 21 | #define EMC2302_PWM_BASEF123 ///< 22 | 23 | #define EMC2302_FAN1_SETTING 0x30 ///< Fan 1 setting 24 | #define EMC2302_PWM1_DIVIDE 0x31 ///< PWM 1 divider 25 | #define EMC2302_FAN1_CONFIG1 0x32 ///< Fan 1 configuration 1 register 26 | #define EMC2302_FAN1_CONFIG2 0x33 ///< Fan 1 configuration 2 register 27 | #define EMC2302_GAIN1 0x35 ///< Gain 1 register 28 | #define EMC2302_FAN1_SPINUP_CONFIG 0x36 ///< Fan 1 spinup configuration register 29 | #define EMC2302_FAN1_MAX_STEP 0x37 ///< Fan 1 max step register 30 | #define EMC2302_FAN1_MIN_DRIVE 0x38 ///< Fan 1 minimum drive register 31 | #define EMC2302_FAN1_TACH_COUNT 0x39 ///< Fan 1 valid TACH count 32 | #define EMC2302_FAN1_DRV_FAIL_LOW 0x3A ///< Fan 1 drive fail band low byte 33 | #define EMC2302_FAN1_DRV_FAIL_HIGH 0x3B ///< Fan 1 drive fail band high byte 34 | #define EMC2302_TACH1_TARGET_LSB 0x3C ///< Tach 1 target low byte 35 | #define EMC2302_TACH1_TARGET_MSB 0x3D ///< Tach 1 target high byte 36 | #define EMC2302_TACH1_LSB 0x3E ///< Tach 1 reading low byte 37 | #define EMC2302_TACH1_MSB 0x3F ///< Tach 1 reading high byte 38 | 39 | #define EMC2302_FAN2_SETTING 0x40 ///< Fan 2 setting 40 | #define EMC2302_PWM2_DIVIDE 0x41 ///< PWM 2 divider 41 | #define EMC2302_FAN2_CONFIG1 0x42 ///< Fan 2 configuration 1 register 42 | #define EMC2302_FAN2_CONFIG2 0x43 ///< Fan 2 configuration 2 register 43 | #define EMC2302_GAIN2 0x45 ///< Gain 2 register 44 | #define EMC2302_FAN2_SPINUP_CONFIG 0x46 ///< Fan 2 spinup configuration register 45 | #define EMC2302_FAN2_MAX_STEP 0x47 ///< Fan 2 max step register 46 | #define EMC2302_FAN2_MIN_DRIVE 0x48 ///< Fan 2 minimum drive register 47 | #define EMC2302_FAN2_TACH_COUNT 0x49 ///< Fan 2 valid TACH count 48 | #define EMC2302_FAN2_DRV_FAIL_LOW 0x4A ///< Fan 2 drive fail band low byte 49 | #define EMC2302_FAN2_DRV_FAIL_HIGH 0x4B ///< Fan 2 drive fail band high byte 50 | #define EMC2302_TACH2_TARGET_LSB 0x4C ///< Tach 2 target low byte 51 | #define EMC2302_TACH2_TARGET_MSB 0x4D ///< Tach 2 target high byte 52 | #define EMC2302_TACH2_LSB 0x4E ///< Tach 2 reading low byte 53 | #define EMC2302_TACH2_MSB 0x4F ///< Tach 2 reading high byte 54 | 55 | //#define EMC2302_FAN_RPM_NUMERATOR 3932160 ///< Conversion unit to convert LSBs to fan RPM 56 | #define _TEMP_LSB 0.125 ///< single bit value for internal temperature readings 57 | 58 | /** 59 | * @brief 60 | * 61 | * Allowed values for `setDataRate`. 62 | */ 63 | typedef enum 64 | { 65 | EMC2302_RATE_1_16_HZ, ///< 1_16_HZ 66 | EMC2302_RATE_1_8_HZ, ///< 1_8_HZ 67 | EMC2302_RATE_1_4_HZ, ///< 1_4_HZ 68 | EMC2302_RATE_1_2_HZ, ///< 1_2_HZ 69 | EMC2302_RATE_1_HZ, ///< 1_HZ 70 | EMC2302_RATE_2_HZ, ///< 2_HZ 71 | EMC2302_RATE_4_HZ, ///< 4_HZ 72 | EMC2302_RATE_8_HZ, ///< 8_HZ 73 | EMC2302_RATE_16_HZ, ///< 16_HZ 74 | EMC2302_RATE_32_HZ, ///< 32_HZ 75 | } emc2302_rate_t; 76 | 77 | void EMC2302_init(bool); 78 | void EMC2302_set_fan_speed(uint8_t, float); 79 | uint16_t EMC2302_get_fan_speed(uint8_t); 80 | 81 | float EMC2302_get_external_temp(void); 82 | uint8_t EMC2302_get_internal_temp(void); 83 | 84 | #endif /* EMC2302_H_ */ -------------------------------------------------------------------------------- /main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "Bitaxe Configuration" 2 | config ASIC_VOLTAGE 3 | int "ASIC Core Voltage (mV)" 4 | range 1000 1800 5 | default 1400 6 | help 7 | The core voltage to set the ASIC to. 1200 for BM1366 or 1400 for BM1397 is typical. 8 | 9 | config ASIC_FREQUENCY 10 | int "ASIC Hash Frequency (MHz)" 11 | range 50 800 12 | default 250 13 | help 14 | The BM1397 hash frequency 15 | endmenu 16 | 17 | menu "Stratum Configuration" 18 | 19 | config STRATUM_URL 20 | string "Stratum Address" 21 | default "public-pool.io" 22 | help 23 | The example will connect to this Stratum pool address. 24 | 25 | config STRATUM_PORT 26 | int "Stratum Port" 27 | range 0 65535 28 | default 21496 29 | help 30 | The stratum server port to connect to. 31 | 32 | config FALLBACK_STRATUM_URL 33 | string "Fallback Stratum Address" 34 | default "public-pool.io" 35 | help 36 | The example will connect to this Stratum pool address if the primary fails. 37 | 38 | config FALLBACK_STRATUM_PORT 39 | int "Fallback Stratum Port" 40 | range 0 65535 41 | default 21496 42 | help 43 | The stratum server port to connect to if the primary fails. 44 | 45 | config STRATUM_USER 46 | string "Stratum username" 47 | default "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa.bitaxe" 48 | help 49 | Stratum user to use with pool 50 | 51 | config STRATUM_PW 52 | string "Stratum password" 53 | default "x" 54 | help 55 | Stratum password to use with pool 56 | 57 | config FALLBACK_STRATUM_USER 58 | string "Fallback Stratum username" 59 | default "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa.bitaxe" 60 | help 61 | Fallback Stratum user to use with pool 62 | 63 | config FALLBACK_STRATUM_PW 64 | string "Fallback Stratum password" 65 | default "x" 66 | help 67 | Fallback Stratum password to use with pool 68 | 69 | config STRATUM_DIFFICULTY 70 | int "Stratum default difficulty" 71 | range 0 4294967296 72 | default 1000 73 | help 74 | A starting difficulty to use with the pool. 75 | 76 | endmenu 77 | -------------------------------------------------------------------------------- /main/TMP1075.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "esp_log.h" 3 | #include "i2c_master.h" 4 | 5 | #include "TMP1075.h" 6 | 7 | static const char *TAG = "TMP1075.c"; 8 | 9 | bool TMP1075_installed(int); 10 | uint8_t TMP1075_read_temperature(int); 11 | 12 | bool TMP1075_installed(int device_index) 13 | { 14 | uint8_t data[2]; 15 | esp_err_t result = ESP_OK; 16 | 17 | // read the configuration register 18 | //ESP_LOGI(TAG, "Reading configuration register"); 19 | ESP_ERROR_CHECK(i2c_master_register_read(TMP1075_I2CADDR_DEFAULT + device_index, TMP1075_CONFIG_REG, data, 2)); 20 | //ESP_LOGI(TAG, "Configuration[%d] = %02X %02X", device_index, data[0], data[1]); 21 | 22 | return (result == ESP_OK?true:false); 23 | } 24 | 25 | uint8_t TMP1075_read_temperature(int device_index) 26 | { 27 | uint8_t data[2]; 28 | 29 | ESP_ERROR_CHECK(i2c_master_register_read(TMP1075_I2CADDR_DEFAULT + device_index, TMP1075_TEMP_REG, data, 2)); 30 | //ESP_LOGI(TAG, "Raw Temperature = %02X %02X", data[0], data[1]); 31 | //ESP_LOGI(TAG, "Temperature[%d] = %d", device_index, data[0]); 32 | return data[0]; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /main/TMP1075.h: -------------------------------------------------------------------------------- 1 | #ifndef TMP1075_H_ 2 | #define TMP1075_H_ 3 | 4 | #define TMP1075_I2CADDR_DEFAULT 0x4A ///< TMP1075 i2c address 5 | #define TMP1075_TEMP_REG 0x00 ///< Temperature register 6 | #define TMP1075_CONFIG_REG 0x01 ///< Configuration register 7 | #define TMP1075_LOW_LIMIT 0x02 ///< Low limit register 8 | #define TMP1075_HIGH_LIMIT 0x03 ///< High limit register 9 | #define TMP1075_DEVICE_ID 0x0F ///< Device ID register 10 | 11 | bool TMP1075_installed(int); 12 | uint8_t TMP1075_read_temperature(int); 13 | 14 | #endif /* TMP1075_H_ */ 15 | -------------------------------------------------------------------------------- /main/TPS546.h: -------------------------------------------------------------------------------- 1 | #ifndef TPS546_H_ 2 | #define TPS546_H_ 3 | 4 | #define TPS546_I2CADDR 0x24 //< TPS546 i2c address 5 | #define TPS546_MANUFACTURER_ID 0xFE //< Manufacturer ID 6 | #define TPS546_REVISION 0xFF //< Chip revision 7 | 8 | /*-------------------------*/ 9 | /* These are the inital values for the voltage regulator configuration */ 10 | /* when the config revision stored in the TPS546 doesn't match, these values are used */ 11 | 12 | 13 | #define TPS546_INIT_ON_OFF_CONFIG 0x18 /* use ON_OFF command to control power */ 14 | #define OPERATION_OFF 0x00 15 | #define OPERATION_ON 0x80 16 | 17 | #define TPS546_INIT_FREQUENCY 650 /* KHz */ 18 | 19 | typedef struct 20 | { 21 | /* vin voltage */ 22 | float TPS546_INIT_VIN_ON; /* V */ 23 | float TPS546_INIT_VIN_OFF; /* V */ 24 | float TPS546_INIT_VIN_UV_WARN_LIMIT; /* V */ 25 | float TPS546_INIT_VIN_OV_FAULT_LIMIT; /* V */ 26 | /* vout voltage */ 27 | float TPS546_INIT_SCALE_LOOP; /* Voltage Scale factor */ 28 | float TPS546_INIT_VOUT_MIN; /* V */ 29 | float TPS546_INIT_VOUT_MAX; /* V */ 30 | float TPS546_INIT_VOUT_COMMAND; /* V absolute value */ 31 | } TPS546_CONFIG; 32 | 33 | /* vin voltage general */ 34 | #define TPS546_INIT_VIN_OV_FAULT_RESPONSE 0xB7 /* retry 6 times */ 35 | 36 | /* vout voltage general */ 37 | #define TPS546_INIT_VOUT_OV_FAULT_LIMIT 1.25 /* %/100 above VOUT_COMMAND */ 38 | #define TPS546_INIT_VOUT_OV_WARN_LIMIT 1.1 /* %/100 above VOUT_COMMAND */ 39 | #define TPS546_INIT_VOUT_MARGIN_HIGH 1.1 /* %/100 above VOUT */ 40 | #define TPS546_INIT_VOUT_MARGIN_LOW 0.90 /* %/100 below VOUT */ 41 | #define TPS546_INIT_VOUT_UV_WARN_LIMIT 0.90 /* %/100 below VOUT_COMMAND */ 42 | #define TPS546_INIT_VOUT_UV_FAULT_LIMIT 0.75 /* %/100 below VOUT_COMMAND */ 43 | 44 | /* iout current */ 45 | #define TPS546_INIT_IOUT_OC_WARN_LIMIT 25.00 /* A */ 46 | #define TPS546_INIT_IOUT_OC_FAULT_LIMIT 30.00 /* A */ 47 | 48 | #define TPS546_INIT_IOUT_OC_FAULT_RESPONSE 0xC0 /* ovecurrent -> shut down, no retries */ 49 | // #define TPS546_INIT_IOUT_OC_FAULT_RESPONSE 0x00 /* ovecurrent -> keep running without interruption */ 50 | 51 | /* temperature */ 52 | #define TPS546_INIT_OT_WARN_LIMIT 105 /* degrees C */ 53 | #define TPS546_INIT_OT_FAULT_LIMIT 145 /* degrees C */ 54 | #define TPS546_INIT_OT_FAULT_RESPONSE 0xFF /* wait for cooling, and retry */ 55 | 56 | /* timing */ 57 | #define TPS546_INIT_TON_DELAY 0 58 | #define TPS546_INIT_TON_RISE 3 59 | #define TPS546_INIT_TON_MAX_FAULT_LIMIT 0 60 | #define TPS546_INIT_TON_MAX_FAULT_RESPONSE 0x3B 61 | #define TPS546_INIT_TOFF_DELAY 0 62 | #define TPS546_INIT_TOFF_FALL 0 63 | 64 | #define INIT_STACK_CONFIG 0x0000 65 | #define INIT_SYNC_CONFIG 0x0010 66 | #define INIT_PIN_DETECT_OVERRIDE 0x0000 67 | 68 | /*-------------------------*/ 69 | 70 | /* PMBUS_ON_OFF_CONFIG initialization values */ 71 | #define ON_OFF_CONFIG_PU 0x10 // turn on PU bit 72 | #define ON_OFF_CONFIG_CMD 0x08 // turn on CMD bit 73 | #define ON_OFF_CONFIG_CP 0x00 // turn off CP bit 74 | #define ON_OFF_CONFIG_POLARITY 0x00 // turn off POLARITY bit 75 | #define ON_OFF_CONFIG_DELAY 0x00 // turn off DELAY bit 76 | 77 | #include "global_state.h" 78 | 79 | /* public functions */ 80 | int TPS546_init(TPS546_CONFIG config); 81 | void TPS546_read_mfr_info(uint8_t *); 82 | void TPS546_set_mfr_info(void); 83 | void TPS546_write_entire_config(); 84 | int TPS546_get_frequency(void); 85 | void TPS546_set_frequency(int); 86 | int TPS546_get_temperature(void); 87 | float TPS546_get_vin(void); 88 | float TPS546_get_iout(void); 89 | float TPS546_get_vout(void); 90 | void TPS546_set_vout(float volts); 91 | void TPS546_show_voltage_settings(void); 92 | 93 | #endif /* TPS546_H_ */ 94 | -------------------------------------------------------------------------------- /main/adc.c: -------------------------------------------------------------------------------- 1 | #include "driver/adc.h" 2 | #include "esp_adc_cal.h" 3 | 4 | // static const char *TAG = "adc.c"; 5 | static esp_adc_cal_characteristics_t adc1_chars; 6 | 7 | // Sets up the ADC to read Vcore. Run this before ADC_get_vcore() 8 | void ADC_init(void) 9 | { 10 | adc1_config_channel_atten(ADC1_CHANNEL_1, ADC_ATTEN_DB_11); 11 | esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_DEFAULT, 0, &adc1_chars); 12 | } 13 | 14 | // returns the ADC voltage in mV 15 | uint16_t ADC_get_vcore(void) 16 | { 17 | adc1_config_width(ADC_WIDTH_BIT_DEFAULT); 18 | return esp_adc_cal_raw_to_voltage(adc1_get_raw(ADC1_CHANNEL_1), &adc1_chars); 19 | } -------------------------------------------------------------------------------- /main/adc.h: -------------------------------------------------------------------------------- 1 | #ifndef ADC_H_ 2 | #define ADC_H_ 3 | 4 | void ADC_init(void); 5 | uint16_t ADC_get_vcore(void); 6 | 7 | #endif /* ADC_H_ */ -------------------------------------------------------------------------------- /main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main Makefile. This is basically the same as a component makefile . 3 | # 4 | -------------------------------------------------------------------------------- /main/fonts.c: -------------------------------------------------------------------------------- 1 | 2 | // 5x7 font (in 6x8 cell) 3 | unsigned char ucSmallFont[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x45, 0x51, 0x45, 0x3e, 0x00, 0x3e, 0x6b, 0x6f, 4 | 0x6b, 0x3e, 0x00, 0x1c, 0x3e, 0x7c, 0x3e, 0x1c, 0x00, 0x18, 0x3c, 0x7e, 0x3c, 0x18, 0x00, 0x30, 5 | 0x36, 0x7f, 0x36, 0x30, 0x00, 0x18, 0x5c, 0x7e, 0x5c, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 6 | 0x00, 0xff, 0xe7, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x24, 0x24, 0x3c, 0x00, 0x00, 0xc3, 0xdb, 0xdb, 7 | 0xc3, 0xff, 0x00, 0x30, 0x48, 0x4a, 0x36, 0x0e, 0x00, 0x06, 0x29, 0x79, 0x29, 0x06, 0x00, 0x60, 8 | 0x70, 0x3f, 0x02, 0x04, 0x00, 0x60, 0x7e, 0x0a, 0x35, 0x3f, 0x00, 0x2a, 0x1c, 0x36, 0x1c, 0x2a, 9 | 0x00, 0x00, 0x7f, 0x3e, 0x1c, 0x08, 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x00, 0x00, 0x14, 0x36, 0x7f, 10 | 0x36, 0x14, 0x00, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x00, 0x06, 0x09, 0x7f, 0x01, 0x7f, 0x00, 0x22, 11 | 0x4d, 0x55, 0x59, 0x22, 0x00, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x14, 0xb6, 0xff, 0xb6, 0x14, 12 | 0x00, 0x04, 0x06, 0x7f, 0x06, 0x04, 0x00, 0x10, 0x30, 0x7f, 0x30, 0x10, 0x00, 0x08, 0x08, 0x3e, 13 | 0x1c, 0x08, 0x00, 0x08, 0x1c, 0x3e, 0x08, 0x08, 0x00, 0x78, 0x40, 0x40, 0x40, 0x40, 0x00, 0x08, 14 | 0x3e, 0x08, 0x3e, 0x08, 0x00, 0x30, 0x3c, 0x3f, 0x3c, 0x30, 0x00, 0x03, 0x0f, 0x3f, 0x0f, 0x03, 15 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x5f, 0x06, 0x00, 0x00, 0x07, 0x03, 0x00, 16 | 0x07, 0x03, 0x00, 0x24, 0x7e, 0x24, 0x7e, 0x24, 0x00, 0x24, 0x2b, 0x6a, 0x12, 0x00, 0x00, 0x63, 17 | 0x13, 0x08, 0x64, 0x63, 0x00, 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 18 | 0x00, 0x00, 0x3e, 0x41, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x08, 0x3e, 0x1c, 19 | 0x3e, 0x08, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0xe0, 0x60, 0x00, 0x00, 0x00, 0x08, 20 | 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 21 | 0x00, 0x3e, 0x51, 0x49, 0x45, 0x3e, 0x00, 0x00, 0x42, 0x7f, 0x40, 0x00, 0x00, 0x62, 0x51, 0x49, 22 | 0x49, 0x46, 0x00, 0x22, 0x49, 0x49, 0x49, 0x36, 0x00, 0x18, 0x14, 0x12, 0x7f, 0x10, 0x00, 0x2f, 23 | 0x49, 0x49, 0x49, 0x31, 0x00, 0x3c, 0x4a, 0x49, 0x49, 0x30, 0x00, 0x01, 0x71, 0x09, 0x05, 0x03, 24 | 0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x06, 0x49, 0x49, 0x29, 0x1e, 0x00, 0x00, 0x6c, 0x6c, 25 | 0x00, 0x00, 0x00, 0x00, 0xec, 0x6c, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, 0x24, 26 | 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x41, 0x22, 0x14, 0x08, 0x00, 0x02, 0x01, 0x59, 0x09, 0x06, 27 | 0x00, 0x3e, 0x41, 0x5d, 0x55, 0x1e, 0x00, 0x7e, 0x11, 0x11, 0x11, 0x7e, 0x00, 0x7f, 0x49, 0x49, 28 | 0x49, 0x36, 0x00, 0x3e, 0x41, 0x41, 0x41, 0x22, 0x00, 0x7f, 0x41, 0x41, 0x41, 0x3e, 0x00, 0x7f, 29 | 0x49, 0x49, 0x49, 0x41, 0x00, 0x7f, 0x09, 0x09, 0x09, 0x01, 0x00, 0x3e, 0x41, 0x49, 0x49, 0x7a, 30 | 0x00, 0x7f, 0x08, 0x08, 0x08, 0x7f, 0x00, 0x00, 0x41, 0x7f, 0x41, 0x00, 0x00, 0x30, 0x40, 0x40, 31 | 0x40, 0x3f, 0x00, 0x7f, 0x08, 0x14, 0x22, 0x41, 0x00, 0x7f, 0x40, 0x40, 0x40, 0x40, 0x00, 0x7f, 32 | 0x02, 0x04, 0x02, 0x7f, 0x00, 0x7f, 0x02, 0x04, 0x08, 0x7f, 0x00, 0x3e, 0x41, 0x41, 0x41, 0x3e, 33 | 0x00, 0x7f, 0x09, 0x09, 0x09, 0x06, 0x00, 0x3e, 0x41, 0x51, 0x21, 0x5e, 0x00, 0x7f, 0x09, 0x09, 34 | 0x19, 0x66, 0x00, 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, 0x01, 0x01, 0x7f, 0x01, 0x01, 0x00, 0x3f, 35 | 0x40, 0x40, 0x40, 0x3f, 0x00, 0x1f, 0x20, 0x40, 0x20, 0x1f, 0x00, 0x3f, 0x40, 0x3c, 0x40, 0x3f, 36 | 0x00, 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, 0x07, 0x08, 0x70, 0x08, 0x07, 0x00, 0x71, 0x49, 0x45, 37 | 0x43, 0x00, 0x00, 0x00, 0x7f, 0x41, 0x41, 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 38 | 0x41, 0x41, 0x7f, 0x00, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 39 | 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x20, 0x54, 0x54, 0x54, 0x78, 0x00, 0x7f, 0x44, 0x44, 40 | 0x44, 0x38, 0x00, 0x38, 0x44, 0x44, 0x44, 0x28, 0x00, 0x38, 0x44, 0x44, 0x44, 0x7f, 0x00, 0x38, 41 | 0x54, 0x54, 0x54, 0x08, 0x00, 0x08, 0x7e, 0x09, 0x09, 0x00, 0x00, 0x18, 0xa4, 0xa4, 0xa4, 0x7c, 42 | 0x00, 0x7f, 0x04, 0x04, 0x78, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x40, 0x00, 0x00, 0x40, 0x80, 0x84, 43 | 0x7d, 0x00, 0x00, 0x7f, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x40, 0x00, 0x00, 0x7c, 44 | 0x04, 0x18, 0x04, 0x78, 0x00, 0x7c, 0x04, 0x04, 0x78, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 45 | 0x00, 0xfc, 0x44, 0x44, 0x44, 0x38, 0x00, 0x38, 0x44, 0x44, 0x44, 0xfc, 0x00, 0x44, 0x78, 0x44, 46 | 0x04, 0x08, 0x00, 0x08, 0x54, 0x54, 0x54, 0x20, 0x00, 0x04, 0x3e, 0x44, 0x24, 0x00, 0x00, 0x3c, 47 | 0x40, 0x20, 0x7c, 0x00, 0x00, 0x1c, 0x20, 0x40, 0x20, 0x1c, 0x00, 0x3c, 0x60, 0x30, 0x60, 0x3c, 48 | 0x00, 0x6c, 0x10, 0x10, 0x6c, 0x00, 0x00, 0x9c, 0xa0, 0x60, 0x3c, 0x00, 0x00, 0x64, 0x54, 0x54, 49 | 0x4c, 0x00, 0x00, 0x08, 0x3e, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 50 | 0x41, 0x41, 0x3e, 0x08, 0x00, 0x02, 0x01, 0x02, 0x01, 0x00, 0x00, 0x3c, 0x26, 0x23, 0x26, 0x3c}; 51 | -------------------------------------------------------------------------------- /main/global_state.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBAL_STATE_H_ 2 | #define GLOBAL_STATE_H_ 3 | 4 | #include 5 | #include 6 | #include "asic_task.h" 7 | #include "bm1366.h" 8 | #include "common.h" 9 | #include "power_management_task.h" 10 | #include "serial.h" 11 | #include "stratum_api.h" 12 | #include "work_queue.h" 13 | 14 | #define STRATUM_USER CONFIG_STRATUM_USER 15 | #define FALLBACK_STRATUM_USER CONFIG_FALLBACK_STRATUM_USER 16 | 17 | #define HISTORY_LENGTH 512 18 | #define DIFF_STRING_SIZE 10 19 | 20 | typedef enum 21 | { 22 | DEVICE_UNKNOWN = -1, 23 | DEVICE_HEX 24 | } DeviceModel; 25 | 26 | typedef enum 27 | { 28 | ASIC_UNKNOWN = -1, 29 | ASIC_BM1366 30 | } AsicModel; 31 | 32 | typedef struct 33 | { 34 | uint8_t (*init_fn)(uint64_t, uint16_t); 35 | task_result * (*receive_result_fn)(void * GLOBAL_STATE); 36 | int (*set_max_baud_fn)(void); 37 | void (*set_difficulty_mask_fn)(int); 38 | void (*send_work_fn)(void * GLOBAL_STATE, bm_job * next_bm_job); 39 | bool (*send_hash_frequency_fn)(float); 40 | } AsicFunctions; 41 | 42 | typedef struct 43 | { 44 | int historical_hashrate_rolling_index; 45 | uint64_t historical_hashrate_time_stamps[HISTORY_LENGTH]; 46 | double historical_hashrate[HISTORY_LENGTH]; 47 | double current_hashrate; 48 | double current_hashrate_10m; 49 | double current_hashrate_1h; 50 | double current_hashrate_1d; 51 | int64_t start_time; 52 | uint64_t shares_accepted; 53 | uint64_t shares_rejected; 54 | int screen_page; 55 | char oled_buf[20]; 56 | uint64_t best_nonce_diff; 57 | char best_diff_string[DIFF_STRING_SIZE]; 58 | uint64_t best_session_nonce_diff; 59 | char best_session_diff_string[DIFF_STRING_SIZE]; 60 | bool FOUND_BLOCK; 61 | bool startup_done; 62 | char ssid[32]; 63 | char wifi_status[20]; 64 | char * pool_url; 65 | char * fallback_pool_url; 66 | uint16_t pool_port; 67 | uint16_t fallback_pool_port; 68 | bool is_using_fallback; 69 | uint16_t overheat_mode; 70 | 71 | uint32_t lastClockSync; 72 | } SystemModule; 73 | 74 | typedef struct 75 | { 76 | DeviceModel device_model; 77 | char * device_model_str; 78 | int board_version; 79 | AsicModel asic_model; 80 | char * asic_model_str; 81 | uint16_t asic_count; 82 | uint16_t voltage_domain; 83 | AsicFunctions ASIC_functions; 84 | double asic_job_frequency_ms; 85 | uint32_t initial_ASIC_difficulty; 86 | 87 | work_queue stratum_queue; 88 | work_queue ASIC_jobs_queue; 89 | 90 | SystemModule SYSTEM_MODULE; 91 | AsicTaskModule ASIC_TASK_MODULE; 92 | PowerManagementModule POWER_MANAGEMENT_MODULE; 93 | 94 | char * extranonce_str; 95 | int extranonce_2_len; 96 | int abandon_work; 97 | 98 | uint8_t * valid_jobs; 99 | pthread_mutex_t valid_jobs_lock; 100 | 101 | uint32_t stratum_difficulty; 102 | uint32_t version_mask; 103 | 104 | int sock; 105 | 106 | } GlobalState; 107 | 108 | #endif /* GLOBAL_STATE_H_ */ 109 | -------------------------------------------------------------------------------- /main/history.h: -------------------------------------------------------------------------------- 1 | #include "esp_psram.h" 2 | #pragma once 3 | 4 | // 128k samples should be enough^^ 5 | // must be power of two 6 | #define HISTORY_MAX_SAMPLES 0x20000 7 | 8 | typedef struct { 9 | int first_sample; 10 | int last_sample; 11 | uint64_t timespan; 12 | uint64_t diffsum; 13 | double avg; 14 | double avg_gh; 15 | uint64_t timestamp; 16 | bool preliminary; 17 | } avg_t; 18 | 19 | typedef struct { 20 | int num_samples; 21 | uint32_t shares[HISTORY_MAX_SAMPLES]; // pool diff is always 32bit int 22 | uint64_t timestamps[HISTORY_MAX_SAMPLES]; // in ms 23 | float hashrate_10m[HISTORY_MAX_SAMPLES]; 24 | float hashrate_1h[HISTORY_MAX_SAMPLES]; 25 | float hashrate_1d[HISTORY_MAX_SAMPLES]; 26 | } psram_t; 27 | 28 | typedef struct { 29 | float *hashrate_10m; 30 | float *hashrate_1h; 31 | float *hashrate_1d; 32 | uint64_t *timestamps; // in ms 33 | } history_t; 34 | 35 | 36 | void *stats_task(void *pvParameters); 37 | 38 | bool history_init(void); 39 | void history_push_share(uint32_t diff, uint64_t timestamp); 40 | int history_search_nearest_timestamp(uint64_t timestamp); 41 | 42 | uint64_t history_get_timestamp_sample(int index); 43 | float history_get_hashrate_10m_sample(int index); 44 | float history_get_hashrate_1h_sample(int index); 45 | float history_get_hashrate_1d_sample(int index); 46 | double history_get_current_10m(void); 47 | double history_get_current_1h(void); 48 | double history_get_current_1d(void); 49 | uint64_t history_get_current_timestamp(void); 50 | void history_lock(void); 51 | void history_unlock(void); 52 | bool is_history_available(void); 53 | void history_get_timestamps(uint64_t *first, uint64_t *last, int *num_samples); -------------------------------------------------------------------------------- /main/http_server/axe-os/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /main/http_server/axe-os/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | # !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /main/http_server/axe-os/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /main/http_server/axe-os/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "chrome", 8 | "request": "launch", 9 | "url": "http://localhost:4200/", 10 | "sourceMaps": true 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /main/http_server/axe-os/README.md: -------------------------------------------------------------------------------- 1 | # AxeOS 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 16.1.3. 4 | 5 | ## Development server 6 | 7 | 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. 8 | 9 | ## Code scaffolding 10 | 11 | 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`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | 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. 24 | 25 | ## Further help 26 | 27 | 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. 28 | -------------------------------------------------------------------------------- /main/http_server/axe-os/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "axe-os": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser", 19 | "options": { 20 | "outputPath": "dist/axe-os", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": [ 24 | "zone.js" 25 | ], 26 | "tsConfig": "tsconfig.app.json", 27 | "inlineStyleLanguage": "scss", 28 | "assets": [ 29 | "src/favicon.ico", 30 | "src/assets" 31 | ], 32 | "styles": [ 33 | "src/styles.scss", 34 | "node_modules/ngx-toastr/toastr.css" 35 | ], 36 | "scripts": [] 37 | }, 38 | "configurations": { 39 | "production": { 40 | "fileReplacements": [ 41 | { 42 | "replace": "src/environments/environment.ts", 43 | "with": "src/environments/environment.prod.ts" 44 | } 45 | ], 46 | "budgets": [ 47 | { 48 | "type": "initial", 49 | "maximumWarning": "2mb", 50 | "maximumError": "3mb" 51 | }, 52 | { 53 | "type": "anyComponentStyle", 54 | "maximumWarning": "2kb", 55 | "maximumError": "4kb" 56 | } 57 | ], 58 | "outputHashing": "all" 59 | }, 60 | "development": { 61 | "buildOptimizer": false, 62 | "optimization": false, 63 | "vendorChunk": true, 64 | "extractLicenses": false, 65 | "sourceMap": true, 66 | "namedChunks": true 67 | } 68 | }, 69 | "defaultConfiguration": "production" 70 | }, 71 | "serve": { 72 | "builder": "@angular-devkit/build-angular:dev-server", 73 | "configurations": { 74 | "production": { 75 | "browserTarget": "axe-os:build:production" 76 | }, 77 | "development": { 78 | "browserTarget": "axe-os:build:development" 79 | } 80 | }, 81 | "defaultConfiguration": "development" 82 | }, 83 | "extract-i18n": { 84 | "builder": "@angular-devkit/build-angular:extract-i18n", 85 | "options": { 86 | "browserTarget": "axe-os:build" 87 | } 88 | }, 89 | "test": { 90 | "builder": "@angular-devkit/build-angular:karma", 91 | "options": { 92 | "polyfills": [ 93 | "zone.js", 94 | "zone.js/testing" 95 | ], 96 | "tsConfig": "tsconfig.spec.json", 97 | "inlineStyleLanguage": "scss", 98 | "assets": [ 99 | "src/favicon.ico", 100 | "src/assets" 101 | ], 102 | "styles": [ 103 | "src/styles.scss" 104 | ], 105 | "scripts": [] 106 | } 107 | } 108 | } 109 | } 110 | }, 111 | "cli": { 112 | "analytics": false 113 | } 114 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/only-gzip.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const directory = './dist/axe-os'; 5 | 6 | fs.readdir(directory, (err, files) => { 7 | if (err) throw err; 8 | 9 | for (const file of files) { 10 | if (!file.endsWith('.gz')) { 11 | fs.unlink(path.join(directory, file), err => { 12 | if (err) throw err; 13 | }); 14 | } 15 | } 16 | }); -------------------------------------------------------------------------------- /main/http_server/axe-os/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "axe-os", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build --configuration=production && gzipper compress --verbose --gzip --gzip-level 9 ./dist/axe-os && node only-gzip.js", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test", 10 | "bundle-report": "ng build --configuration=production --stats-json && webpack-bundle-analyzer dist/axe-os/stats.json" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "17.2.2", 15 | "@angular/common": "17.2.2", 16 | "@angular/compiler": "17.2.2", 17 | "@angular/core": "17.2.2", 18 | "@angular/forms": "17.2.2", 19 | "@angular/platform-browser": "17.2.2", 20 | "@angular/platform-browser-dynamic": "17.2.2", 21 | "@angular/router": "17.2.2", 22 | "chart.js": "^4.4.1", 23 | "chartjs-adapter-moment": "^1.0.1", 24 | "moment": "^2.30.1", 25 | "ngx-toastr": "^17.0.2", 26 | "primeflex": "^3.3.1", 27 | "primeicons": "^6.0.1", 28 | "primeng": "^17.8.0", 29 | "rxjs": "~7.8.0", 30 | "tslib": "^2.3.0", 31 | "xterm": "^5.2.1", 32 | "zone.js": "~0.14.4" 33 | }, 34 | "devDependencies": { 35 | "@angular-devkit/build-angular": "17.2.1", 36 | "@angular/cli": "17.2.1", 37 | "@angular/compiler-cli": "17.2.2", 38 | "@types/jasmine": "~4.3.0", 39 | "gzipper": "^7.2.0", 40 | "jasmine-core": "~4.6.0", 41 | "karma": "~6.4.0", 42 | "karma-chrome-launcher": "~3.2.0", 43 | "karma-coverage": "~2.2.0", 44 | "karma-jasmine": "~5.1.0", 45 | "karma-jasmine-html-reporter": "~2.1.0", 46 | "typescript": "~5.3.3", 47 | "webpack-bundle-analyzer": "^4.9.0" 48 | } 49 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | 4 | import { HomeComponent } from './components/home/home.component'; 5 | import { LogsComponent } from './components/logs/logs.component'; 6 | import { SettingsComponent } from './components/settings/settings.component'; 7 | import { SwarmComponent } from './components/swarm/swarm.component'; 8 | import { AppLayoutComponent } from './layout/app.layout.component'; 9 | 10 | const routes: Routes = [ 11 | { 12 | path: '', 13 | component: AppLayoutComponent, 14 | children: [ 15 | { 16 | path: '', 17 | component: HomeComponent 18 | }, 19 | { 20 | path: 'logs', 21 | component: LogsComponent 22 | }, 23 | { 24 | path: 'settings', 25 | component: SettingsComponent 26 | }, 27 | { 28 | path: 'swarm', 29 | component: SwarmComponent 30 | } 31 | ] 32 | }, 33 | 34 | ]; 35 | 36 | @NgModule({ 37 | imports: [RouterModule.forRoot(routes)], 38 | exports: [RouterModule] 39 | }) 40 | export class AppRoutingModule { } 41 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 |
8 | 9 |
10 |
-------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitaxeorg/esp-miner-multichip/2f85fd308ca860859070361004151107c3d1191c/main/http_server/axe-os/src/app/app.component.scss -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(() => TestBed.configureTestingModule({ 7 | imports: [RouterTestingModule], 8 | declarations: [AppComponent] 9 | })); 10 | 11 | it('should create the app', () => { 12 | const fixture = TestBed.createComponent(AppComponent); 13 | const app = fixture.componentInstance; 14 | expect(app).toBeTruthy(); 15 | }); 16 | 17 | it(`should have as title 'axe-os'`, () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app.title).toEqual('axe-os'); 21 | }); 22 | 23 | it('should render title', () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | fixture.detectChanges(); 26 | const compiled = fixture.nativeElement as HTMLElement; 27 | expect(compiled.querySelector('.content span')?.textContent).toContain('axe-os app is running!'); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'] 7 | }) 8 | export class AppComponent { 9 | constructor( 10 | 11 | ) { 12 | 13 | 14 | } 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import 'chartjs-adapter-moment'; 2 | 3 | import { CommonModule, HashLocationStrategy, LocationStrategy } from '@angular/common'; 4 | import { HttpClientModule } from '@angular/common/http'; 5 | import { NgModule } from '@angular/core'; 6 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 7 | import { BrowserModule } from '@angular/platform-browser'; 8 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 9 | import { ToastrModule } from 'ngx-toastr'; 10 | 11 | import { AppRoutingModule } from './app-routing.module'; 12 | import { AppComponent } from './app.component'; 13 | import { EditComponent } from './components/edit/edit.component'; 14 | import { HomeComponent } from './components/home/home.component'; 15 | import { LoadingComponent } from './components/loading/loading.component'; 16 | import { LogsComponent } from './components/logs/logs.component'; 17 | import { SettingsComponent } from './components/settings/settings.component'; 18 | import { SwarmComponent } from './components/swarm/swarm.component'; 19 | import { AppLayoutModule } from './layout/app.layout.module'; 20 | import { ANSIPipe } from './pipes/ansi.pipe'; 21 | import { DateAgoPipe } from './pipes/date-ago.pipe'; 22 | import { HashSuffixPipe } from './pipes/hash-suffix.pipe'; 23 | import { PrimeNGModule } from './prime-ng.module'; 24 | 25 | 26 | 27 | const components = [ 28 | AppComponent, 29 | EditComponent, 30 | HomeComponent, 31 | LoadingComponent, 32 | SettingsComponent, 33 | LogsComponent 34 | ]; 35 | 36 | @NgModule({ 37 | declarations: [ 38 | ...components, 39 | 40 | ANSIPipe, 41 | DateAgoPipe, 42 | SwarmComponent, 43 | SettingsComponent, 44 | HashSuffixPipe 45 | ], 46 | imports: [ 47 | BrowserModule, 48 | AppRoutingModule, 49 | HttpClientModule, 50 | ReactiveFormsModule, 51 | FormsModule, 52 | ToastrModule.forRoot({ 53 | positionClass: 'toast-bottom-right' 54 | }), 55 | BrowserAnimationsModule, 56 | CommonModule, 57 | PrimeNGModule, 58 | AppLayoutModule 59 | ], 60 | providers: [ 61 | { provide: LocationStrategy, useClass: HashLocationStrategy }, 62 | ], 63 | bootstrap: [AppComponent] 64 | }) 65 | export class AppModule { } 66 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/edit/edit.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitaxeorg/esp-miner-multichip/2f85fd308ca860859070361004151107c3d1191c/main/http_server/axe-os/src/app/components/edit/edit.component.scss -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/edit/edit.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EditComponent } from './edit.component'; 4 | 5 | describe('EditComponent', () => { 6 | let component: EditComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [EditComponent] 12 | }); 13 | fixture = TestBed.createComponent(EditComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/edit/edit.component.ts: -------------------------------------------------------------------------------- 1 | import { HttpErrorResponse } from '@angular/common/http'; 2 | import { Component, Input, OnInit } from '@angular/core'; 3 | import { FormBuilder, FormGroup, Validators } from '@angular/forms'; 4 | import { ToastrService } from 'ngx-toastr'; 5 | import { startWith } from 'rxjs'; 6 | import { LoadingService } from 'src/app/services/loading.service'; 7 | import { SystemService } from 'src/app/services/system.service'; 8 | import { eASICModel } from 'src/models/enum/eASICModel'; 9 | 10 | @Component({ 11 | selector: 'app-edit', 12 | templateUrl: './edit.component.html', 13 | styleUrls: ['./edit.component.scss'] 14 | }) 15 | export class EditComponent implements OnInit { 16 | 17 | public form!: FormGroup; 18 | 19 | public firmwareUpdateProgress: number | null = null; 20 | public websiteUpdateProgress: number | null = null; 21 | 22 | 23 | public devToolsOpen: boolean = false; 24 | public eASICModel = eASICModel; 25 | public ASICModel!: eASICModel; 26 | 27 | @Input() uri = ''; 28 | 29 | public BM1366DropdownFrequency = [ 30 | { name: '400', value: 400 }, 31 | { name: '425', value: 425 }, 32 | { name: '450', value: 450 }, 33 | { name: '475', value: 475 }, 34 | { name: '485 (default)', value: 485 }, 35 | { name: '500', value: 500 }, 36 | { name: '525', value: 525 }, 37 | { name: '550', value: 550 }, 38 | { name: '575', value: 575 }, 39 | ]; 40 | 41 | public BM1366CoreVoltage = [ 42 | { name: '1100', value: 1100 }, 43 | { name: '1150', value: 1150 }, 44 | { name: '1200 (default)', value: 1200 }, 45 | { name: '1250', value: 1250 }, 46 | { name: '1300', value: 1300 }, 47 | ]; 48 | 49 | constructor( 50 | private fb: FormBuilder, 51 | private systemService: SystemService, 52 | private toastr: ToastrService, 53 | private toastrService: ToastrService, 54 | private loadingService: LoadingService 55 | ) { 56 | 57 | window.addEventListener('resize', this.checkDevTools); 58 | this.checkDevTools(); 59 | 60 | } 61 | ngOnInit(): void { 62 | this.systemService.getInfo(0, this.uri) 63 | .pipe(this.loadingService.lockUIUntilComplete()) 64 | .subscribe(info => { 65 | this.ASICModel = info.ASICModel; 66 | this.form = this.fb.group({ 67 | flipscreen: [info.flipscreen == 1], 68 | invertscreen: [info.invertscreen == 1], 69 | stratumURL: [info.stratumURL, [ 70 | Validators.required, 71 | Validators.pattern(/^(?!.*stratum\+tcp:\/\/).*$/), 72 | Validators.pattern(/^[^:]*$/), 73 | ]], 74 | stratumPort: [info.stratumPort, [ 75 | Validators.required, 76 | Validators.pattern(/^[^:]*$/), 77 | Validators.min(0), 78 | Validators.max(65353) 79 | ]], 80 | fallbackStratumURL: [info.fallbackStratumURL, [ 81 | Validators.pattern(/^(?!.*stratum\+tcp:\/\/).*$/), 82 | ]], 83 | fallbackStratumPort: [info.fallbackStratumPort, [ 84 | Validators.required, 85 | Validators.pattern(/^[^:]*$/), 86 | Validators.min(0), 87 | Validators.max(65353) 88 | ]], 89 | stratumUser: [info.stratumUser, [Validators.required]], 90 | stratumPassword: ['password', [Validators.required]], 91 | fallbackStratumUser: [info.fallbackStratumUser, [Validators.required]], 92 | fallbackStratumPassword: ['password', [Validators.required]], 93 | hostname: [info.hostname, [Validators.required]], 94 | ssid: [info.ssid, [Validators.required]], 95 | wifiPass: ['password'], 96 | coreVoltage: [info.coreVoltage, [Validators.required]], 97 | frequency: [info.frequency, [Validators.required]], 98 | autofanspeed: [info.autofanspeed == 1, [Validators.required]], 99 | invertfanpolarity: [info.invertfanpolarity == 1, [Validators.required]], 100 | fanspeed: [info.fanspeed, [Validators.required]], 101 | overheat_mode: [info.overheat_mode, [Validators.required]] 102 | }); 103 | 104 | this.form.controls['autofanspeed'].valueChanges.pipe( 105 | startWith(this.form.controls['autofanspeed'].value) 106 | ).subscribe(autofanspeed => { 107 | if (autofanspeed) { 108 | this.form.controls['fanspeed'].disable(); 109 | } else { 110 | this.form.controls['fanspeed'].enable(); 111 | } 112 | }); 113 | }); 114 | } 115 | 116 | 117 | private checkDevTools = () => { 118 | if ( 119 | window.outerWidth - window.innerWidth > 160 || 120 | window.outerHeight - window.innerHeight > 160 121 | ) { 122 | this.devToolsOpen = true; 123 | } else { 124 | this.devToolsOpen = false; 125 | } 126 | }; 127 | 128 | public updateSystem() { 129 | 130 | const form = this.form.getRawValue(); 131 | 132 | if (form.wifiPass === 'password') { 133 | delete form.wifiPass; 134 | } 135 | if (form.stratumPassword === 'password') { 136 | delete form.stratumPassword; 137 | } 138 | 139 | form.overheat_mode = form.overheat_mode ? 1 : 0; 140 | 141 | this.systemService.updateSystem(this.uri, form) 142 | .pipe(this.loadingService.lockUIUntilComplete()) 143 | .subscribe({ 144 | next: () => { 145 | this.toastr.success('Success!', 'Saved.'); 146 | }, 147 | error: (err: HttpErrorResponse) => { 148 | this.toastr.error('Error.', `Could not save. ${err.message}`); 149 | } 150 | }); 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/home/home.component.scss: -------------------------------------------------------------------------------- 1 | .danger { 2 | color: red; 3 | font-weight: bold; 4 | } 5 | 6 | .card { 7 | min-height: 100%; 8 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | 5 | describe('HomeComponent', () => { 6 | let component: HomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [HomeComponent] 12 | }); 13 | fixture = TestBed.createComponent(HomeComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/loading/loading.component.html: -------------------------------------------------------------------------------- 1 |
2 |
Working...
3 |
-------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/loading/loading.component.scss: -------------------------------------------------------------------------------- 1 | #loading { 2 | background-color: rgba(0, 0, 0, 0.5); 3 | top: 0; 4 | bottom: 0; 5 | left: 0; 6 | right: 0; 7 | position: fixed; 8 | z-index: 99999999999999999999; 9 | } 10 | 11 | #loading-text { 12 | text-align: center; 13 | margin-top: 40vh; 14 | font-size: 20pt; 15 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/loading/loading.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoadingComponent } from './loading.component'; 4 | 5 | describe('LoadingComponent', () => { 6 | let component: LoadingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [LoadingComponent] 12 | }); 13 | fixture = TestBed.createComponent(LoadingComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/loading/loading.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { Observable } from 'rxjs'; 3 | import { LoadingService } from 'src/app/services/loading.service'; 4 | 5 | @Component({ 6 | selector: 'app-loading', 7 | templateUrl: './loading.component.html', 8 | styleUrls: ['./loading.component.scss'] 9 | }) 10 | export class LoadingComponent { 11 | 12 | public loading$: Observable; 13 | 14 | constructor(private loadingService: LoadingService) { 15 | this.loading$ = this.loadingService.loading$.asObservable(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/logs/logs.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
Overview
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
Model:{{info.ASICModel}}
Uptime:{{info.uptimeSeconds | dateAgo}}
WiFi Status:{{info.wifiStatus}}
Free Heap Memory:{{info.freeHeap}}
Version:{{info.version}}
Board Version:{{info.boardVersion}}
31 |
32 | 33 |
34 | 35 |
36 |
37 |

Realtime Logs 41 | 42 | 44 |

45 | 46 |
47 |
₿ {{log | ANSI}}
48 |
49 |
50 |
51 |
-------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/logs/logs.component.scss: -------------------------------------------------------------------------------- 1 | #logs { 2 | height: 500px; 3 | font-family: monospace; 4 | border: 1px solid #304562; 5 | overflow-y: scroll; 6 | overflow-x: hidden; 7 | 8 | >div { 9 | max-width: 100%; 10 | line-break: anywhere; 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/logs/logs.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LogsComponent } from './logs.component'; 4 | 5 | describe('LogsComponent', () => { 6 | let component: LogsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [LogsComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(LogsComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/logs/logs.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewChecked, Component, ElementRef, OnDestroy, ViewChild } from '@angular/core'; 2 | import { interval, map, Observable, shareReplay, startWith, Subscription, switchMap } from 'rxjs'; 3 | import { SystemService } from 'src/app/services/system.service'; 4 | import { WebsocketService } from 'src/app/services/web-socket.service'; 5 | import { ISystemInfo } from 'src/models/ISystemInfo'; 6 | 7 | @Component({ 8 | selector: 'app-logs', 9 | templateUrl: './logs.component.html', 10 | styleUrl: './logs.component.scss' 11 | }) 12 | export class LogsComponent implements OnDestroy, AfterViewChecked { 13 | 14 | @ViewChild('scrollContainer') private scrollContainer!: ElementRef; 15 | public info$: Observable; 16 | 17 | public logs: string[] = []; 18 | 19 | private websocketSubscription?: Subscription; 20 | 21 | public showLogs = false; 22 | 23 | public stopScroll: boolean = false; 24 | 25 | constructor( 26 | private websocketService: WebsocketService, 27 | private systemService: SystemService 28 | ) { 29 | 30 | 31 | this.info$ = interval(5000).pipe( 32 | startWith(() => this.systemService.getInfo(0)), 33 | switchMap(() => { 34 | return this.systemService.getInfo(0) 35 | }), 36 | map(info => { 37 | info.power = parseFloat(info.power.toFixed(1)) 38 | info.voltage = parseFloat((info.voltage / 1000).toFixed(1)); 39 | info.current = parseFloat((info.current / 1000).toFixed(1)); 40 | info.coreVoltageActual = parseFloat((info.coreVoltageActual / 1000).toFixed(2)); 41 | info.coreVoltage = parseFloat((info.coreVoltage / 1000).toFixed(2)); 42 | return info; 43 | }), 44 | shareReplay({ refCount: true, bufferSize: 1 }) 45 | ); 46 | 47 | 48 | } 49 | ngOnDestroy(): void { 50 | this.websocketSubscription?.unsubscribe(); 51 | } 52 | public toggleLogs() { 53 | this.showLogs = !this.showLogs; 54 | 55 | if (this.showLogs) { 56 | this.websocketSubscription = this.websocketService.ws$.subscribe({ 57 | next: (val) => { 58 | this.logs.push(val); 59 | if (this.logs.length > 100) { 60 | this.logs.shift(); 61 | } 62 | } 63 | }) 64 | } else { 65 | this.websocketSubscription?.unsubscribe(); 66 | } 67 | } 68 | 69 | ngAfterViewChecked(): void { 70 | if(this.stopScroll == true){ 71 | return; 72 | } 73 | if (this.scrollContainer?.nativeElement != null) { 74 | this.scrollContainer.nativeElement.scrollTo({ left: 0, top: this.scrollContainer.nativeElement.scrollHeight, behavior: 'smooth' }); 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/settings/settings.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Settings

3 | 4 | 5 | 6 | 7 |
8 | 9 |
10 |
11 |
12 |
Current Version: {{(info$ | async)?.version}}
13 |

Latest Release: Check

14 |
15 |
16 | 17 |
Current Version: {{(info$ | async)?.version}}
18 |

Latest Release: {{latestRelease.name}}

19 | 20 |
21 | 25 |
26 | www.bin 28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |

Update Firmware {{firmwareUpdateProgress}}%

36 | 37 | 39 | 40 | (esp-miner-multichip.bin) 41 |
42 | 43 |
44 |
45 |
46 |

Update Website {{websiteUpdateProgress}}%

47 | 48 | 50 | 51 | (www.bin) 52 |
53 |
54 |
-------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/settings/settings.component.scss: -------------------------------------------------------------------------------- 1 | input[type="text"], 2 | input[type="number"], 3 | input[type="password"], 4 | input[type="range"] { 5 | min-width: 250px; 6 | max-width: 90%; 7 | } 8 | 9 | select { 10 | min-width: 268px; 11 | max-width: 90%; 12 | } 13 | 14 | .restart { 15 | margin-bottom: 1.5rem; 16 | 17 | } 18 | 19 | @media only screen and (min-width:900px) { 20 | 21 | input[type="text"], 22 | input[type="password"], 23 | input[type="number"], 24 | input[type="range"] { 25 | min-width: 500px 26 | } 27 | 28 | select { 29 | min-width: 518px 30 | } 31 | } 32 | 33 | a { 34 | color: white; 35 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/settings/settings.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SettingsComponent } from './settings.component'; 4 | 5 | describe('SettingsComponent', () => { 6 | let component: SettingsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [SettingsComponent] 12 | }); 13 | fixture = TestBed.createComponent(SettingsComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/swarm/swarm.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 |
15 |
16 |
17 | 18 |
19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 |
IPHash RateUptimeAcceptedPowerTempBest DifficultyVersionEditRestartRemove
{{axe.ip}}{{axe.hashRate | number: '1.2-2'}} Gh/s{{axe.uptimeSeconds | dateAgo}}{{axe.sharesAccepted}}{{axe.power | number: '1.2-2'}} W {{axe.temp}} C{{axe.bestDiff}}{{axe.version}}
50 |
51 | 52 | 53 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/swarm/swarm.component.scss: -------------------------------------------------------------------------------- 1 | form { 2 | margin-bottom: 20px; 3 | } 4 | 5 | table { 6 | width: 100%; 7 | margin-top: 40px; 8 | margin-bottom: 40px; 9 | border: 1px solid #304562; 10 | } 11 | 12 | th { 13 | text-align: left; 14 | background-color: #1f2d40; 15 | } 16 | 17 | 18 | th, 19 | td { 20 | padding: 1rem 1rem; 21 | border-bottom: 1px solid #304562; 22 | } 23 | 24 | a { 25 | color: white; 26 | } 27 | 28 | .modal-backdrop { 29 | background-color: rgba(0, 0, 0, 0.5); 30 | top: 0; 31 | bottom: 0; 32 | left: 0; 33 | right: 0; 34 | position: fixed; 35 | z-index: 9; 36 | } 37 | 38 | .modal { 39 | position: fixed; 40 | max-height: 70vh; 41 | width: 50vw; 42 | z-index: 999; 43 | top: 0; 44 | left: 0; 45 | margin: 12vh 25vw; 46 | padding: 50px; 47 | overflow-y: auto; 48 | } 49 | 50 | .close { 51 | position: absolute; 52 | right: 20px; 53 | top: 20px; 54 | cursor: pointer; 55 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/swarm/swarm.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SwarmComponent } from './swarm.component'; 4 | 5 | describe('SwarmComponent', () => { 6 | let component: SwarmComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [SwarmComponent] 12 | }); 13 | fixture = TestBed.createComponent(SwarmComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/components/swarm/swarm.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { FormBuilder, FormGroup, Validators } from '@angular/forms'; 3 | import { ToastrService } from 'ngx-toastr'; 4 | import { BehaviorSubject, catchError, combineLatest, forkJoin, map, Observable, of, startWith, switchMap } from 'rxjs'; 5 | import { SystemService } from 'src/app/services/system.service'; 6 | 7 | @Component({ 8 | selector: 'app-swarm', 9 | templateUrl: './swarm.component.html', 10 | styleUrls: ['./swarm.component.scss'] 11 | }) 12 | export class SwarmComponent { 13 | 14 | public form: FormGroup; 15 | 16 | public swarm$: Observable[]>; 17 | 18 | public refresh$: BehaviorSubject = new BehaviorSubject(null); 19 | 20 | public selectedAxeOs: any = null; 21 | public showEdit = false; 22 | 23 | constructor( 24 | private fb: FormBuilder, 25 | private systemService: SystemService, 26 | private toastr: ToastrService 27 | ) { 28 | this.form = this.fb.group({ 29 | ip: [null, [Validators.required, Validators.pattern('(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)')]] 30 | }); 31 | 32 | this.swarm$ = this.systemService.getSwarmInfo().pipe( 33 | map(swarmInfo => { 34 | return swarmInfo.map(({ ip }) => { 35 | // Make individual API calls for each IP 36 | return this.refresh$.pipe( 37 | switchMap(() => { 38 | return this.systemService.getInfo(0, `http://${ip}`); 39 | }) 40 | ).pipe( 41 | startWith({ ip }), 42 | map(info => { 43 | return { 44 | ip, 45 | ...info 46 | }; 47 | }), 48 | catchError(error => { 49 | return of({ ip, error: true }); 50 | }) 51 | ); 52 | }); 53 | }) 54 | ); 55 | 56 | 57 | } 58 | 59 | 60 | public add() { 61 | const newIp = this.form.value.ip; 62 | 63 | combineLatest([this.systemService.getSwarmInfo('http://' + newIp), this.systemService.getSwarmInfo()]).pipe( 64 | switchMap(([newSwarmInfo, existingSwarmInfo]) => { 65 | 66 | if (existingSwarmInfo.length < 1) { 67 | existingSwarmInfo.push({ ip: window.location.host }); 68 | } 69 | 70 | 71 | const swarmUpdate = existingSwarmInfo.map(({ ip }) => { 72 | return this.systemService.updateSwarm('http://' + ip, [{ ip: newIp }, ...newSwarmInfo, ...existingSwarmInfo]) 73 | }); 74 | 75 | const newAxeOs = this.systemService.updateSwarm('http://' + newIp, [{ ip: newIp }, ...existingSwarmInfo]) 76 | 77 | return forkJoin([newAxeOs, ...swarmUpdate]); 78 | 79 | }) 80 | ).subscribe({ 81 | next: () => { 82 | this.toastr.success('Success!', 'Saved.'); 83 | window.location.reload(); 84 | }, 85 | error: (err) => { 86 | this.toastr.error('Error.', `Could not save. ${err.message}`); 87 | }, 88 | complete: () => { 89 | this.form.reset(); 90 | } 91 | }); 92 | 93 | } 94 | 95 | public refresh() { 96 | this.refresh$.next(null); 97 | } 98 | 99 | public edit(axe: any) { 100 | this.selectedAxeOs = axe; 101 | this.showEdit = true; 102 | } 103 | 104 | public restart(axe: any) { 105 | this.systemService.restart(`http://${axe.ip}`).subscribe(res => { 106 | 107 | }); 108 | this.toastr.success('Success!', 'Bitaxe restarted'); 109 | } 110 | 111 | public remove(axeOs: any) { 112 | this.systemService.getSwarmInfo().pipe( 113 | switchMap((swarmInfo) => { 114 | 115 | const newSwarm = swarmInfo.filter((s: any) => s.ip != axeOs.ip); 116 | 117 | const swarmUpdate = newSwarm.map(({ ip }) => { 118 | return this.systemService.updateSwarm('http://' + ip, newSwarm) 119 | }); 120 | 121 | const removedAxeOs = this.systemService.updateSwarm('http://' + axeOs.ip, []); 122 | 123 | return forkJoin([removedAxeOs, ...swarmUpdate]); 124 | }) 125 | ).subscribe({ 126 | next: () => { 127 | this.toastr.success('Success!', 'Saved.'); 128 | window.location.reload(); 129 | }, 130 | error: (err) => { 131 | this.toastr.error('Error.', `Could not save. ${err.message}`); 132 | }, 133 | complete: () => { 134 | this.form.reset(); 135 | } 136 | }); 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/api/menuchangeevent.ts: -------------------------------------------------------------------------------- 1 | export interface MenuChangeEvent { 2 | key: string; 3 | routeEvent?: boolean; 4 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/app.footer.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/app.footer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { LayoutService } from "./service/app.layout.service"; 3 | 4 | @Component({ 5 | selector: 'app-footer', 6 | templateUrl: './app.footer.component.html' 7 | }) 8 | export class AppFooterComponent { 9 | constructor(public layoutService: LayoutService) { } 10 | } 11 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/app.layout.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 |
7 |
8 | 9 |
10 | 11 |
12 | 13 |
14 |
-------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/app.layout.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnDestroy, Renderer2, ViewChild } from '@angular/core'; 2 | import { NavigationEnd, Router } from '@angular/router'; 3 | import { filter, Subscription } from 'rxjs'; 4 | import { LayoutService } from "./service/app.layout.service"; 5 | import { AppSidebarComponent } from "./app.sidebar.component"; 6 | import { AppTopBarComponent } from './app.topbar.component'; 7 | 8 | @Component({ 9 | selector: 'app-layout', 10 | templateUrl: './app.layout.component.html' 11 | }) 12 | export class AppLayoutComponent implements OnDestroy { 13 | 14 | overlayMenuOpenSubscription: Subscription; 15 | 16 | menuOutsideClickListener: any; 17 | 18 | profileMenuOutsideClickListener: any; 19 | 20 | @ViewChild(AppSidebarComponent) appSidebar!: AppSidebarComponent; 21 | 22 | @ViewChild(AppTopBarComponent) appTopbar!: AppTopBarComponent; 23 | 24 | constructor(public layoutService: LayoutService, public renderer: Renderer2, public router: Router) { 25 | this.overlayMenuOpenSubscription = this.layoutService.overlayOpen$.subscribe(() => { 26 | if (!this.menuOutsideClickListener) { 27 | this.menuOutsideClickListener = this.renderer.listen('document', 'click', event => { 28 | const isOutsideClicked = !(this.appSidebar.el.nativeElement.isSameNode(event.target) || this.appSidebar.el.nativeElement.contains(event.target) 29 | || this.appTopbar.menuButton.nativeElement.isSameNode(event.target) || this.appTopbar.menuButton.nativeElement.contains(event.target)); 30 | 31 | if (isOutsideClicked) { 32 | this.hideMenu(); 33 | } 34 | }); 35 | } 36 | 37 | if (!this.profileMenuOutsideClickListener) { 38 | this.profileMenuOutsideClickListener = this.renderer.listen('document', 'click', event => { 39 | const isOutsideClicked = !(this.appTopbar.menu.nativeElement.isSameNode(event.target) || this.appTopbar.menu.nativeElement.contains(event.target) 40 | || this.appTopbar.topbarMenuButton.nativeElement.isSameNode(event.target) || this.appTopbar.topbarMenuButton.nativeElement.contains(event.target)); 41 | 42 | if (isOutsideClicked) { 43 | this.hideProfileMenu(); 44 | } 45 | }); 46 | } 47 | 48 | if (this.layoutService.state.staticMenuMobileActive) { 49 | this.blockBodyScroll(); 50 | } 51 | }); 52 | 53 | this.router.events.pipe(filter(event => event instanceof NavigationEnd)) 54 | .subscribe(() => { 55 | this.hideMenu(); 56 | this.hideProfileMenu(); 57 | }); 58 | } 59 | 60 | hideMenu() { 61 | this.layoutService.state.overlayMenuActive = false; 62 | this.layoutService.state.staticMenuMobileActive = false; 63 | this.layoutService.state.menuHoverActive = false; 64 | if (this.menuOutsideClickListener) { 65 | this.menuOutsideClickListener(); 66 | this.menuOutsideClickListener = null; 67 | } 68 | this.unblockBodyScroll(); 69 | } 70 | 71 | hideProfileMenu() { 72 | this.layoutService.state.profileSidebarVisible = false; 73 | if (this.profileMenuOutsideClickListener) { 74 | this.profileMenuOutsideClickListener(); 75 | this.profileMenuOutsideClickListener = null; 76 | } 77 | } 78 | 79 | blockBodyScroll(): void { 80 | if (document.body.classList) { 81 | document.body.classList.add('blocked-scroll'); 82 | } 83 | else { 84 | document.body.className += ' blocked-scroll'; 85 | } 86 | } 87 | 88 | unblockBodyScroll(): void { 89 | if (document.body.classList) { 90 | document.body.classList.remove('blocked-scroll'); 91 | } 92 | else { 93 | document.body.className = document.body.className.replace(new RegExp('(^|\\b)' + 94 | 'blocked-scroll'.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); 95 | } 96 | } 97 | 98 | get containerClass() { 99 | return { 100 | 'layout-theme-light': this.layoutService.config().colorScheme === 'light', 101 | 'layout-theme-dark': this.layoutService.config().colorScheme === 'dark', 102 | 'layout-overlay': this.layoutService.config().menuMode === 'overlay', 103 | 'layout-static': this.layoutService.config().menuMode === 'static', 104 | 'layout-static-inactive': this.layoutService.state.staticMenuDesktopInactive && this.layoutService.config().menuMode === 'static', 105 | 'layout-overlay-active': this.layoutService.state.overlayMenuActive, 106 | 'layout-mobile-active': this.layoutService.state.staticMenuMobileActive, 107 | 'p-input-filled': this.layoutService.config().inputStyle === 'filled', 108 | 'p-ripple-disabled': !this.layoutService.config().ripple 109 | } 110 | } 111 | 112 | ngOnDestroy() { 113 | if (this.overlayMenuOpenSubscription) { 114 | this.overlayMenuOpenSubscription.unsubscribe(); 115 | } 116 | 117 | if (this.menuOutsideClickListener) { 118 | this.menuOutsideClickListener(); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/app.layout.module.ts: -------------------------------------------------------------------------------- 1 | import { HttpClientModule } from '@angular/common/http'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { BrowserModule } from '@angular/platform-browser'; 5 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 6 | import { RouterModule } from '@angular/router'; 7 | import { BadgeModule } from 'primeng/badge'; 8 | import { InputSwitchModule } from 'primeng/inputswitch'; 9 | import { InputTextModule } from 'primeng/inputtext'; 10 | import { RadioButtonModule } from 'primeng/radiobutton'; 11 | import { RippleModule } from 'primeng/ripple'; 12 | import { SidebarModule } from 'primeng/sidebar'; 13 | 14 | import { PrimeNGModule } from '../prime-ng.module'; 15 | import { AppFooterComponent } from './app.footer.component'; 16 | import { AppLayoutComponent } from './app.layout.component'; 17 | import { AppMenuComponent } from './app.menu.component'; 18 | import { AppMenuitemComponent } from './app.menuitem.component'; 19 | import { AppSidebarComponent } from './app.sidebar.component'; 20 | import { AppTopBarComponent } from './app.topbar.component'; 21 | 22 | @NgModule({ 23 | declarations: [ 24 | AppMenuitemComponent, 25 | AppTopBarComponent, 26 | AppFooterComponent, 27 | AppMenuComponent, 28 | AppSidebarComponent, 29 | AppLayoutComponent, 30 | ], 31 | imports: [ 32 | BrowserModule, 33 | FormsModule, 34 | HttpClientModule, 35 | BrowserAnimationsModule, 36 | InputTextModule, 37 | SidebarModule, 38 | BadgeModule, 39 | RadioButtonModule, 40 | InputSwitchModule, 41 | RippleModule, 42 | RouterModule, 43 | PrimeNGModule, 44 | 45 | ], 46 | exports: [AppLayoutComponent] 47 | }) 48 | export class AppLayoutModule { } 49 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/app.menu.component.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
  • 4 | 5 |
    6 | 7 | 8 | 9 | 10 |
-------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/app.menu.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { ToastrService } from 'ngx-toastr'; 3 | 4 | import { SystemService } from '../services/system.service'; 5 | import { LayoutService } from './service/app.layout.service'; 6 | 7 | @Component({ 8 | selector: 'app-menu', 9 | templateUrl: './app.menu.component.html' 10 | }) 11 | export class AppMenuComponent implements OnInit { 12 | 13 | model: any[] = []; 14 | 15 | constructor(public layoutService: LayoutService, 16 | private systemService: SystemService, 17 | private toastr: ToastrService 18 | ) { } 19 | 20 | ngOnInit() { 21 | this.model = [ 22 | { 23 | label: 'Menu', 24 | items: [ 25 | { label: 'Dashboard', icon: 'pi pi-fw pi-home', routerLink: ['/'] }, 26 | { label: 'Swarm', icon: 'pi pi-fw pi-share-alt', routerLink: ['swarm'] }, 27 | { label: 'Settings', icon: 'pi pi-fw pi-cog', routerLink: ['settings'] }, 28 | { label: 'Logs', icon: 'pi pi-fw pi-list', routerLink: ['logs'] }, 29 | 30 | ] 31 | } 32 | 33 | ]; 34 | } 35 | 36 | 37 | 38 | public restart() { 39 | this.systemService.restart().subscribe(res => { 40 | 41 | }); 42 | this.toastr.success('Success!', 'Bitaxe restarted'); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/app.menu.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Subject } from 'rxjs'; 3 | import { MenuChangeEvent } from './api/menuchangeevent'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class MenuService { 9 | 10 | private menuSource = new Subject(); 11 | private resetSource = new Subject(); 12 | 13 | menuSource$ = this.menuSource.asObservable(); 14 | resetSource$ = this.resetSource.asObservable(); 15 | 16 | onMenuStateChange(event: MenuChangeEvent) { 17 | this.menuSource.next(event); 18 | } 19 | 20 | reset() { 21 | this.resetSource.next(true); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/app.menuitem.component.ts: -------------------------------------------------------------------------------- 1 | import { ChangeDetectorRef, Component, Host, HostBinding, Input, OnDestroy, OnInit } from '@angular/core'; 2 | import { NavigationEnd, Router } from '@angular/router'; 3 | import { animate, state, style, transition, trigger } from '@angular/animations'; 4 | import { Subscription } from 'rxjs'; 5 | import { filter } from 'rxjs/operators'; 6 | import { MenuService } from './app.menu.service'; 7 | import { LayoutService } from './service/app.layout.service'; 8 | 9 | @Component({ 10 | // eslint-disable-next-line @angular-eslint/component-selector 11 | selector: '[app-menuitem]', 12 | template: ` 13 | 14 |
{{item.label}}
15 | 17 | 18 | {{item.label}} 19 | 20 | 21 | 26 | 27 | {{item.label}} 28 | 29 | 30 | 31 |
    32 | 33 |
  • 34 |
    35 |
36 |
37 | `, 38 | animations: [ 39 | trigger('children', [ 40 | state('collapsed', style({ 41 | height: '0' 42 | })), 43 | state('expanded', style({ 44 | height: '*' 45 | })), 46 | transition('collapsed <=> expanded', animate('400ms cubic-bezier(0.86, 0, 0.07, 1)')) 47 | ]) 48 | ] 49 | }) 50 | export class AppMenuitemComponent implements OnInit, OnDestroy { 51 | 52 | @Input() item: any; 53 | 54 | @Input() index!: number; 55 | 56 | @Input() @HostBinding('class.layout-root-menuitem') root!: boolean; 57 | 58 | @Input() parentKey!: string; 59 | 60 | active = false; 61 | 62 | menuSourceSubscription: Subscription; 63 | 64 | menuResetSubscription: Subscription; 65 | 66 | key: string = ""; 67 | 68 | constructor(public layoutService: LayoutService, private cd: ChangeDetectorRef, public router: Router, private menuService: MenuService) { 69 | this.menuSourceSubscription = this.menuService.menuSource$.subscribe(value => { 70 | Promise.resolve(null).then(() => { 71 | if (value.routeEvent) { 72 | this.active = (value.key === this.key || value.key.startsWith(this.key + '-')) ? true : false; 73 | } 74 | else { 75 | if (value.key !== this.key && !value.key.startsWith(this.key + '-')) { 76 | this.active = false; 77 | } 78 | } 79 | }); 80 | }); 81 | 82 | this.menuResetSubscription = this.menuService.resetSource$.subscribe(() => { 83 | this.active = false; 84 | }); 85 | 86 | this.router.events.pipe(filter(event => event instanceof NavigationEnd)) 87 | .subscribe(params => { 88 | if (this.item.routerLink) { 89 | this.updateActiveStateFromRoute(); 90 | } 91 | }); 92 | } 93 | 94 | ngOnInit() { 95 | this.key = this.parentKey ? this.parentKey + '-' + this.index : String(this.index); 96 | 97 | if (this.item.routerLink) { 98 | this.updateActiveStateFromRoute(); 99 | } 100 | } 101 | 102 | updateActiveStateFromRoute() { 103 | let activeRoute = this.router.isActive(this.item.routerLink[0], { paths: 'exact', queryParams: 'ignored', matrixParams: 'ignored', fragment: 'ignored' }); 104 | 105 | if (activeRoute) { 106 | this.menuService.onMenuStateChange({ key: this.key, routeEvent: true }); 107 | } 108 | } 109 | 110 | itemClick(event: Event) { 111 | // avoid processing disabled items 112 | if (this.item.disabled) { 113 | event.preventDefault(); 114 | return; 115 | } 116 | 117 | // execute command 118 | if (this.item.command) { 119 | this.item.command({ originalEvent: event, item: this.item }); 120 | } 121 | 122 | // toggle active state 123 | if (this.item.items) { 124 | this.active = !this.active; 125 | } 126 | 127 | this.menuService.onMenuStateChange({ key: this.key }); 128 | } 129 | 130 | get submenuAnimation() { 131 | return this.root ? 'expanded' : (this.active ? 'expanded' : 'collapsed'); 132 | } 133 | 134 | @HostBinding('class.active-menuitem') 135 | get activeClass() { 136 | return this.active && !this.root; 137 | } 138 | 139 | ngOnDestroy() { 140 | if (this.menuSourceSubscription) { 141 | this.menuSourceSubscription.unsubscribe(); 142 | } 143 | 144 | if (this.menuResetSubscription) { 145 | this.menuResetSubscription.unsubscribe(); 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/app.sidebar.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/app.sidebar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef } from '@angular/core'; 2 | import { LayoutService } from "./service/app.layout.service"; 3 | 4 | @Component({ 5 | selector: 'app-sidebar', 6 | templateUrl: './app.sidebar.component.html' 7 | }) 8 | export class AppSidebarComponent { 9 | constructor(public layoutService: LayoutService, public el: ElementRef) { } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/app.topbar.component.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | 6 | 9 | 10 | 11 |
12 | 13 |
14 | 15 |
-------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/app.topbar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, ViewChild } from '@angular/core'; 2 | import { MenuItem } from 'primeng/api'; 3 | 4 | import { LayoutService } from './service/app.layout.service'; 5 | 6 | @Component({ 7 | selector: 'app-topbar', 8 | templateUrl: './app.topbar.component.html' 9 | }) 10 | export class AppTopBarComponent { 11 | 12 | items!: MenuItem[]; 13 | 14 | @ViewChild('menubutton') menuButton!: ElementRef; 15 | 16 | @ViewChild('topbarmenubutton') topbarMenuButton!: ElementRef; 17 | 18 | @ViewChild('topbarmenu') menu!: ElementRef; 19 | 20 | constructor(public layoutService: LayoutService, 21 | ) { } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/service/app.layout.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, effect, signal } from '@angular/core'; 2 | import { Subject } from 'rxjs'; 3 | 4 | export interface AppConfig { 5 | inputStyle: string; 6 | colorScheme: string; 7 | theme: string; 8 | ripple: boolean; 9 | menuMode: string; 10 | scale: number; 11 | } 12 | 13 | interface LayoutState { 14 | staticMenuDesktopInactive: boolean; 15 | overlayMenuActive: boolean; 16 | profileSidebarVisible: boolean; 17 | configSidebarVisible: boolean; 18 | staticMenuMobileActive: boolean; 19 | menuHoverActive: boolean; 20 | } 21 | 22 | @Injectable({ 23 | providedIn: 'root', 24 | }) 25 | export class LayoutService { 26 | _config: AppConfig = { 27 | ripple: false, 28 | inputStyle: 'outlined', 29 | menuMode: 'static', 30 | colorScheme: 'light', 31 | theme: 'lara-light-indigo', 32 | scale: 14, 33 | }; 34 | 35 | config = signal(this._config); 36 | 37 | state: LayoutState = { 38 | staticMenuDesktopInactive: false, 39 | overlayMenuActive: false, 40 | profileSidebarVisible: false, 41 | configSidebarVisible: false, 42 | staticMenuMobileActive: false, 43 | menuHoverActive: false, 44 | }; 45 | 46 | private configUpdate = new Subject(); 47 | 48 | private overlayOpen = new Subject(); 49 | 50 | configUpdate$ = this.configUpdate.asObservable(); 51 | 52 | overlayOpen$ = this.overlayOpen.asObservable(); 53 | 54 | constructor() { 55 | effect(() => { 56 | const config = this.config(); 57 | if (this.updateStyle(config)) { 58 | this.changeTheme(); 59 | } 60 | this.changeScale(config.scale); 61 | this.onConfigUpdate(); 62 | }); 63 | } 64 | 65 | updateStyle(config: AppConfig) { 66 | return ( 67 | config.theme !== this._config.theme || 68 | config.colorScheme !== this._config.colorScheme 69 | ); 70 | } 71 | 72 | onMenuToggle() { 73 | if (this.isOverlay()) { 74 | this.state.overlayMenuActive = !this.state.overlayMenuActive; 75 | if (this.state.overlayMenuActive) { 76 | this.overlayOpen.next(null); 77 | } 78 | } 79 | 80 | if (this.isDesktop()) { 81 | this.state.staticMenuDesktopInactive = 82 | !this.state.staticMenuDesktopInactive; 83 | } else { 84 | this.state.staticMenuMobileActive = 85 | !this.state.staticMenuMobileActive; 86 | 87 | if (this.state.staticMenuMobileActive) { 88 | this.overlayOpen.next(null); 89 | } 90 | } 91 | } 92 | 93 | showProfileSidebar() { 94 | this.state.profileSidebarVisible = !this.state.profileSidebarVisible; 95 | if (this.state.profileSidebarVisible) { 96 | this.overlayOpen.next(null); 97 | } 98 | } 99 | 100 | showConfigSidebar() { 101 | this.state.configSidebarVisible = true; 102 | } 103 | 104 | isOverlay() { 105 | return this.config().menuMode === 'overlay'; 106 | } 107 | 108 | isDesktop() { 109 | return window.innerWidth > 991; 110 | } 111 | 112 | isMobile() { 113 | return !this.isDesktop(); 114 | } 115 | 116 | onConfigUpdate() { 117 | this._config = { ...this.config() }; 118 | this.configUpdate.next(this.config()); 119 | } 120 | 121 | changeTheme() { 122 | const config = this.config(); 123 | const themeLink = document.getElementById('theme-css'); 124 | const themeLinkHref = themeLink.getAttribute('href')!; 125 | const newHref = themeLinkHref 126 | .split('/') 127 | .map((el) => 128 | el == this._config.theme 129 | ? (el = config.theme) 130 | : el == `theme-${this._config.colorScheme}` 131 | ? (el = `theme-${config.colorScheme}`) 132 | : el 133 | ) 134 | .join('/'); 135 | 136 | this.replaceThemeLink(newHref); 137 | } 138 | replaceThemeLink(href: string) { 139 | const id = 'theme-css'; 140 | let themeLink = document.getElementById(id); 141 | const cloneLinkElement = themeLink.cloneNode(true); 142 | 143 | cloneLinkElement.setAttribute('href', href); 144 | cloneLinkElement.setAttribute('id', id + '-clone'); 145 | 146 | themeLink.parentNode!.insertBefore( 147 | cloneLinkElement, 148 | themeLink.nextSibling 149 | ); 150 | cloneLinkElement.addEventListener('load', () => { 151 | themeLink.remove(); 152 | cloneLinkElement.setAttribute('id', id); 153 | }); 154 | } 155 | 156 | changeScale(value: number) { 157 | document.documentElement.style.fontSize = `${value}px`; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/styles/layout/_config.scss: -------------------------------------------------------------------------------- 1 | .layout-config-button { 2 | display: block; 3 | position: fixed; 4 | width: 3rem; 5 | height: 3rem; 6 | line-height: 3rem; 7 | background: var(--primary-color); 8 | color: var(--primary-color-text); 9 | text-align: center; 10 | top: 50%; 11 | right: 0; 12 | margin-top: -1.5rem; 13 | border-top-left-radius: var(--border-radius); 14 | border-bottom-left-radius: var(--border-radius); 15 | border-top-right-radius: 0; 16 | border-bottom-right-radius: 0; 17 | transition: background-color var(--transition-duration); 18 | overflow: hidden; 19 | cursor: pointer; 20 | z-index: 999; 21 | box-shadow: -.25rem 0 1rem rgba(0,0,0,.15); 22 | 23 | i { 24 | font-size: 2rem; 25 | line-height: inherit; 26 | transform: rotate(0deg); 27 | transition: transform 1s; 28 | } 29 | 30 | &:hover { 31 | background: var(--primary-400); 32 | } 33 | } 34 | 35 | .layout-config-sidebar { 36 | &.p-sidebar { 37 | .p-sidebar-content { 38 | padding-left: 2rem; 39 | padding-right: 2rem; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/styles/layout/_content.scss: -------------------------------------------------------------------------------- 1 | .layout-main-container { 2 | display: flex; 3 | flex-direction: column; 4 | min-height: 100vh; 5 | justify-content: space-between; 6 | padding: 7rem 2rem 2rem 4rem; 7 | transition: margin-left $transitionDuration; 8 | } 9 | 10 | .layout-main { 11 | flex: 1 1 auto; 12 | } 13 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/styles/layout/_footer.scss: -------------------------------------------------------------------------------- 1 | .layout-footer { 2 | transition: margin-left $transitionDuration; 3 | display: flex; 4 | align-items: center; 5 | justify-content: center; 6 | padding-top: 1rem; 7 | border-top: 1px solid var(--surface-border); 8 | } 9 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/styles/layout/_main.scss: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | html { 6 | height: 100%; 7 | font-size: $scale; 8 | } 9 | 10 | body { 11 | font-family: var(--font-family); 12 | color: var(--text-color); 13 | background-color: var(--surface-ground); 14 | margin: 0; 15 | padding: 0; 16 | min-height: 100%; 17 | -webkit-font-smoothing: antialiased; 18 | -moz-osx-font-smoothing: grayscale; 19 | } 20 | 21 | a { 22 | text-decoration: none; 23 | color: var(--primary-color); 24 | } 25 | 26 | .layout-wrapper { 27 | min-height: 100vh; 28 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/styles/layout/_menu.scss: -------------------------------------------------------------------------------- 1 | .layout-sidebar { 2 | position: fixed; 3 | width: 300px; 4 | height: calc(100vh - 9rem); 5 | z-index: 999; 6 | overflow-y: auto; 7 | user-select: none; 8 | top: 7rem; 9 | left: 2rem; 10 | transition: transform $transitionDuration, left $transitionDuration; 11 | background-color: var(--surface-overlay); 12 | border-radius: $borderRadius; 13 | padding: 0.5rem 1.5rem; 14 | box-shadow: 0px 3px 5px rgba(0, 0, 0, .02), 0px 0px 2px rgba(0, 0, 0, .05), 0px 1px 4px rgba(0, 0, 0, .08); 15 | } 16 | 17 | .layout-menu { 18 | margin: 0; 19 | padding: 0; 20 | list-style-type: none; 21 | 22 | .layout-root-menuitem { 23 | >.layout-menuitem-root-text { 24 | font-size: .857rem; 25 | text-transform: uppercase; 26 | font-weight: 700; 27 | color: var(--surface-900); 28 | margin: .75rem 0; 29 | } 30 | 31 | >a { 32 | display: none; 33 | } 34 | } 35 | 36 | a { 37 | user-select: none; 38 | 39 | &.active-menuitem { 40 | >.layout-submenu-toggler { 41 | transform: rotate(-180deg); 42 | } 43 | } 44 | } 45 | 46 | li.active-menuitem { 47 | >a { 48 | .layout-submenu-toggler { 49 | transform: rotate(-180deg); 50 | } 51 | } 52 | } 53 | 54 | ul { 55 | margin: 0; 56 | padding: 0; 57 | list-style-type: none; 58 | 59 | a { 60 | display: flex; 61 | align-items: center; 62 | position: relative; 63 | outline: 0 none; 64 | color: var(--text-color); 65 | cursor: pointer; 66 | padding: .75rem 1rem; 67 | border-radius: $borderRadius; 68 | transition: background-color $transitionDuration, box-shadow $transitionDuration; 69 | 70 | .layout-menuitem-icon { 71 | margin-right: .5rem; 72 | } 73 | 74 | .layout-submenu-toggler { 75 | font-size: 75%; 76 | margin-left: auto; 77 | transition: transform $transitionDuration; 78 | } 79 | 80 | &.active-route { 81 | font-weight: 700; 82 | color: var(--primary-color); 83 | } 84 | 85 | &:hover { 86 | background-color: var(--surface-hover); 87 | } 88 | 89 | &:focus { 90 | @include focused-inset(); 91 | } 92 | } 93 | 94 | ul { 95 | overflow: hidden; 96 | border-radius: $borderRadius; 97 | 98 | li { 99 | a { 100 | margin-left: 1rem; 101 | } 102 | 103 | li { 104 | a { 105 | margin-left: 2rem; 106 | } 107 | 108 | li { 109 | a { 110 | margin-left: 2.5rem; 111 | } 112 | 113 | li { 114 | a { 115 | margin-left: 3rem; 116 | } 117 | 118 | li { 119 | a { 120 | margin-left: 3.5rem; 121 | } 122 | 123 | li { 124 | a { 125 | margin-left: 4rem; 126 | } 127 | } 128 | } 129 | } 130 | } 131 | } 132 | } 133 | } 134 | } 135 | } 136 | 137 | #restart { 138 | padding: 2rem 1rem; 139 | display: block; 140 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/styles/layout/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin focused() { 2 | outline: 0 none; 3 | outline-offset: 0; 4 | transition: box-shadow .2s; 5 | box-shadow: var(--focus-ring); 6 | } 7 | 8 | @mixin focused-inset() { 9 | outline: 0 none; 10 | outline-offset: 0; 11 | transition: box-shadow .2s; 12 | box-shadow: inset var(--focus-ring); 13 | } 14 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/styles/layout/_preloading.scss: -------------------------------------------------------------------------------- 1 | .preloader { 2 | position: fixed; 3 | z-index: 999999; 4 | background: #edf1f5; 5 | width: 100%; 6 | height: 100%; 7 | } 8 | 9 | .preloader-content { 10 | border: 0 solid transparent; 11 | border-radius: 50%; 12 | width: 150px; 13 | height: 150px; 14 | position: absolute; 15 | top: calc(50vh - 75px); 16 | left: calc(50vw - 75px); 17 | } 18 | 19 | .preloader-content:before, 20 | .preloader-content:after { 21 | content: ''; 22 | border: 1em solid var(--primary-color); 23 | border-radius: 50%; 24 | width: inherit; 25 | height: inherit; 26 | position: absolute; 27 | top: 0; 28 | left: 0; 29 | animation: loader 2s linear infinite; 30 | opacity: 0; 31 | } 32 | 33 | .preloader-content:before { 34 | animation-delay: 0.5s; 35 | } 36 | 37 | @keyframes loader { 38 | 0% { 39 | transform: scale(0); 40 | opacity: 0; 41 | } 42 | 43 | 50% { 44 | opacity: 1; 45 | } 46 | 47 | 100% { 48 | transform: scale(1); 49 | opacity: 0; 50 | } 51 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/styles/layout/_responsive.scss: -------------------------------------------------------------------------------- 1 | @media screen and (min-width: 1960px) { 2 | .layout-main, .landing-wrapper { 3 | width: 1504px; 4 | margin-left: auto !important; 5 | margin-right: auto !important; 6 | } 7 | 8 | } 9 | 10 | @media (min-width: 992px) { 11 | .layout-wrapper { 12 | &.layout-overlay { 13 | .layout-main-container { 14 | margin-left: 0; 15 | padding-left: 2rem; 16 | } 17 | 18 | .layout-sidebar { 19 | transform: translateX(-100%); 20 | left: 0; 21 | top: 0; 22 | height: 100vh; 23 | border-top-left-radius: 0; 24 | border-bottom-left-radius: 0; 25 | } 26 | 27 | &.layout-overlay-active { 28 | .layout-sidebar { 29 | transform: translateX(0); 30 | } 31 | } 32 | } 33 | 34 | &.layout-static { 35 | .layout-main-container { 36 | margin-left: 300px; 37 | } 38 | 39 | &.layout-static-inactive { 40 | .layout-sidebar { 41 | transform: translateX(-100%); 42 | left: 0; 43 | } 44 | 45 | .layout-main-container { 46 | margin-left: 0; 47 | padding-left: 2rem; 48 | } 49 | } 50 | } 51 | 52 | .layout-mask { 53 | display: none; 54 | } 55 | } 56 | } 57 | 58 | @media (max-width: 991px) { 59 | .blocked-scroll { 60 | overflow: hidden; 61 | } 62 | 63 | .layout-wrapper { 64 | .layout-main-container { 65 | margin-left: 0; 66 | padding-left: 2rem; 67 | } 68 | 69 | .layout-sidebar { 70 | transform: translateX(-100%); 71 | left: 0; 72 | top: 0; 73 | height: 100vh; 74 | border-top-left-radius: 0; 75 | border-bottom-left-radius: 0; 76 | } 77 | 78 | .layout-mask { 79 | display: none; 80 | position: fixed; 81 | top: 0; 82 | left: 0; 83 | z-index: 998; 84 | width: 100%; 85 | height: 100%; 86 | background-color: var(--maskbg); 87 | } 88 | 89 | &.layout-mobile-active { 90 | .layout-sidebar { 91 | transform: translateX(0); 92 | } 93 | 94 | .layout-mask { 95 | display: block; 96 | animation: fadein $transitionDuration; 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/styles/layout/_topbar.scss: -------------------------------------------------------------------------------- 1 | .layout-topbar { 2 | position: fixed; 3 | height: 5rem; 4 | z-index: 997; 5 | left: 0; 6 | top: 0; 7 | width: 100%; 8 | padding: 0 2rem; 9 | background-color: var(--surface-card); 10 | transition: left $transitionDuration; 11 | display: flex; 12 | align-items: center; 13 | box-shadow: 0px 3px 5px rgba(0,0,0,.02), 0px 0px 2px rgba(0,0,0,.05), 0px 1px 4px rgba(0,0,0,.08); 14 | 15 | .layout-topbar-logo { 16 | display: flex; 17 | align-items: center; 18 | color: var(--surface-900); 19 | font-size: 1.5rem; 20 | font-weight: 500; 21 | width: 300px; 22 | border-radius: 12px; 23 | 24 | img { 25 | height: 2.5rem; 26 | margin-right: .5rem; 27 | } 28 | 29 | &:focus { 30 | @include focused(); 31 | } 32 | } 33 | 34 | .layout-topbar-button { 35 | display: inline-flex; 36 | justify-content: center; 37 | align-items: center; 38 | position: relative; 39 | color: var(--text-color-secondary); 40 | border-radius: 50%; 41 | width: 3rem; 42 | height: 3rem; 43 | cursor: pointer; 44 | transition: background-color $transitionDuration; 45 | 46 | &:hover { 47 | color: var(--text-color); 48 | background-color: var(--surface-hover); 49 | } 50 | 51 | &:focus { 52 | @include focused(); 53 | } 54 | 55 | i { 56 | font-size: 1.5rem; 57 | } 58 | 59 | span { 60 | font-size: 1rem; 61 | display: none; 62 | } 63 | } 64 | 65 | .layout-menu-button { 66 | margin-left: 2rem; 67 | } 68 | 69 | .layout-topbar-menu-button { 70 | display: none; 71 | 72 | i { 73 | font-size: 1.25rem; 74 | } 75 | } 76 | 77 | .layout-topbar-menu { 78 | margin: 0 0 0 auto; 79 | padding: 0; 80 | list-style: none; 81 | display: flex; 82 | 83 | .layout-topbar-button { 84 | margin-left: 1rem; 85 | } 86 | } 87 | } 88 | 89 | @media (max-width: 991px) { 90 | .layout-topbar { 91 | justify-content: space-between; 92 | 93 | .layout-topbar-logo { 94 | width: auto; 95 | order: 2; 96 | } 97 | 98 | .layout-menu-button { 99 | margin-left: 0; 100 | order: 1; 101 | } 102 | 103 | .layout-topbar-menu-button { 104 | display: inline-flex; 105 | margin-left: 0; 106 | order: 3; 107 | } 108 | 109 | .layout-topbar-menu { 110 | margin-left: 0; 111 | position: absolute; 112 | flex-direction: column; 113 | background-color: var(--surface-overlay); 114 | box-shadow: 0px 3px 5px rgba(0,0,0,.02), 0px 0px 2px rgba(0,0,0,.05), 0px 1px 4px rgba(0,0,0,.08); 115 | border-radius: 12px; 116 | padding: 1rem; 117 | right: 2rem; 118 | top: 5rem; 119 | min-width: 15rem; 120 | display: none; 121 | -webkit-animation: scalein 0.15s linear; 122 | animation: scalein 0.15s linear; 123 | 124 | &.layout-topbar-menu-mobile-active { 125 | display: block 126 | } 127 | 128 | .layout-topbar-button { 129 | margin-left: 0; 130 | display: flex; 131 | width: 100%; 132 | height: auto; 133 | justify-content: flex-start; 134 | border-radius: 12px; 135 | padding: 1rem; 136 | 137 | i { 138 | font-size: 1rem; 139 | margin-right: .5rem; 140 | } 141 | 142 | span { 143 | font-weight: medium; 144 | display: block; 145 | } 146 | } 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/styles/layout/_typography.scss: -------------------------------------------------------------------------------- 1 | h1, h2, h3, h4, h5, h6 { 2 | margin: 1.5rem 0 1rem 0; 3 | font-family: inherit; 4 | font-weight: 500; 5 | line-height: 1.2; 6 | color: var(--surface-900); 7 | 8 | &:first-child { 9 | margin-top: 0; 10 | } 11 | } 12 | 13 | h1 { 14 | font-size: 2.5rem; 15 | } 16 | 17 | h2 { 18 | font-size: 2rem; 19 | } 20 | 21 | h3 { 22 | font-size: 1.75rem; 23 | } 24 | 25 | h4 { 26 | font-size: 1.5rem; 27 | } 28 | 29 | h5 { 30 | font-size: 1.25rem; 31 | } 32 | 33 | h6 { 34 | font-size: 1rem; 35 | } 36 | 37 | mark { 38 | background: #FFF8E1; 39 | padding: .25rem .4rem; 40 | border-radius: $borderRadius; 41 | font-family: monospace; 42 | } 43 | 44 | blockquote { 45 | margin: 1rem 0; 46 | padding: 0 2rem; 47 | border-left: 4px solid #90A4AE; 48 | } 49 | 50 | hr { 51 | border-top: solid var(--surface-border); 52 | border-width: 1px 0 0 0; 53 | margin: 1rem 0; 54 | } 55 | 56 | p { 57 | margin: 0 0 1rem 0; 58 | line-height: 1.5; 59 | 60 | &:last-child { 61 | margin-bottom: 0; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/styles/layout/_utils.scss: -------------------------------------------------------------------------------- 1 | .card { 2 | background: var(--surface-card); 3 | border: 1px solid var(--surface-border); 4 | padding: 2rem; 5 | margin-bottom: 2rem; 6 | box-shadow: var(--card-shadow); 7 | border-radius: $borderRadius; 8 | 9 | &:last-child { 10 | margin-bottom: 0; 11 | } 12 | } 13 | 14 | .p-toast { 15 | &.p-toast-top-right, 16 | &.p-toast-top-left, 17 | &.p-toast-top-center { 18 | top: 100px; 19 | } 20 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/styles/layout/_variables.scss: -------------------------------------------------------------------------------- 1 | /* General */ 2 | $scale:14px; /* main font size */ 3 | $borderRadius:12px; /* border radius of layout element e.g. card, sidebar */ 4 | $transitionDuration:.2s; /* transition duration of layout elements e.g. sidebar, overlay menus */ 5 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/layout/styles/layout/layout.scss: -------------------------------------------------------------------------------- 1 | @import './_variables'; 2 | @import "./_mixins"; 3 | @import "./_preloading"; 4 | @import "./_main"; 5 | @import "./_topbar"; 6 | @import "./_menu"; 7 | @import "./_config"; 8 | @import "./_content"; 9 | @import "./_footer"; 10 | @import "./_responsive"; 11 | @import "./_utils"; 12 | @import "./_typography"; -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/pipes/ansi.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { ANSIPipe } from './ansi.pipe'; 2 | 3 | describe('ANSIPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ANSIPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/pipes/ansi.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'ANSI', 5 | pure: true 6 | }) 7 | export class ANSIPipe implements PipeTransform { 8 | 9 | transform(value: string): string { 10 | return value.slice(9, value.length - 5); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/pipes/date-ago.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { DateAgoPipe } from './date-ago.pipe'; 2 | 3 | describe('DateAgoPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new DateAgoPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/pipes/date-ago.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'dateAgo', 5 | pure: true 6 | }) 7 | export class DateAgoPipe implements PipeTransform { 8 | 9 | transform(value: any, args?: any): any { 10 | if (value) { 11 | value = new Date().getTime() - value * 1000; 12 | const seconds = Math.floor((+new Date() - +new Date(value)) / 1000); 13 | if (seconds < 29) // less than 30 seconds ago will show as 'Just now' 14 | return 'Just now'; 15 | const intervals: { [key: string]: number } = { 16 | 'year': 31536000, 17 | 'month': 2592000, 18 | 'week': 604800, 19 | 'day': 86400, 20 | 'hour': 3600, 21 | 'minute': 60, 22 | 'second': 1 23 | }; 24 | let counter; 25 | for (const i in intervals) { 26 | counter = Math.floor(seconds / intervals[i]); 27 | if (counter > 0) 28 | if (counter === 1) { 29 | return counter + ' ' + i + ''; // singular (1 day ago) 30 | } else { 31 | return counter + ' ' + i + 's'; // plural (2 days ago) 32 | } 33 | } 34 | } 35 | return value; 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/pipes/hash-suffix.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { HashSuffixPipe } from './hash-suffix.pipe'; 2 | 3 | describe('HashSuffixPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new HashSuffixPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/pipes/hash-suffix.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'hashSuffix' 5 | }) 6 | export class HashSuffixPipe implements PipeTransform { 7 | 8 | private static _this = new HashSuffixPipe(); 9 | 10 | public static transform(value: number): string { 11 | return this._this.transform(value); 12 | } 13 | 14 | public transform(value: number): string { 15 | 16 | if (value == null || value < 0) { 17 | return '0'; 18 | } 19 | 20 | const suffixes = [' H/s', ' KH/s', ' MH/s', ' GH/s', ' TH/s', ' PH/s', ' EH/s']; 21 | 22 | let power = Math.floor(Math.log10(value) / 3); 23 | if (power < 0) { 24 | power = 0; 25 | } 26 | const scaledValue = value / Math.pow(1000, power); 27 | const suffix = suffixes[power]; 28 | 29 | return scaledValue.toFixed(1) + suffix; 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/prime-ng.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { ButtonModule } from 'primeng/button'; 3 | import { ChartModule } from 'primeng/chart'; 4 | import { CheckboxModule } from 'primeng/checkbox'; 5 | import { DropdownModule } from 'primeng/dropdown'; 6 | import { FileUploadModule } from 'primeng/fileupload'; 7 | import { InputGroupModule } from 'primeng/inputgroup'; 8 | import { InputGroupAddonModule } from 'primeng/inputgroupaddon'; 9 | import { InputTextModule } from 'primeng/inputtext'; 10 | import { KnobModule } from 'primeng/knob'; 11 | import { SidebarModule } from 'primeng/sidebar'; 12 | import { SliderModule } from 'primeng/slider'; 13 | 14 | const primeNgModules = [ 15 | SidebarModule, 16 | InputTextModule, 17 | CheckboxModule, 18 | DropdownModule, 19 | SliderModule, 20 | ButtonModule, 21 | FileUploadModule, 22 | KnobModule, 23 | ChartModule, 24 | InputGroupModule, 25 | InputGroupAddonModule 26 | ]; 27 | 28 | @NgModule({ 29 | imports: [ 30 | ...primeNgModules 31 | ], 32 | exports: [ 33 | ...primeNgModules 34 | ], 35 | }) 36 | export class PrimeNGModule { } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/services/github-update.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { GithubUpdateService } from './github-update.service'; 4 | 5 | describe('GithubUpdateService', () => { 6 | let service: GithubUpdateService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(GithubUpdateService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/services/github-update.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { Observable } from 'rxjs'; 4 | import { map } from 'rxjs/operators'; 5 | 6 | 7 | interface GithubRelease { 8 | id: number; 9 | tag_name: string; 10 | name: string; 11 | prerelease: boolean; 12 | } 13 | 14 | @Injectable({ 15 | providedIn: 'root' 16 | }) 17 | export class GithubUpdateService { 18 | 19 | constructor( 20 | private httpClient: HttpClient 21 | ) { } 22 | 23 | 24 | public getReleases(): Observable { 25 | return this.httpClient.get( 26 | 'https://api.github.com/repos/bitaxeorg/esp-miner-multichip/releases' 27 | ).pipe( 28 | map((releases: GithubRelease[]) => releases.filter((release: GithubRelease) => !release.prerelease)) 29 | ); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/services/loading.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { LoadingService } from './loading.service'; 4 | 5 | describe('LoadingService', () => { 6 | let service: LoadingService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(LoadingService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/services/loading.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { BehaviorSubject, Observable } from 'rxjs'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class LoadingService { 8 | 9 | public loading$: BehaviorSubject = new BehaviorSubject(false); 10 | 11 | constructor() { } 12 | 13 | public lockUIUntilComplete() { 14 | return (source: Observable): Observable => { 15 | return new Observable(subscriber => { 16 | this.loading$.next(true); 17 | source.subscribe({ 18 | next: (value) => { 19 | subscriber.next(value); 20 | }, 21 | error: (err) => { 22 | subscriber.next(err); 23 | }, 24 | complete: () => { 25 | this.loading$.next(false); 26 | subscriber.complete(); 27 | } 28 | }) 29 | }); 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/services/system.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { SystemService } from './system.service'; 4 | 5 | describe('SystemService', () => { 6 | let service: SystemService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(SystemService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/services/system.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient, HttpEvent } from '@angular/common/http'; 2 | import { Injectable } from '@angular/core'; 3 | import { delay, Observable, of } from 'rxjs'; 4 | import { eASICModel } from 'src/models/enum/eASICModel'; 5 | import { ISystemInfo } from 'src/models/ISystemInfo'; 6 | import { IHistory } from 'src/models/IHistory'; 7 | import { environment } from '../../environments/environment'; 8 | 9 | const defaultInfo: ISystemInfo = { 10 | power: 11.670000076293945, 11 | voltage: 5208.75, 12 | current: 2237.5, 13 | temp: 60, 14 | vrTemp: 45, 15 | hashRateTimestamp: 1724398272483, 16 | hashRate: 2775.61417065818, 17 | hashRate_10m: 475, 18 | hashRate_1h: 475, 19 | hashRate_1d: 475, 20 | bestDiff: "0", 21 | bestSessionDiff: "0", 22 | freeHeap: 200504, 23 | coreVoltage: 1200, 24 | coreVoltageActual: 1200, 25 | hostname: "Bitaxe", 26 | ssid: "default", 27 | wifiPass: "password", 28 | wifiStatus: "Connected!", 29 | sharesAccepted: 1, 30 | sharesRejected: 0, 31 | uptimeSeconds: 38, 32 | asicCount: 1, 33 | smallCoreCount: 672, 34 | ASICModel: eASICModel.BM1366, 35 | stratumURL: "public-pool.io", 36 | stratumPort: 21496, 37 | fallbackStratumURL: "test.public-pool.io", 38 | fallbackStratumPort: 21497, 39 | stratumUser: "bc1q99n3pu025yyu0jlywpmwzalyhm36tg5u37w20d.bitaxe-U1", 40 | fallbackStratumUser: "bc1q99n3pu025yyu0jlywpmwzalyhm36tg5u37w20d.bitaxe-U1", 41 | frequency: 485, 42 | version: "2.0", 43 | boardVersion: "204", 44 | flipscreen: 1, 45 | invertscreen: 0, 46 | invertfanpolarity: 1, 47 | autofanspeed: 1, 48 | fanspeed: 100, 49 | fanrpm: 0, 50 | autoscreenoff: 0, 51 | 52 | boardtemp1: 30, 53 | boardtemp2: 40, 54 | overheat_mode: 0, 55 | history: { 56 | hashrate_10m: [], 57 | hashrate_1h: [], 58 | hashrate_1d: [], 59 | timestamps: [], 60 | timestampBase: 0 61 | } 62 | } 63 | 64 | 65 | @Injectable({ 66 | providedIn: 'root' 67 | }) 68 | export class SystemService { 69 | 70 | constructor( 71 | private httpClient: HttpClient 72 | ) { } 73 | 74 | static defaultInfo() { 75 | return defaultInfo; 76 | } 77 | 78 | public getInfo(ts: number, uri: string = ''): Observable { 79 | if (environment.production) { 80 | return this.httpClient.get(`${uri}/api/system/info?ts=${ts}`) as Observable; 81 | } else { 82 | return of(defaultInfo).pipe(delay(1000)); 83 | } 84 | } 85 | 86 | 87 | public getHistoryLen(): Observable { 88 | return this.httpClient.get('/api/history/len'); 89 | } 90 | 91 | public getHistoryData(ts: number): Observable { 92 | return this.httpClient.get(`/api/history/data?ts=${ts}`); 93 | } 94 | 95 | 96 | public restart(uri: string = '') { 97 | return this.httpClient.post(`${uri}/api/system/restart`, {}); 98 | } 99 | 100 | public updateSystem(uri: string = '', update: any) { 101 | return this.httpClient.patch(`${uri}/api/system`, update); 102 | } 103 | 104 | 105 | 106 | private otaUpdate(file: File | Blob, url: string) { 107 | return new Observable>((subscriber) => { 108 | const reader = new FileReader(); 109 | 110 | reader.onload = (event: any) => { 111 | const fileContent = event.target.result; 112 | 113 | return this.httpClient.post(url, fileContent, { 114 | reportProgress: true, 115 | observe: 'events', 116 | responseType: 'text', // Specify the response type 117 | headers: { 118 | 'Content-Type': 'application/octet-stream', // Set the content type 119 | }, 120 | }).subscribe({ 121 | next: (e) => { 122 | 123 | }, 124 | error: (err) => { 125 | subscriber.error(err) 126 | }, 127 | complete: () => { 128 | subscriber.next() 129 | subscriber.complete(); 130 | } 131 | }); 132 | }; 133 | reader.readAsArrayBuffer(file); 134 | }); 135 | } 136 | 137 | public performOTAUpdate(file: File | Blob) { 138 | return this.otaUpdate(file, `/api/system/OTA`); 139 | } 140 | public performWWWOTAUpdate(file: File | Blob) { 141 | return this.otaUpdate(file, `/api/system/OTAWWW`); 142 | } 143 | 144 | 145 | public getSwarmInfo(uri: string = ''): Observable<{ ip: string }[]> { 146 | return this.httpClient.get(`${uri}/api/swarm/info`) as Observable<{ ip: string }[]>; 147 | } 148 | 149 | public updateSwarm(uri: string = '', swarmConfig: any) { 150 | return this.httpClient.patch(`${uri}/api/swarm`, swarmConfig); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/services/web-socket.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { WebSocketService } from './web-socket.service'; 4 | 5 | describe('WebSocketService', () => { 6 | let service: WebSocketService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(WebSocketService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/app/services/web-socket.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { webSocket, WebSocketSubject } from 'rxjs/webSocket'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class WebsocketService { 8 | 9 | public ws$: WebSocketSubject; 10 | 11 | constructor() { 12 | this.ws$ = webSocket({ 13 | url: `ws://${window.location.host}/api/ws`, 14 | deserializer: (e: MessageEvent) => { return e.data } 15 | }); 16 | } 17 | 18 | 19 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitaxeorg/esp-miner-multichip/2f85fd308ca860859070361004151107c3d1191c/main/http_server/axe-os/src/assets/.gitkeep -------------------------------------------------------------------------------- /main/http_server/axe-os/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: false 3 | }; 4 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitaxeorg/esp-miner-multichip/2f85fd308ca860859070361004151107c3d1191c/main/http_server/axe-os/src/favicon.ico -------------------------------------------------------------------------------- /main/http_server/axe-os/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | AxeOS 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/main.ts: -------------------------------------------------------------------------------- 1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 2 | 3 | import { AppModule } from './app/app.module'; 4 | 5 | 6 | platformBrowserDynamic().bootstrapModule(AppModule) 7 | .catch(err => console.error(err)); 8 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/models/IHistory.ts: -------------------------------------------------------------------------------- 1 | import { eASICModel } from './enum/eASICModel'; 2 | 3 | export interface IHistory { 4 | 5 | hashrate_10m: number[], 6 | hashrate_1h: number[], 7 | hashrate_1d: number[], 8 | timestamps: number[], 9 | timestampBase: number 10 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/src/models/ISystemInfo.ts: -------------------------------------------------------------------------------- 1 | import { eASICModel } from './enum/eASICModel'; 2 | import { IHistory } from 'src/models/IHistory'; 3 | 4 | export interface ISystemInfo { 5 | 6 | flipscreen: number; 7 | invertscreen: number; 8 | autoscreenoff: number; 9 | power: number, 10 | voltage: number, 11 | current: number, 12 | temp: number, 13 | vrTemp: number, 14 | hashRateTimestamp: number, 15 | hashRate: number, 16 | hashRate_10m: number, 17 | hashRate_1h: number, 18 | hashRate_1d: number, 19 | bestDiff: string, 20 | bestSessionDiff: string, 21 | freeHeap: number, 22 | coreVoltage: number, 23 | hostname: string, 24 | ssid: string, 25 | wifiPass: string, 26 | wifiStatus: string, 27 | sharesAccepted: number, 28 | sharesRejected: number, 29 | uptimeSeconds: number, 30 | asicCount: number, 31 | smallCoreCount: number, 32 | ASICModel: eASICModel, 33 | stratumURL: string, 34 | stratumPort: number, 35 | fallbackStratumURL: string, 36 | fallbackStratumPort: number, 37 | stratumUser: string, 38 | fallbackStratumUser: string, 39 | frequency: number, 40 | version: string, 41 | boardVersion: string, 42 | invertfanpolarity: number, 43 | autofanspeed: number, 44 | fanspeed: number, 45 | fanrpm: number, 46 | coreVoltageActual: number, 47 | 48 | boardtemp1?: number, 49 | boardtemp2?: number, 50 | overheat_mode: number, 51 | 52 | history: IHistory 53 | } 54 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/models/enum/eASICModel.ts: -------------------------------------------------------------------------------- 1 | export enum eASICModel { 2 | BM1366 = 'BM1366' 3 | } 4 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/models/enum/eDeviceModel.ts: -------------------------------------------------------------------------------- 1 | export enum eDeviceModel { 2 | hex = 'hex' 3 | } 4 | -------------------------------------------------------------------------------- /main/http_server/axe-os/src/styles.scss: -------------------------------------------------------------------------------- 1 | @import "app/layout/styles/layout/layout.scss"; 2 | @import "app/layout/styles/theme/vela-blue/theme.css"; 3 | 4 | @import "../node_modules/primeicons/primeicons.css"; 5 | @import "../node_modules/primeng/resources/primeng.min.css"; 6 | 7 | @import "../node_modules/primeflex/primeflex.min.css"; 8 | 9 | 10 | /* You can add global styles to this file, and also import other style files */ 11 | p-chart>div { 12 | position: relative; 13 | min-height: 40vh; 14 | } 15 | 16 | .card { 17 | &.chart { 18 | padding: 10px; 19 | } 20 | } -------------------------------------------------------------------------------- /main/http_server/axe-os/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /main/http_server/axe-os/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "ES2022", 20 | "module": "ES2022", 21 | "useDefineForClassFields": false, 22 | "lib": [ 23 | "ES2022", 24 | "dom" 25 | ] 26 | }, 27 | "angularCompilerOptions": { 28 | "enableI18nLegacyMessageIdFormat": false, 29 | "strictInjectionParameters": true, 30 | "strictInputAccessModifiers": true, 31 | "strictTemplates": true 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /main/http_server/axe-os/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "include": [ 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /main/http_server/http_server.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_SERVER_H_ 2 | #define HTTP_SERVER_H_ 3 | #include 4 | 5 | esp_err_t start_rest_server(void *pvParameters); 6 | 7 | #endif -------------------------------------------------------------------------------- /main/http_server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "http_server", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": {} 6 | } 7 | -------------------------------------------------------------------------------- /main/http_server/recovery_page.h: -------------------------------------------------------------------------------- 1 | #ifndef RECOVERY_PAGE 2 | #define RECOVERY_PAGE 3 | 4 | const char recovery_page[] = "" 5 | "" 12 | "" 13 | "AxeOS Recovery" 14 | "" 15 | "" 16 | "
"
17 | "                      ____   _____\n"
18 | "     /\\              / __ \\ / ____|\n"
19 | "    /  \\   __  _____| |  | | (___\n"
20 | "   / /\\ \\  \\ \\/ / _ \\ |  | |\\___ \\\n"
21 | "  / ____ \\  >  <  __/ |__| |____) |\n"
22 | " /_/___ \\_\\/_/\\_\\___|\\____/|_____/\n"
23 | " |  __ \\\n"
24 | " | |__) |___  ___ _____   _____ _ __ _   _\n"
25 | " |  _  // _ \\/ __/ _ \\ \\ / / _ \\ '__| | | |\n"
26 | " | | \\ \\  __/ (_| (_) \\ V /  __/ |  | |_| |\n"
27 | " |_|  \\_\\___|\\___\\___/ \\_/ \\___|_|   \\__, |\n"
28 | "                                      __/ |\n"
29 | "                                     |___/\n"
30 | "
" 31 | "

Please upload www.bin to recover AxeOS

" 32 | "

After clicking upload, please wait 60 seconds
" 33 | "DO NOT restart the device until response is received

" 34 | "
" 35 | "" 36 | "" 37 | "
" 38 | "

Response:
" 39 | "" 40 | "" 76 | "" 77 | ""; 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /main/i2c_master.c: -------------------------------------------------------------------------------- 1 | #include "i2c_master.h" 2 | 3 | #define I2C_MASTER_SCL_IO 48 /*!< GPIO number used for I2C master clock */ 4 | #define I2C_MASTER_SDA_IO 47 /*!< GPIO number used for I2C master data */ 5 | #define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency */ 6 | #define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ 7 | #define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ 8 | 9 | /** 10 | * @brief i2c master initialization 11 | */ 12 | esp_err_t i2c_master_init(void) 13 | { 14 | int i2c_master_port = I2C_MASTER_NUM; 15 | 16 | i2c_config_t conf = { 17 | .mode = I2C_MODE_MASTER, 18 | .sda_io_num = I2C_MASTER_SDA_IO, 19 | .scl_io_num = I2C_MASTER_SCL_IO, 20 | .sda_pullup_en = GPIO_PULLUP_ENABLE, 21 | .scl_pullup_en = GPIO_PULLUP_ENABLE, 22 | .master.clk_speed = I2C_MASTER_FREQ_HZ, 23 | }; 24 | 25 | i2c_param_config(i2c_master_port, &conf); 26 | 27 | return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); 28 | } 29 | 30 | /** 31 | * @brief i2c master delete 32 | */ 33 | esp_err_t i2c_master_delete(void) 34 | { 35 | return i2c_driver_delete(I2C_MASTER_NUM); 36 | } 37 | 38 | /** 39 | * @brief Read a sequence of I2C bytes 40 | */ 41 | esp_err_t i2c_master_register_read(uint8_t device_address, uint8_t reg_addr, uint8_t * data, size_t len) 42 | { 43 | return i2c_master_write_read_device(I2C_MASTER_NUM, device_address, ®_addr, 1, data, len, 44 | I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); 45 | } 46 | 47 | /** 48 | * @brief Write a byte to a I2C register 49 | */ 50 | esp_err_t i2c_master_register_write_byte(uint8_t device_address, uint8_t reg_addr, uint8_t data) 51 | { 52 | int ret; 53 | uint8_t write_buf[2] = {reg_addr, data}; 54 | 55 | ret = i2c_master_write_to_device(I2C_MASTER_NUM, device_address, write_buf, sizeof(write_buf), 56 | I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); 57 | 58 | return ret; 59 | } 60 | 61 | /** 62 | * @brief Write a word to a I2C register 63 | */ 64 | esp_err_t i2c_master_register_write_word(uint8_t device_address, uint8_t reg_addr, uint16_t data) 65 | { 66 | int ret; 67 | uint8_t write_buf[3] = {reg_addr, (data >> 8) & 0xFF, data & 0xFF}; 68 | 69 | ret = i2c_master_write_to_device(I2C_MASTER_NUM, device_address, write_buf, sizeof(write_buf), 70 | I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS); 71 | 72 | return ret; 73 | } 74 | -------------------------------------------------------------------------------- /main/i2c_master.h: -------------------------------------------------------------------------------- 1 | #ifndef I2C_MASTER_H_ 2 | #define I2C_MASTER_H_ 3 | 4 | #include "driver/i2c.h" 5 | 6 | #define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */ 7 | #define I2C_MASTER_TIMEOUT_MS 1000 8 | 9 | esp_err_t i2c_master_init(void); 10 | esp_err_t i2c_master_delete(void); 11 | esp_err_t i2c_master_register_read(uint8_t device_address, uint8_t reg_addr, uint8_t * data, size_t len); 12 | esp_err_t i2c_master_register_write_byte(uint8_t device_address, uint8_t reg_addr, uint8_t data); 13 | esp_err_t i2c_master_register_write_word(uint8_t device_address, uint8_t reg_addr, uint16_t data); 14 | 15 | #endif /* I2C_MASTER_H_ */ 16 | -------------------------------------------------------------------------------- /main/main.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_H_ 2 | #define MAIN_H_ 3 | 4 | #include "connect.h" 5 | 6 | void MINER_set_wifi_status(wifi_status_t status, uint16_t retry_count); 7 | void self_test(void * pvParameters); 8 | 9 | #endif /* MAIN_H_ */ -------------------------------------------------------------------------------- /main/nvs_config.c: -------------------------------------------------------------------------------- 1 | #include "nvs_config.h" 2 | #include "esp_log.h" 3 | #include "nvs.h" 4 | #include 5 | 6 | #define NVS_CONFIG_NAMESPACE "main" 7 | 8 | static const char * TAG = "nvs_config"; 9 | 10 | char * nvs_config_get_string(const char * key, const char * default_value) 11 | { 12 | nvs_handle handle; 13 | esp_err_t err; 14 | err = nvs_open(NVS_CONFIG_NAMESPACE, NVS_READONLY, &handle); 15 | if (err != ESP_OK) { 16 | return strdup(default_value); 17 | } 18 | 19 | size_t size = 0; 20 | err = nvs_get_str(handle, key, NULL, &size); 21 | 22 | if (err != ESP_OK) { 23 | nvs_close(handle); 24 | return strdup(default_value); 25 | } 26 | 27 | char * out = malloc(size); 28 | err = nvs_get_str(handle, key, out, &size); 29 | 30 | if (err != ESP_OK) { 31 | free(out); 32 | nvs_close(handle); 33 | return strdup(default_value); 34 | } 35 | 36 | nvs_close(handle); 37 | return out; 38 | } 39 | 40 | void nvs_config_set_string(const char * key, const char * value) 41 | { 42 | 43 | nvs_handle handle; 44 | esp_err_t err; 45 | err = nvs_open(NVS_CONFIG_NAMESPACE, NVS_READWRITE, &handle); 46 | if (err != ESP_OK) { 47 | ESP_LOGW(TAG, "Could not open nvs"); 48 | return; 49 | } 50 | 51 | err = nvs_set_str(handle, key, value); 52 | if (err != ESP_OK) { 53 | ESP_LOGW(TAG, "Could not write nvs key: %s, value: %s", key, value); 54 | 55 | } 56 | 57 | nvs_close(handle); 58 | 59 | } 60 | 61 | uint16_t nvs_config_get_u16(const char * key, const uint16_t default_value) 62 | { 63 | nvs_handle handle; 64 | esp_err_t err; 65 | err = nvs_open(NVS_CONFIG_NAMESPACE, NVS_READONLY, &handle); 66 | if (err != ESP_OK) { 67 | return default_value; 68 | } 69 | 70 | uint16_t out; 71 | err = nvs_get_u16(handle, key, &out); 72 | nvs_close(handle); 73 | 74 | if (err != ESP_OK) { 75 | return default_value; 76 | } 77 | return out; 78 | } 79 | 80 | void nvs_config_set_u16(const char * key, const uint16_t value) 81 | { 82 | 83 | nvs_handle handle; 84 | esp_err_t err; 85 | err = nvs_open(NVS_CONFIG_NAMESPACE, NVS_READWRITE, &handle); 86 | if (err != ESP_OK) { 87 | ESP_LOGW(TAG, "Could not open nvs"); 88 | return; 89 | } 90 | 91 | err = nvs_set_u16(handle, key, value); 92 | if (err != ESP_OK) { 93 | ESP_LOGW(TAG, "Could not write nvs key: %s, value: %u", key, value); 94 | 95 | } 96 | 97 | nvs_close(handle); 98 | 99 | } 100 | 101 | uint64_t nvs_config_get_u64(const char * key, const uint64_t default_value) 102 | { 103 | nvs_handle handle; 104 | esp_err_t err; 105 | err = nvs_open(NVS_CONFIG_NAMESPACE, NVS_READONLY, &handle); 106 | if (err != ESP_OK) { 107 | return default_value; 108 | } 109 | 110 | uint64_t out; 111 | err = nvs_get_u64(handle, key, &out); 112 | 113 | if (err != ESP_OK) { 114 | nvs_close(handle); 115 | return default_value; 116 | } 117 | 118 | nvs_close(handle); 119 | return out; 120 | } 121 | 122 | void nvs_config_set_u64(const char * key, const uint64_t value) 123 | { 124 | 125 | nvs_handle handle; 126 | esp_err_t err; 127 | err = nvs_open(NVS_CONFIG_NAMESPACE, NVS_READWRITE, &handle); 128 | if (err != ESP_OK) { 129 | ESP_LOGW(TAG, "Could not open nvs"); 130 | return; 131 | } 132 | 133 | err = nvs_set_u64(handle, key, value); 134 | if (err != ESP_OK) { 135 | ESP_LOGW(TAG, "Could not write nvs key: %s, value: %llu", key, value); 136 | 137 | } 138 | nvs_close(handle); 139 | 140 | } 141 | -------------------------------------------------------------------------------- /main/nvs_config.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_NVS_CONFIG_H 2 | #define MAIN_NVS_CONFIG_H 3 | 4 | #include 5 | 6 | // Max length 15 7 | 8 | #define NVS_CONFIG_WIFI_SSID "wifissid" 9 | #define NVS_CONFIG_WIFI_PASS "wifipass" 10 | #define NVS_CONFIG_HOSTNAME "hostname" 11 | #define NVS_CONFIG_STRATUM_URL "stratumurl" 12 | #define NVS_CONFIG_STRATUM_PORT "stratumport" 13 | #define NVS_CONFIG_FALLBACK_STRATUM_URL "fbstratumurl" 14 | #define NVS_CONFIG_FALLBACK_STRATUM_PORT "fbstratumport" 15 | #define NVS_CONFIG_STRATUM_USER "stratumuser" 16 | #define NVS_CONFIG_STRATUM_PASS "stratumpass" 17 | #define NVS_CONFIG_FALLBACK_STRATUM_USER "fbstratumuser" 18 | #define NVS_CONFIG_FALLBACK_STRATUM_PASS "fbstratumpass" 19 | #define NVS_CONFIG_ASIC_FREQ "asicfrequency" 20 | #define NVS_CONFIG_ASIC_VOLTAGE "asicvoltage" 21 | #define NVS_CONFIG_ASIC_MODEL "asicmodel" 22 | #define NVS_CONFIG_DEVICE_MODEL "devicemodel" 23 | #define NVS_CONFIG_BOARD_VERSION "boardversion" 24 | #define NVS_CONFIG_FLIP_SCREEN "flipscreen" 25 | #define NVS_CONFIG_INVERT_SCREEN "invertscreen" 26 | #define NVS_CONFIG_INVERT_FAN_POLARITY "invertfanpol" 27 | #define NVS_CONFIG_AUTO_FAN_SPEED "autofanspeed" 28 | #define NVS_CONFIG_FAN_SPEED "fanspeed" 29 | #define NVS_CONFIG_BEST_DIFF "bestdiff" 30 | #define NVS_CONFIG_SELF_TEST "selftest" 31 | #define NVS_CONFIG_OVERHEAT_MODE "overheat_mode" 32 | 33 | #define NVS_CONFIG_SWARM "swarmconfig" 34 | 35 | char * nvs_config_get_string(const char * key, const char * default_value); 36 | void nvs_config_set_string(const char * key, const char * default_value); 37 | uint16_t nvs_config_get_u16(const char * key, const uint16_t default_value); 38 | void nvs_config_set_u16(const char * key, const uint16_t value); 39 | uint64_t nvs_config_get_u64(const char * key, const uint64_t default_value); 40 | void nvs_config_set_u64(const char * key, const uint64_t value); 41 | 42 | #endif // MAIN_NVS_CONFIG_H 43 | -------------------------------------------------------------------------------- /main/oled.h: -------------------------------------------------------------------------------- 1 | #ifndef OLED96_H 2 | #define OLED96_H 3 | // 4 | // OLED96 5 | // Library for accessing the 0.96" SSD1306 128x64 OLED display 6 | // Written by Larry Bank (bitbank@pobox.com) 7 | // Copyright (c) 2017 BitBank Software, Inc. 8 | // Project started 1/15/2017 9 | // 10 | // OLED type for init function 11 | enum 12 | { 13 | OLED_128x32 = 1, 14 | OLED_128x64, 15 | OLED_132x64, 16 | OLED_64x32 17 | }; 18 | 19 | typedef enum 20 | { 21 | FONT_NORMAL = 0, // 8x8 22 | FONT_BIG, // 16x24 23 | FONT_SMALL // 6x8 24 | } FONTSIZE; 25 | 26 | // Initialize the OLED96 library for a specific I2C address 27 | // Optionally enable inverted or flipped mode 28 | // returns 0 for success, 1 for failure 29 | // 30 | bool OLED_init(void); 31 | 32 | // Turns off the display and closes the I2C handle 33 | void OLED_shutdown(void); 34 | 35 | // Fills the display with the byte pattern 36 | int OLED_fill(uint8_t ucPattern); 37 | 38 | // Write a text string to the display at x (column 0-127) and y (row 0-7) 39 | // bLarge = 0 - 8x8 font, bLarge = 1 - 16x24 font 40 | int OLED_writeString(int x, int y, const char *szText); 41 | 42 | // Sets a pixel to On (1) or Off (0) 43 | // Coordinate system is pixels, not text rows (0-127, 0-63) 44 | int OLED_setPixel(int x, int y, uint8_t ucPixel); 45 | 46 | // Sets the contrast (brightness) level of the display 47 | // Valid values are 0-255 where 0=off and 255=max brightness 48 | bool OLED_setContrast(uint8_t ucContrast); 49 | int OLED_clearLine(uint8_t); 50 | bool OLED_status(void); 51 | 52 | #endif // OLED96_H 53 | -------------------------------------------------------------------------------- /main/pmbus_commands.h: -------------------------------------------------------------------------------- 1 | 2 | /* Standard Core PMBus commands */ 3 | #define PMBUS_OPERATION 0x01 4 | #define PMBUS_ON_OFF_CONFIG 0x02 5 | #define PMBUS_CLEAR_FAULTS 0x03 6 | #define PMBUS_PHASE 0x04 7 | #define PMBUS_WRITE_PROTECT 0x10 8 | #define PMBUS_STORE_USER_ALL 0x15 9 | #define PMBUS_RESTORE_USER_ALL 0x16 10 | #define PMBUS_CAPABILITY 0x19 11 | #define PMBUS_SMBALERT_MASK 0x1B 12 | #define PMBUS_VOUT_MODE 0x20 13 | #define PMBUS_VOUT_COMMAND 0x21 14 | #define PMBUS_VOUT_TRIM 0x22 15 | #define PMBUS_VOUT_MAX 0x24 16 | #define PMBUS_VOUT_MARGIN_HIGH 0x25 17 | #define PMBUS_VOUT_MARGIN_LOW 0x26 18 | #define PMBUS_VOUT_TRANSITION_RATE 0x27 19 | #define PMBUS_VOUT_SCALE_LOOP 0x29 20 | #define PMBUS_VOUT_MIN 0x2B 21 | #define PMBUS_FREQUENCY_SWITCH 0x33 22 | #define PMBUS_VIN_ON 0x35 23 | #define PMBUS_VIN_OFF 0x36 24 | #define PMBUS_INTERLEAVE 0x37 25 | #define PMBUS_IOUT_CAL_GAIN 0x38 26 | #define PMBUS_IOUT_CAL_OFFSET 0x39 27 | #define PMBUS_VOUT_OV_FAULT_LIMIT 0x40 28 | #define PMBUS_VOUT_OV_FAULT_RESPONSE 0x41 29 | #define PMBUS_VOUT_OV_WARN_LIMIT 0x42 30 | #define PMBUS_VOUT_UV_WARN_LIMIT 0x43 31 | #define PMBUS_VOUT_UV_FAULT_LIMIT 0x44 32 | #define PMBUS_VOUT_UV_FAULT_RESPONSE 0x45 33 | #define PMBUS_IOUT_OC_FAULT_LIMIT 0x46 34 | #define PMBUS_IOUT_OC_FAULT_RESPONSE 0x47 35 | #define PMBUS_IOUT_OC_WARN_LIMIT 0x4A 36 | #define PMBUS_OT_FAULT_LIMIT 0x4F 37 | #define PMBUS_OT_FAULT_RESPONSE 0x50 38 | #define PMBUS_OT_WARN_LIMIT 0x51 39 | #define PMBUS_VIN_OV_FAULT_LIMIT 0x55 40 | #define PMBUS_VIN_OV_FAULT_RESPONSE 0x56 41 | #define PMBUS_VIN_UV_WARN_LIMIT 0x58 42 | #define PMBUS_TON_DELAY 0x60 43 | #define PMBUS_TON_RISE 0x61 44 | #define PMBUS_TON_MAX_FAULT_LIMIT 0x62 45 | #define PMBUS_TON_MAX_FAULT_RESPONSE 0x63 46 | #define PMBUS_TOFF_DELAY 0x64 47 | #define PMBUS_TOFF_FALL 0x65 48 | #define PMBUS_STATUS_BYTE 0x78 49 | #define PMBUS_STATUS_WORD 0x79 50 | #define PMBUS_STATUS_VOUT 0x7A 51 | #define PMBUS_STATUS_IOUT 0x7B 52 | #define PMBUS_STATUS_INPUT 0x7C 53 | #define PMBUS_STATUS_TEMPERATURE 0x7D 54 | #define PMBUS_STATUS_CML 0x7E 55 | #define PMBUS_STATUS_OTHER 0x7F 56 | #define PMBUS_STATUS_MFR_SPECIFIC 0x80 57 | #define PMBUS_READ_VIN 0x88 58 | #define PMBUS_READ_VOUT 0x8B 59 | #define PMBUS_READ_IOUT 0x8C 60 | #define PMBUS_READ_TEMPERATURE_1 0x8D 61 | #define PMBUS_REVISION 0x98 62 | #define PMBUS_MFR_ID 0x99 63 | #define PMBUS_MFR_MODEL 0x9A 64 | #define PMBUS_MFR_REVISION 0x9B 65 | #define PMBUS_MFR_SERIAL 0x9E 66 | #define PMBUS_IC_DEVICE_ID 0xAD 67 | #define PMBUS_IC_DEVICE_REV 0xAE 68 | #define PMBUS_COMPENSATION_CONFIG 0xB1 69 | #define PMBUS_POWER_STAGE_CONFIG 0xB5 70 | 71 | /* Manufacturer Specific PMBUS commands used by the TPS546D24A */ 72 | #define PMBUS_TELEMETRY_CFG 0xD0 73 | #define PMBUS_READ_ALL 0xDA 74 | #define PMBUS_STATUS_ALL 0xDB 75 | #define PMBUS_SYNC_CONFIG 0xE4 76 | #define PMBUS_STACK_CONFIG 0xEC 77 | #define PMBUS_MISC_OPTIONS 0xED 78 | #define PMBUS_PIN_DETECT_OVERRIDE 0xEE 79 | #define PMBUS_SLAVE_ADDRESS 0xEF 80 | #define PMBUS_NVM_CHECKSUM 0xF0 81 | #define PMBUS_SIMULATE_FAULTS 0xF1 82 | #define PMBUS_FUSION_ID0 0xFC 83 | #define PMBUS_FUSION_ID1 0xFD 84 | -------------------------------------------------------------------------------- /main/self_test/self_text.h: -------------------------------------------------------------------------------- 1 | #ifndef SELF_TEST_H_ 2 | #define SELF_TEST_H_ 3 | 4 | void self_test(void * pvParameters); 5 | 6 | #endif -------------------------------------------------------------------------------- /main/system.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSTEM_H_ 2 | #define SYSTEM_H_ 3 | 4 | #include "global_state.h" 5 | 6 | void SYSTEM_task(void * parameters); 7 | 8 | void SYSTEM_notify_accepted_share(GlobalState * GLOBAL_STATE); 9 | void SYSTEM_notify_rejected_share(GlobalState * GLOBAL_STATE); 10 | void SYSTEM_notify_found_nonce(GlobalState * GLOBAL_STATE); 11 | void SYSTEM_check_for_best_diff(GlobalState * GLOBAL_STATE, double found_diff, uint8_t job_id); 12 | void SYSTEM_notify_mining_started(GlobalState * GLOBAL_STATE); 13 | void SYSTEM_notify_new_ntime(GlobalState * GLOBAL_STATE, uint32_t ntime); 14 | 15 | #endif /* SYSTEM_H_ */ 16 | -------------------------------------------------------------------------------- /main/tasks/asic_result_task.c: -------------------------------------------------------------------------------- 1 | #include "system.h" 2 | #include "work_queue.h" 3 | #include "serial.h" 4 | #include 5 | #include "esp_log.h" 6 | #include "nvs_config.h" 7 | #include "utils.h" 8 | #include "stratum_task.h" 9 | #include 10 | 11 | static const char *TAG = "asic_result"; 12 | 13 | void ASIC_result_task(void *pvParameters) 14 | { 15 | GlobalState *GLOBAL_STATE = (GlobalState *)pvParameters; 16 | 17 | char *user = nvs_config_get_string(NVS_CONFIG_STRATUM_USER, STRATUM_USER); 18 | 19 | while (1) 20 | { 21 | 22 | task_result *asic_result = (*GLOBAL_STATE->ASIC_functions.receive_result_fn)(GLOBAL_STATE); 23 | 24 | if (asic_result == NULL) 25 | { 26 | continue; 27 | } 28 | 29 | uint8_t job_id = asic_result->job_id; 30 | 31 | if (GLOBAL_STATE->valid_jobs[job_id] == 0) 32 | { 33 | ESP_LOGI(TAG, "Invalid job nonce found, 0x%02X", job_id); 34 | continue; 35 | } 36 | 37 | // check the nonce difficulty 38 | double nonce_diff = test_nonce_value( 39 | GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id], 40 | asic_result->nonce, 41 | asic_result->rolled_version); 42 | 43 | uint32_t pool_difficulty = GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->pool_diff; 44 | 45 | //log the ASIC response 46 | ESP_LOGI(TAG, "AsicNr: %d Ver: %08" PRIX32 " Nonce %08" PRIX32 " diff %.1f of %ld.", asic_result->asic_nr,asic_result->rolled_version, asic_result->nonce, nonce_diff, pool_difficulty); 47 | 48 | // warn if pool diff lower than chip diff 49 | if (pool_difficultyinitial_ASIC_difficulty) { 50 | ESP_LOGI(TAG, "Warning chip diff %i lower than pool diff %i, hashrate will be under reported", 51 | (int)pool_difficulty,(int)GLOBAL_STATE->initial_ASIC_difficulty); 52 | } 53 | 54 | 55 | if (nonce_diff > GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->pool_diff) 56 | { 57 | int ret = STRATUM_V1_submit_share( 58 | GLOBAL_STATE->sock, 59 | user, 60 | GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->jobid, 61 | GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->extranonce2, 62 | GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->ntime, 63 | asic_result->nonce, 64 | asic_result->rolled_version ^ GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->version); 65 | 66 | if (ret < 0) { 67 | ESP_LOGI(TAG, "Unable to write share to socket. Closing connection. Ret: %d (errno %d: %s)", ret, errno, strerror(errno)); 68 | stratum_close_connection(GLOBAL_STATE); 69 | } 70 | } 71 | SYSTEM_notify_found_nonce(GLOBAL_STATE); 72 | SYSTEM_check_for_best_diff(GLOBAL_STATE, nonce_diff, job_id); 73 | 74 | } 75 | } -------------------------------------------------------------------------------- /main/tasks/asic_result_task.h: -------------------------------------------------------------------------------- 1 | #ifndef ASIC_result_TASK_H_ 2 | #define ASIC_result_TASK_H_ 3 | 4 | void ASIC_result_task(void *pvParameters); 5 | 6 | #endif -------------------------------------------------------------------------------- /main/tasks/asic_task.c: -------------------------------------------------------------------------------- 1 | #include "system.h" 2 | #include "work_queue.h" 3 | #include "serial.h" 4 | #include 5 | #include "esp_log.h" 6 | 7 | #include "freertos/FreeRTOS.h" 8 | #include "freertos/task.h" 9 | 10 | static const char *TAG = "ASIC_task"; 11 | 12 | // static bm_job ** active_jobs; is required to keep track of the active jobs since the 13 | 14 | void ASIC_task(void *pvParameters) 15 | { 16 | GlobalState *GLOBAL_STATE = (GlobalState *)pvParameters; 17 | 18 | //initialize the semaphore 19 | GLOBAL_STATE->ASIC_TASK_MODULE.semaphore = xSemaphoreCreateBinary(); 20 | 21 | GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs = malloc(sizeof(bm_job *) * 128); 22 | GLOBAL_STATE->valid_jobs = malloc(sizeof(uint8_t) * 128); 23 | for (int i = 0; i < 128; i++) 24 | { 25 | GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[i] = NULL; 26 | GLOBAL_STATE->valid_jobs[i] = 0; 27 | } 28 | 29 | ESP_LOGI(TAG, "ASIC Job Interval: %.2f ms", GLOBAL_STATE->asic_job_frequency_ms); 30 | SYSTEM_notify_mining_started(GLOBAL_STATE); 31 | ESP_LOGI(TAG, "ASIC Ready!"); 32 | 33 | while (1) 34 | { 35 | 36 | bm_job *next_bm_job = (bm_job *)queue_dequeue(&GLOBAL_STATE->ASIC_jobs_queue); 37 | 38 | if (next_bm_job->pool_diff != GLOBAL_STATE->stratum_difficulty) 39 | { 40 | ESP_LOGI(TAG, "New pool difficulty %lu", next_bm_job->pool_diff); 41 | GLOBAL_STATE->stratum_difficulty = next_bm_job->pool_diff; 42 | } 43 | 44 | (*GLOBAL_STATE->ASIC_functions.send_work_fn)(GLOBAL_STATE, next_bm_job); // send the job to the ASIC 45 | 46 | // Time to execute the above code is ~0.3ms 47 | // Delay for ASIC(s) to finish the job 48 | //vTaskDelay((GLOBAL_STATE->asic_job_frequency_ms - 0.3) / portTICK_PERIOD_MS); 49 | xSemaphoreTake(GLOBAL_STATE->ASIC_TASK_MODULE.semaphore, (GLOBAL_STATE->asic_job_frequency_ms / portTICK_PERIOD_MS)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /main/tasks/asic_task.h: -------------------------------------------------------------------------------- 1 | #ifndef ASIC_TASK_H_ 2 | #define ASIC_TASK_H_ 3 | 4 | #include "freertos/FreeRTOS.h" 5 | #include "freertos/semphr.h" 6 | #include "mining.h" 7 | typedef struct 8 | { 9 | // ASIC may not return the nonce in the same order as the jobs were sent 10 | // it also may return a previous nonce under some circumstances 11 | // so we keep a list of jobs indexed by the job id 12 | bm_job **active_jobs; 13 | //semaphone 14 | SemaphoreHandle_t semaphore; 15 | } AsicTaskModule; 16 | 17 | void ASIC_task(void *pvParameters); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /main/tasks/create_jobs_task.h: -------------------------------------------------------------------------------- 1 | #ifndef CREATE_JOBS_TASK_H_ 2 | #define CREATE_JOBS_TASK_H_ 3 | 4 | void create_jobs_task(void *pvParameters); 5 | 6 | #endif -------------------------------------------------------------------------------- /main/tasks/power_management_task.h: -------------------------------------------------------------------------------- 1 | #ifndef POWER_MANAGEMENT_TASK_H_ 2 | #define POWER_MANAGEMENT_TASK_H_ 3 | 4 | typedef struct 5 | { 6 | uint16_t fan_perc; 7 | float chip_temp_avg; 8 | float vr_temp; 9 | float board_temp_1; 10 | float board_temp_2; 11 | float voltage; 12 | float frequency_multiplier; 13 | float frequency_value; 14 | float power; 15 | float current; 16 | } PowerManagementModule; 17 | 18 | void POWER_MANAGEMENT_task(void * pvParameters); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /main/tasks/stratum_task.h: -------------------------------------------------------------------------------- 1 | #ifndef STRATUM_TASK_H_ 2 | #define STRATUM_TASK_H_ 3 | 4 | typedef struct 5 | { 6 | uint32_t stratum_difficulty; 7 | } SystemTaskModule; 8 | 9 | void stratum_task(void *pvParameters); 10 | void stratum_close_connection(GlobalState * GLOBAL_STATE); 11 | 12 | #endif -------------------------------------------------------------------------------- /main/tasks/user_input_task.c: -------------------------------------------------------------------------------- 1 | #include "freertos/FreeRTOS.h" 2 | #include "freertos/task.h" 3 | #include "freertos/queue.h" 4 | #include "esp_timer.h" // Include esp_timer for esp_timer_get_time 5 | #include "driver/gpio.h" 6 | #include "esp_log.h" 7 | #include "connect.h" 8 | 9 | #define BUTTON_BOOT GPIO_NUM_0 10 | #define SHORT_PRESS_DURATION_MS 100 // Define what constitutes a short press 11 | #define LONG_PRESS_DURATION_MS 2000 // Define what constitutes a long press 12 | 13 | static const char *TAG = "user_input"; 14 | static bool button_being_pressed = false; 15 | static int64_t button_press_time = 0; 16 | 17 | extern QueueHandle_t user_input_queue; // Declare the queue as external 18 | 19 | void USER_INPUT_task(void *pvParameters) 20 | { 21 | gpio_set_direction(BUTTON_BOOT, GPIO_MODE_INPUT); 22 | 23 | while (1) 24 | { 25 | if (gpio_get_level(BUTTON_BOOT) == 0 && button_being_pressed == false) 26 | { // If button is pressed 27 | button_being_pressed = true; 28 | button_press_time = esp_timer_get_time(); 29 | } 30 | else if (gpio_get_level(BUTTON_BOOT) == 1 && button_being_pressed == true) 31 | { 32 | int64_t press_duration = esp_timer_get_time() - button_press_time; 33 | button_being_pressed = false; 34 | if (press_duration > LONG_PRESS_DURATION_MS * 1000) 35 | { 36 | ESP_LOGI(TAG, "LONG PRESS DETECTED"); 37 | xQueueSend(user_input_queue, (void *)"LONG", (TickType_t)0); 38 | } 39 | else if (press_duration > SHORT_PRESS_DURATION_MS * 1000) 40 | { 41 | ESP_LOGI(TAG, "SHORT PRESS DETECTED"); 42 | xQueueSend(user_input_queue, (void *)"SHORT", (TickType_t)0); 43 | } 44 | } 45 | 46 | vTaskDelay(30 / portTICK_PERIOD_MS); // Add delay so that current task does not starve idle task and trigger watchdog timer 47 | } 48 | } -------------------------------------------------------------------------------- /main/tasks/user_input_task.h: -------------------------------------------------------------------------------- 1 | #ifndef USER_INPUT_TASK_H_ 2 | #define USER_INPUT_TASK_H_ 3 | 4 | void USER_INPUT_task(void *pvParameters); 5 | 6 | #endif -------------------------------------------------------------------------------- /main/vcore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "esp_log.h" 4 | 5 | #include "vcore.h" 6 | #include "adc.h" 7 | #include "TPS546.h" 8 | 9 | static const char *TAG = "vcore.c"; 10 | 11 | static TPS546_CONFIG TPS546_CONFIG_HEX = { 12 | /* vin voltage */ 13 | .TPS546_INIT_VIN_ON = 11.5, 14 | .TPS546_INIT_VIN_OFF = 11.0, 15 | .TPS546_INIT_VIN_UV_WARN_LIMIT = 11.0, 16 | .TPS546_INIT_VIN_OV_FAULT_LIMIT = 14.0, 17 | /* vout voltage */ 18 | .TPS546_INIT_SCALE_LOOP = 0.125, 19 | .TPS546_INIT_VOUT_MIN = 2.5, 20 | .TPS546_INIT_VOUT_MAX = 4.5, 21 | .TPS546_INIT_VOUT_COMMAND = 3.6 22 | }; 23 | 24 | void VCORE_init(GlobalState * global_state) { 25 | switch (global_state->device_model) { 26 | case DEVICE_HEX: // init TPS546 for Hex 27 | TPS546_init(TPS546_CONFIG_HEX); 28 | break; 29 | default: 30 | } 31 | 32 | ADC_init(); 33 | } 34 | 35 | bool VCORE_set_voltage(float core_voltage, GlobalState * global_state) 36 | { 37 | switch (global_state->device_model) { 38 | case DEVICE_HEX: // turn on ASIC core voltage (three domains in series) 39 | ESP_LOGI(TAG, "Set ASIC voltage = %.3fV", core_voltage); 40 | TPS546_set_vout(core_voltage * (float)global_state->voltage_domain); 41 | break; 42 | default: 43 | } 44 | 45 | return true; 46 | } 47 | 48 | uint16_t VCORE_get_voltage_mv(GlobalState * global_state) { 49 | switch (global_state->device_model) { 50 | case DEVICE_HEX: 51 | return (TPS546_get_vout() * 1000) / global_state->voltage_domain; 52 | break; 53 | default: 54 | } 55 | 56 | return ADC_get_vcore() / global_state->voltage_domain; 57 | } 58 | -------------------------------------------------------------------------------- /main/vcore.h: -------------------------------------------------------------------------------- 1 | #ifndef VCORE_H_ 2 | #define VCORE_H_ 3 | 4 | #include "global_state.h" 5 | 6 | void VCORE_init(GlobalState * global_state); 7 | bool VCORE_set_voltage(float core_voltage, GlobalState * global_state); 8 | uint16_t VCORE_get_voltage_mv(GlobalState * global_state); 9 | 10 | #endif /* VCORE_H_ */ 11 | -------------------------------------------------------------------------------- /main/work_queue.c: -------------------------------------------------------------------------------- 1 | #include "work_queue.h" 2 | #include "esp_log.h" 3 | 4 | void queue_init(work_queue *queue) 5 | { 6 | queue->head = 0; 7 | queue->tail = 0; 8 | queue->count = 0; 9 | pthread_mutex_init(&queue->lock, NULL); 10 | pthread_cond_init(&queue->not_empty, NULL); 11 | pthread_cond_init(&queue->not_full, NULL); 12 | } 13 | 14 | void queue_enqueue(work_queue *queue, void *new_work) 15 | { 16 | pthread_mutex_lock(&queue->lock); 17 | 18 | while (queue->count == QUEUE_SIZE) 19 | { 20 | pthread_cond_wait(&queue->not_full, &queue->lock); 21 | } 22 | 23 | queue->buffer[queue->tail] = new_work; 24 | queue->tail = (queue->tail + 1) % QUEUE_SIZE; 25 | queue->count++; 26 | 27 | pthread_cond_signal(&queue->not_empty); 28 | pthread_mutex_unlock(&queue->lock); 29 | } 30 | 31 | void *queue_dequeue(work_queue *queue) 32 | { 33 | pthread_mutex_lock(&queue->lock); 34 | 35 | while (queue->count == 0) 36 | { 37 | pthread_cond_wait(&queue->not_empty, &queue->lock); 38 | } 39 | 40 | void *next_work = queue->buffer[queue->head]; 41 | queue->head = (queue->head + 1) % QUEUE_SIZE; 42 | queue->count--; 43 | 44 | pthread_cond_signal(&queue->not_full); 45 | pthread_mutex_unlock(&queue->lock); 46 | 47 | return next_work; 48 | } 49 | 50 | void queue_clear(work_queue *queue) 51 | { 52 | pthread_mutex_lock(&queue->lock); 53 | 54 | while (queue->count > 0) 55 | { 56 | mining_notify *next_work = queue->buffer[queue->head]; 57 | STRATUM_V1_free_mining_notify(next_work); 58 | queue->head = (queue->head + 1) % QUEUE_SIZE; 59 | queue->count--; 60 | } 61 | 62 | pthread_cond_signal(&queue->not_full); 63 | pthread_mutex_unlock(&queue->lock); 64 | } 65 | 66 | void ASIC_jobs_queue_clear(work_queue *queue) 67 | { 68 | pthread_mutex_lock(&queue->lock); 69 | 70 | while (queue->count > 0) 71 | { 72 | bm_job *next_work = queue->buffer[queue->head]; 73 | free(next_work->jobid); 74 | free(next_work->extranonce2); 75 | free(next_work); 76 | queue->head = (queue->head + 1) % QUEUE_SIZE; 77 | queue->count--; 78 | } 79 | 80 | pthread_cond_signal(&queue->not_full); 81 | pthread_mutex_unlock(&queue->lock); 82 | } 83 | -------------------------------------------------------------------------------- /main/work_queue.h: -------------------------------------------------------------------------------- 1 | #ifndef WORK_QUEUE_H 2 | #define WORK_QUEUE_H 3 | 4 | #include 5 | #include "mining.h" 6 | 7 | #define QUEUE_SIZE 12 8 | 9 | typedef struct 10 | { 11 | void *buffer[QUEUE_SIZE]; 12 | int head; 13 | int tail; 14 | int count; 15 | pthread_mutex_t lock; 16 | pthread_cond_t not_empty; 17 | pthread_cond_t not_full; 18 | } work_queue; 19 | 20 | void queue_init(work_queue *queue); 21 | void queue_enqueue(work_queue *queue, void *new_work); 22 | void ASIC_jobs_queue_clear(work_queue *queue); 23 | void *queue_dequeue(work_queue *queue); 24 | void queue_clear(work_queue *queue); 25 | 26 | #endif // WORK_QUEUE_H -------------------------------------------------------------------------------- /merge_bin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Binary file paths and addresses 4 | BOOTLOADER_BIN="build/bootloader/bootloader.bin" 5 | BOOTLOADER_BIN_ADDR=0x0 6 | PARTITION_TABLE="build/partition_table/partition-table.bin" 7 | PARTITION_TABLE_ADDR=0x8000 8 | CONFIG_BIN="config.bin" 9 | CONFIG_BIN_ADDR=0x9000 10 | MINER_BIN="build/esp-miner-multichip.bin" 11 | MINER_BIN_ADDR=0x10000 12 | WWW_BIN="build/www.bin" 13 | WWW_BIN_ADDR=0x410000 14 | OTA_BIN="build/ota_data_initial.bin" 15 | OTA_BIN_ADDR=0xf10000 16 | 17 | BINS_DEFAULT=($BOOTLOADER_BIN $PARTITION_TABLE $MINER_BIN $WWW_BIN $OTA_BIN) 18 | BINS_AND_ADDRS_DEFAULT=($BOOTLOADER_BIN_ADDR $BOOTLOADER_BIN $PARTITION_TABLE_ADDR $PARTITION_TABLE $MINER_BIN_ADDR $MINER_BIN $WWW_BIN_ADDR $WWW_BIN $OTA_BIN_ADDR $OTA_BIN) 19 | 20 | BINS_WITH_CONFIG=($BOOTLOADER_BIN $PARTITION_TABLE $CONFIG_BIN $MINER_BIN $WWW_BIN $OTA_BIN) 21 | BINS_AND_ADDRS_WITH_CONFIG=($BOOTLOADER_BIN_ADDR $BOOTLOADER_BIN $PARTITION_TABLE_ADDR $PARTITION_TABLE $CONFIG_BIN_ADDR $CONFIG_BIN $MINER_BIN_ADDR $MINER_BIN $WWW_BIN_ADDR $WWW_BIN $OTA_BIN_ADDR $OTA_BIN) 22 | 23 | BINS_UPDATE=($MINER_BIN $WWW_BIN $OTA_BIN) 24 | BINS_AND_ADDRS_UPDATE=($MINER_BIN_ADDR $MINER_BIN $WWW_BIN_ADDR $WWW_BIN $OTA_BIN_ADDR $OTA_BIN) 25 | 26 | 27 | function show_help() { 28 | echo "Creates a combined binary using esptool's merge_bin command" 29 | echo "Usage: $0 [OPTION] output_file" 30 | echo " output_file: The combined binary" 31 | echo " Options:" 32 | echo " -c: Include $CONFIG_BIN in addition to default binaries into output_file" 33 | echo " -u: Only include the following binaries into output_file:" 34 | echo " ${BINS_UPDATE[@]}" 35 | echo " If no options are specified, by default the following binaries are included:" 36 | echo " ${BINS_DEFAULT[@]}" 37 | echo 38 | } 39 | 40 | 41 | function print_with_error_header() { 42 | echo "ERROR:" $1 43 | } 44 | 45 | 46 | #### MAIN #### 47 | 48 | # Check if esptool.py is installed and accessible 49 | if ! command -v esptool.py &> /dev/null; then 50 | echo "esptool.py is not installed or not in PATH. Please install it first." 51 | echo "pip install esptool" 52 | exit 1 53 | fi 54 | 55 | OPTIND=1 # Reset in case getops has been used previously 56 | 57 | # default values 58 | output_file="" 59 | update_only=0 60 | with_config=0 61 | 62 | while getopts "huc" opt; do 63 | case "$opt" in 64 | h) 65 | show_help 66 | exit 0 67 | ;; 68 | c) with_config=1 69 | ;; 70 | u) update_only=1 71 | ;; 72 | *) 73 | show_help 74 | exit 1 75 | esac 76 | done 77 | 78 | shift $((OPTIND-1)) 79 | 80 | [ "${1:-}" = "--" ] && shift 81 | 82 | # Extract output_file argument 83 | output_file="$1" 84 | 85 | if [ -z "$output_file" ]; then 86 | print_with_error_header "output_file missing" 87 | echo 88 | show_help 89 | exit 2 90 | fi 91 | 92 | if [ "$update_only" -eq 1 ] && [ "$with_config" -eq 1 ]; then 93 | print_with_error_header "Include only one of '-c' and '-u'" 94 | exit 3 95 | fi 96 | 97 | selected_bins=() 98 | selected_bins_and_addrs=() 99 | esptool_leading_args="--chip esp32s3 merge_bin --flash_mode dio --flash_size 8MB --flash_freq 80m" 100 | 101 | if [ "$update_only" -eq 1 ]; then 102 | selected_bins+=(${BINS_UPDATE[@]}) 103 | selected_bins_and_addrs+=(${BINS_AND_ADDRS_UPDATE[@]}) 104 | esptool_leading_args+=" --format hex" 105 | else 106 | if [ "$with_config" -eq 1 ]; then 107 | selected_bins+=(${BINS_WITH_CONFIG[@]}) 108 | selected_bins_and_addrs+=(${BINS_AND_ADDRS_WITH_CONFIG[@]}) 109 | else 110 | selected_bins+=(${BINS_DEFAULT[@]}) 111 | selected_bins_and_addrs+=(${BINS_AND_ADDRS_DEFAULT[@]}) 112 | fi 113 | fi 114 | 115 | for file in "${selected_bins[@]}"; do 116 | if [ ! -f "$file" ]; then 117 | print_with_error_header "Required file $file does not exist. Make sure to build first." 118 | echo "Exiting" 119 | exit 4 120 | fi 121 | done 122 | 123 | # Call esptool.py with the specified arguments 124 | esptool.py $esptool_leading_args "${selected_bins_and_addrs[@]}" -o "$output_file" 125 | 126 | # Check if esptool.py command was successful 127 | if [ $? -eq 0 ]; then 128 | echo "Successfully created $output_file" 129 | else 130 | print_with_error_header "Failed to create $output_file" 131 | exit 5 132 | fi 133 | -------------------------------------------------------------------------------- /merge_bin_update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./merge_bin.sh -u $1 4 | -------------------------------------------------------------------------------- /merge_bin_with_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./merge_bin.sh -c $1 4 | -------------------------------------------------------------------------------- /partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap 3 | nvs, data, nvs, 0x9000, 0x6000 4 | phy_init, data, phy, 0xf000, 0x1000 5 | factory, app, factory, 0x10000, 4M 6 | www, data, spiffs, 0x410000, 3M 7 | ota_0, app, ota_0, 0x710000, 4M 8 | ota_1, app, ota_1, 0xb10000, 4M 9 | otadata, data, ota, 0xf10000, 8k 10 | coredump, data, coredump, , 64K 11 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | [![](https://dcbadge.vercel.app/api/server/3E8ca2dkcC)](https://discord.gg/3E8ca2dkcC) 2 | 3 | ![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/bitaxeorg/esp-miner-multichip/total) 4 | 5 | 6 | # ESP-Miner-Multichip 7 | 8 | | Supported Targets | ESP32-S3 (BitAxe v2+) | 9 | | ----------------- | --------------------- | 10 | 11 | ## Requires Python3.4 or later and pip 12 | 13 | Install bitaxetool from pip. pip is included with Python 3.4 but if you need to install it check 14 | 15 | ``` 16 | pip install --upgrade bitaxetool 17 | ``` 18 | 19 | ## Hardware Required 20 | 21 | This firmware is designed to run on a BitAxe v2+ 22 | 23 | If you do have a Bitaxe with no USB connectivity make sure to establish a serial connection with either a JTAG ESP-Prog device or a USB-to-UART bridge 24 | 25 | ## Preconfiguration 26 | 27 | Starting with v2.0.0, the ESP-Miner-Multichip firmware requires some basic manufacturing data to be flashed in the NVS partition. 28 | 29 | 1. Download the esp-miner-multichip-factory.bin file from the release tab. 30 | Click [here](https://github.com/bitaxeorg/esp-miner-multichip/releases) for the release tab 31 | 32 | 2. Copy `config.cvs.example` to `config.cvs` and modify `asicfrequency`, `asicvoltage`, `asicmodel`, `devicemodel`, and `boardversion` 33 | 34 | The following are recommendations but it is necessary that you do have all values in your `config.cvs`file to flash properly. 35 | 36 | - recomended values for the Bitaxe 1366 (hex) 37 | 38 | ``` 39 | key,type,encoding,value 40 | main,namespace,, 41 | asicfrequency,data,u16,485 42 | asicvoltage,data,u16,1200 43 | asicmodel,data,string,BM1366 44 | devicemodel,data,string,hex 45 | boardversion,data,string,303 46 | ``` 47 | 48 | ## Flash 49 | 50 | The bitaxetool includes all necessary library for flashing the binary file to the Bitaxe Hardware. 51 | 52 | The bitaxetool requires a config.cvs preloaded file and the appropiate firmware.bin file in it's executed directory. 53 | 54 | 3. Flash with the bitaxetool 55 | 56 | ``` 57 | bitaxetool --config ./config.cvs --firmware ./esp-miner-multichip-factory.bin 58 | ``` 59 | 60 | ## Build from source 61 | 62 | Building the esp-miner-multichip firmware requires ESP-IDF v2.2 upwards and npm 10.2+ 63 | 64 | --> install VSCode extension for esp-idf and express install 65 | 66 | in ./main/http_server/axe-os --> `npm install`--> `npm run build` 67 | 68 | in ./ --> `idf.py build` --> this will create the build dir and you can use the `esp-miner-multichip.bin`and `wwww.bin` to update your Device. 69 | 70 | ## API 71 | Bitaxe provides an API to expose actions and information. 72 | 73 | For more details take a look at `main/http_server/http_server.c`. 74 | 75 | Things that can be done are: 76 | 77 | - Get System Info 78 | - Get Swarm Info 79 | - Update Swarm 80 | - Swarm Options 81 | - System Restart Action 82 | - Update System Settings Action 83 | - System Options 84 | - Update OTA Firmware 85 | - Update OTA WWW 86 | - WebSocket 87 | 88 | Some API examples in curl: 89 | ```bash 90 | # Get system information 91 | curl http://YOUR-BITAXE-IP/api/system/info 92 | ``` 93 | ```bash 94 | # Get swarm information 95 | curl http://YOUR-BITAXE-IP/api/swarm/info 96 | ``` 97 | ```bash 98 | # System restart action 99 | curl -X POST http://YOUR-BITAXE-IP/api/system/restart 100 | ``` 101 | -------------------------------------------------------------------------------- /sdkconfig.ci: -------------------------------------------------------------------------------- 1 | CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y 2 | CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN=y 3 | -------------------------------------------------------------------------------- /sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | CONFIG_PARTITION_TABLE_CUSTOM=y 2 | CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" 3 | CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" 4 | CONFIG_PARTITION_TABLE_OFFSET=0x8000 5 | CONFIG_PARTITION_TABLE_MD5=y 6 | CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y 7 | CONFIG_ESPTOOLPY_FLASHSIZE="16MB" 8 | CONFIG_HTTPD_WS_SUPPORT=y 9 | CONFIG_SPIFFS_OBJ_NAME_LEN=64 10 | CONFIG_HTTPD_MAX_URI_LEN=2048 11 | 12 | # psram config 13 | CONFIG_ESP32S3_SPIRAM_SUPPORT=y 14 | #CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=n 15 | CONFIG_SPIRAM_BOOT_INIT=y 16 | CONFIG_SPIRAM_MEMTEST=y 17 | CONFIG_SPIRAM_MODE_OCT=y 18 | CONFIG_SPIRAM_SPEED=40 19 | CONFIG_SPIRAM_SPEED_40M=y 20 | CONFIG_SPIRAM_TYPE_AUTO=y 21 | CONFIG_SPIRAM_USE_CAPS_ALLOC=y 22 | CONFIG_SPIRAM=y --------------------------------------------------------------------------------