118 Commits
Author SHA1 Message Date
Ben V. Brown caccc7818a Version bump to 0.0.5 2025-08-01 14:33:46 +10:00
Pavel Zakopaylo f3cb4c1fc6 Merge pull request #57 from Pavlos1/master
BL808 Support
2025-07-21 15:41:26 +10:00
Ben V. Brown 5580eec07b Merge pull request #38 from bdd/compiler-warnings
Refactor to address compiler warnings
2025-07-18 14:57:40 +10:00
Berk D. Demir ee10c51970 Fix compiler warnings: Explicit cast where needed 2025-07-17 20:35:55 -07:00
Berk D. Demir d60e0046a1 Enable all compiler warnings 2025-07-17 20:19:33 -07:00
Berk D. Demir cb89bdb537 Fix compiler warnings: format string
`z` is the length field for `size_t`.
2025-07-17 14:59:09 -07:00
Berk D. Demir 20270e5201 Fix compiler warnings: blisp_flash_firmware
Improve blisp_flash_firmware error handling:
- Address never checked return of `parse_firmware_file`
- Ensure the function always returns the correct blisp_return_t value
- Make error checking syntactic dance consistent
2025-07-17 14:59:09 -07:00
Berk D. Demir 77410adbee Fix compiler warnings: enum-conversion
sp_* functions from libserialport return `enum sp_return`, not
`blisp_return_t`.
2025-07-17 14:59:09 -07:00
Berk D. Demir 847be6c690 Fix compiler warnings: enum-int-mismatch
blisp.h and common.h declares signatures of functions that return
blisp_return_t as int32_t.
2025-07-17 14:59:09 -07:00
Berk D. Demir 77df78c1af Fix compiler warnings: Unused function params
We could use C23's `[[maybe_unused]]` but MSVC doesn't support it.
So we void cast them with an accompanying "unused" comment.
2025-07-17 14:59:09 -07:00
Berk D. Demir 52e736eaa2 Fix compiler warnings: Unused functions
Move function definitions in include/blisp_util.h to lib/blisp_util.c.

Defining them as static leads to internal linkage, accessible in that
translation unit, hence the warning. Their references are to be handled
in other translation units, so they shouldn't be static.
2025-07-17 14:59:09 -07:00
Ben V. Brown 26cee48869 Merge pull request #76 from pine64/hex-fixup
Adding Hex file support
2025-07-17 18:53:29 +10:00
Ben Brown 027b7d8c51 Fixup test building in cmake and path injection 2025-07-08 22:17:09 +10:00
Ben Brown e598bdb002 Update googletest 2025-07-08 21:55:47 +10:00
Ben Brown a9d27efe4f Update argtable3 2025-07-08 21:53:18 +10:00
Ben Brown 9e0dabff67 Build & run tests in CI 2025-07-08 21:49:37 +10:00
Ben Brown ed68b973a4 Hex File Parsing 2025-07-08 21:49:37 +10:00
Ben V. Brown e45941c45e Merge pull request #74 from ia/makefile
Makefile: add file with basic targets
2025-03-04 21:25:11 +11:00
Ivan Zorin 0d997dfb1e Makefile: add file with basic targets 2025-02-04 23:13:26 +03:00
Ben V. Brown a7f857e63b Merge pull request #73 from ia/readme-icons
Fix missing simpleicons-based windows logo by standalone version
2025-01-10 12:08:28 +11:00
Ivan Zorin 010f6b4d3a README.md: set width=15 for windows logo 2025-01-10 01:14:36 +03:00
Ivan Zorin d47d3f9a20 README.md: replace missing simpleicons Windows logo by local standalone version 2025-01-10 01:05:30 +03:00
Ivan Zorin feb324443b README.md: update broken Windows icon 2025-01-10 00:09:14 +03:00
Ben V. Brown a67a771bd6 Merge pull request #72 from ia/artifact-zip
workflows/build.yml: remove redundant zip extension from file names of artifacts
2024-12-13 12:32:58 +11:00
Ivan Zorin 1cef97ca89 workflows/build.yml: remove redundant zip extension from file names of artifacts 2024-12-13 03:20:20 +03:00
Ben V. Brown bfe472e71c Merge pull request #65 from JetbladeDevsStuff/fix-build-macos
Fix lots of build problems on macOS
2024-12-12 13:05:16 +11:00
Terence Noone 2268e535d4 Fix linking with argtable3
CMake interpreted `argtable3` to mean add `-largtable3` rather than to
use the imported argtable3 target. This worked when using the bundled
library, but broke with native libraries.
2024-12-11 20:54:11 -05:00
Terence Noone cb32800728 Do not build for both arm64 and x86_84 on macOS.
While this might work when using bundled libraries, this breaks with
system libraries as they are all compiled for arm64. Also, why would you
need to compile an x86_64 version on arm64, and vise versa.
2024-12-11 20:54:11 -05:00
Terence Noone da463d79fd Use new find module for libserialport
This new find module will replace the old logic used to locate a native
copy of libserialport. THe old code didn't work on macOS, and was pretty
messy.
2024-12-11 20:54:11 -05:00
Ben V. Brown 1fb33da291 Merge pull request #60 from barracuda156/darwin
parse_file.h: include sys/types.h
2024-12-11 14:33:11 +11:00
Ben V. Brown 17f6234a4a Merge pull request #62 from barracuda156/static_assert
blisp_struct.h: use _Static_assert for pre-C23 compatibility
2024-12-11 14:32:28 +11:00
Ben V. Brown 108c387d31 Merge pull request #71 from ia/checkout-v4
* workflows/build.yml: update checkout to v4 since v3 is deprecated

* workflows/build.yml: update upload-artifact to v4 since v3 is deprecated

* workflows/build.yml: remove extra space in the end of the lines
2024-12-11 14:25:01 +11:00
Ivan Zorin ebae66c392 workflows/build.yml: remove extra space in the end of the lines 2024-12-03 02:32:38 +03:00
Ivan Zorin c2fc20452c workflows/build.yml: update upload-artifact to v4 since v3 is deprecated 2024-12-03 02:31:26 +03:00
Ivan Zorin 39388c6b2c workflows/build.yml: update checkout to v4 since v3 is deprecated 2024-12-03 02:10:27 +03:00
Dom Rodriguez d51e7bcc1e fix: Fix mismatching format strings when writing
We were using the incorrect format string - this commit fixes that.

Signed-off-by: Dom Rodriguez <shymega@shymega.org.uk>
2024-12-02 09:27:13 +01:00
Dom Rodriguez d63612c256 fix: Make blisp check for existing file before flashing
This commit adds a simple check to both blisp commands that checks the
passed firmware .bin file exists, and is readable.

Justification: I flashed my Pinecil V2 that arrived today, and
misspelled the filename. blisp erased flash, and then exited - it did
not check the firmware .bin was readable/accessible, which meant my
Pinecil was soft-bricked.

I have tested the change, and it works for both commands when the input
file isn't readable.

I had to declare the `cmd_{iot,write}_args_print_glossary` function as
static before the call, so that we don't use undeclared functions before
we call them.

Signed-off-by: Dom Rodriguez <shymega@shymega.org.uk>
2024-12-01 16:44:17 +01:00
Dom Rodriguez 98784b1776 feat: Add Nix CI workflow
Signed-off-by: Dom Rodriguez <shymega@shymega.org.uk>
2024-12-01 16:43:49 +01:00
Dom Rodriguez 3490c37581 feat: Add Nix flake & derivation
This adds a Nix flake, shims for 'legacy' Nix, and a `.envrc` for
`direnv`. blisp is now able to run directly via:

`nix run github:pine64/blisp`

and for Nix/NixOS users, this helps with a one-click developer
environment.

Signed-off-by: Dom Rodriguez <shymega@shymega.org.uk>
2024-12-01 16:43:49 +01:00
Sergey Fedorov be86373d37 blisp_struct.h: define static_assert when undefined to _Static_assert 2024-01-06 16:03:05 +08:00
Sergey Fedorov 81faf3f213 parse_file.h: include sys/types.h
Fixes: https://github.com/pine64/blisp/issues/59
2024-01-05 22:23:53 +08:00
Andre Fonseca 7a85414ece Enable macOS universal builds (#52)
* enable universal builds (x86_64/arm64) on macOS

* rename macOS build artifact filename

* update README.md
2023-08-28 11:25:41 +02:00
schrobandSchdro c41d128e73 Compile internal file_parsers lib always statically (#51)
Otherwise, depending on BUILD_SHARED_LIBS default, it may be
compiled dynamically. However, the resulting DSO currently would
not be installed, resulting in unusable installed blisp binary.

Co-authored-by: Schdro <>
2023-08-10 14:23:12 +10:00
Robert Lipe d2fef0af22 Merge pull request #49 from neil-forks/master
Add DESTINATION for PUBLIC_HEADERS targets
2023-08-07 22:21:47 -05:00
Neil Hanlon 2203a250e3 Add DESTINATION for PUBLIC_HEADERS targets 2023-08-07 22:49:15 -04:00
Robert Lipe 713e444656 Merge pull request #48 from neil-forks/master
WIP: Use CMAKE_INSTALL_LIBDIR for install destination to respect build forges
2023-08-07 21:24:22 -05:00
Neil Hanlon 3b47993de7 Use CMAKE_INSTALL_LIBDIR for install destination to respect build forges
CMAKE_INSTALL_LIBDIR should be popualted with either lib or lib64,
depending on the architecture. This change makes it so that this flag is
respected by blisp and the library, runtime, and archives are installed
to the location requested by the build.
2023-08-07 21:18:43 -04:00
Marek Kraus f601b6b965 Release v0.0.4 2023-08-03 08:21:21 +02:00
Marc JuulandMarek Kraus 48af2aded0 Adds support for compiling on Ubuntu 20.04 by lowering required cmake… (#44)
* Adds support for compiling on Ubuntu 20.04 by lowering required cmake version to 3.16 (from 3.22) and removing the "set(CMAKE_C_STANDARD 20)" line which is not supported by cmake 3.16

* Adds back the CMAKE_C_STANDARD flag but now sets it to 11, the highest version supported by cmake 3.16

---------

Co-authored-by: Marek Kraus <gamelaster@users.noreply.github.com>
2023-08-01 14:50:32 +02:00
Ben V. BrownandMarek Kraus f1b93a1881 DFU file support (#45)
* DFU file work

Just grabbing first one for now

Expose crc

Update CMakeLists.txt

Test DFU file

Split crc function

Fixup

Zero init struct
Dont null the pointer 🤦
correct fread

Adding tests

Create dfu_file.h

Format

Scratching out more parsing

Basic port parser

Scratching fread wrapper

* Relocate dfu parsing and link in

* Scratching out parsers

* Generic bin parser

* Pull out get file util

Update CMakeLists.txt

* Pull in the generic parser

Fixup

.

* Print flash address

* Rebase address

* stdlib

Update dfu_file.c

* FIXUP! flash offset

* Update dfu_file.c

* Improve logging

* Drop extra erase

* Adjust DFU to avoid goto

* Pragma -> ifndef

* Include Windows headers for missing data types

---------

Co-authored-by: Marek Kraus <gamelaster@outlook.com>
2023-08-01 22:43:56 +10:00
Ben V. Brown 048a724082 Merge pull request #43 from schdro/feature-allow-syslibs3
Optional syslibs build support
2023-06-04 12:17:17 +10:00
Ben V. Brown 37571bc5f1 Merge pull request #41 from pine64/error_codes
Proper error codes (and return failure code)
2023-06-04 12:16:36 +10:00
Schdro 8914260b60 Optional syslibs support
Add optional support for building against system libraries of
libserialport and Argtable3
2023-05-14 18:07:55 +02:00
Marek Kraus 2e931f80db Merge pull request #42 from pine64/multi-build
Build linux executables for multiple architectures, closes #32
2023-05-09 11:10:54 +02:00
Ben V. Brown ec078224bd Unify uploaded artefact names 2023-05-09 14:38:58 +10:00
Ben V. Brown 33c3f36b98 update upload artifact 2023-05-09 14:31:37 +10:00
Ben V. Brown f6f2013c8e Upload with specific names 2023-05-09 14:29:51 +10:00
Ben V. Brown 729609f2c0 Use Actions to recursively checkout 2023-05-09 14:29:51 +10:00
Ben V. Brown 89488b3bb5 Merge pull request #39 from bdd/cmake-install
Add CMake installation support
2023-05-09 08:41:50 +10:00
Ben V. Brown 491dd4f8c0 Draft test multi builder 2023-05-09 08:30:09 +10:00
Ben V. Brown 5306720e5d More annotations on errors 2023-05-09 08:05:38 +10:00
Ben V. Brown bac4f4b49f Cleanup blisp tool to use error codes 2023-05-09 07:58:18 +10:00
Ben V. Brown 6ec0e9e862 Expand blisp_easy to use error codes 2023-05-09 07:58:06 +10:00
Ben V. Brown 6e2d40b9c4 Stitch more error codes through tool 2023-05-09 07:46:45 +10:00
Ben V. Brown fced48570a Start migration to error codes enum 2023-05-09 07:39:34 +10:00
Ben V. Brown 179a4ea267 Extract error codes 2023-05-09 07:39:25 +10:00
Berk D. Demir 2ad3ae7b50 Add CMake installation support
Allows installation with:
  `cmake --install . [--prefix /dir]`
2023-04-22 18:08:39 -07:00
river-mochi de4a9cd5e6 update install instructions 2023-04-10 18:26:06 -07:00
River M 0b363c620a Merge pull request #31 from River-Mochi/master
changed icon colors
2023-04-01 21:28:57 -07:00
River M e7eeef5f85 changed icon colors
Icons in black can not be seen well in dark screen. 
changed to color that matches badges and can be seen in dark mode.
2023-04-01 21:28:08 -07:00
Robert Lipe aaf07b7724 Update README.md
Updated from https://github.com/pine64/blisp/pull/1/files
2023-03-30 13:51:18 -05:00
Marek Kraus 8c3b93cbec Merge pull request #28 from River-Mochi/master
defind ISP
2023-03-30 20:04:35 +02:00
River M cc9ef81934 Update README.md 2023-03-30 10:57:23 -07:00
River M 9cb381d03e Update README.md 2023-03-19 15:49:38 -07:00
Robert Lipe f47bc9f948 Merge pull request #26 from River-Mochi/master
add table, icons, edit doc
2023-03-18 18:08:11 -05:00
River M 4b8713ecd4 Update README.md 2023-03-18 15:01:40 -07:00
River M 935ee4a12c Delete test 2023-03-18 14:55:03 -07:00
River M 55198e9612 Update README.md 2023-03-18 14:05:05 -07:00
River M 63dff45156 Update README.md 2023-03-18 14:03:44 -07:00
River M a98a5090b3 Update README.md 2023-03-18 13:43:53 -07:00
River M 55f40caa60 Update README.md 2023-03-18 13:10:41 -07:00
River M 7618f24c97 Update README.md 2023-03-18 12:41:33 -07:00
River M fb31f9a742 Add files via upload 2023-03-18 12:38:19 -07:00
River M 28d0743742 Create test 2023-03-18 12:37:52 -07:00
River M 042b9a72f0 Update README.md 2023-03-18 12:31:53 -07:00
River M eb55ab4702 Update README.md 2023-03-18 12:29:21 -07:00
River M ca4aca7219 Update README.md 2023-03-18 12:27:18 -07:00
River M 6f174eaffe Update README.md 2023-03-18 12:14:04 -07:00
River M a59d4f7a32 Merge branch 'pine64:master' into master 2023-03-17 04:53:04 -07:00
Marek Kraus 93703a7c2e Merge pull request #25 from porsolic/master
Enable building on FreeBSD hosts
2023-03-17 09:46:02 +01:00
porsolic 6f508d3db8 Enable building on FreeBSD hosts
FreeBSD has libusb built in.
Needs external libserialport.
2023-03-17 00:13:17 +01:00
River M 565c9ff913 Update README.md 2023-03-12 14:54:49 -07:00
River M e219e50efb Update README.md 2023-03-09 16:39:20 -08:00
River M 5a0ae8abc3 Update README.md 2023-03-09 14:15:12 -08:00
River M 0275fad1db Update README.md 2023-03-03 04:20:54 -08:00
River M e63ca04be5 Update README.md 2023-03-03 04:18:14 -08:00
River M 8c21c18b3a Merge branch 'pine64:master' into master 2023-03-03 04:11:38 -08:00
23ca06a336 add Badges (#23)
* Update README.md

syntax error in instructions. this command as written will not work because if flag --chip is used it needs to be --chip=bl70x with the "="
does not work: blisp write --chip bl70x --reset name_of_firmware.bin
or if "=" is not desired then "-c bl70x" could be used instead.

-c, --chip=<chip_type>    Chip Type

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

---------

Co-authored-by: River <97197236+River-b@users.noreply.github.com>
Co-authored-by: Marek Kraus <gamelaster@users.noreply.github.com>
2023-03-02 09:59:05 +01:00
Marek Kraus 5ebcf881b6 Merge branch 'master' into master 2023-03-02 09:58:34 +01:00
River M cda17f2713 Update README.md 2023-03-02 00:53:32 -08:00
River M 933851a775 Update README.md 2023-03-02 00:50:02 -08:00
River M 32e2a64390 Update README.md 2023-03-02 00:46:50 -08:00
River M c157261bf2 Update README.md 2023-03-02 09:44:16 +01:00
River M b54d820408 Update README.md 2023-03-02 09:44:16 +01:00
River M 9d4294f308 Update README.md 2023-03-02 09:44:16 +01:00
River M 44f5c12b40 Update README.md 2023-03-02 00:08:31 -08:00
River M f2605801a4 Update README.md 2023-03-01 22:04:18 -08:00
River M 670ec95507 Update README.md 2023-03-01 19:15:54 -08:00
River M f8acfa2ac1 Merge branch 'pine64:master' into master 2023-03-01 17:58:14 -08:00
Marek Kraus 3d4dfe8b81 Add BL602 branded MCUs 2023-02-28 11:23:18 +01:00
River 4afdfff4b7 Update README.md
syntax error in instructions. this command as written will not work because if flag --chip is used it needs to be --chip=bl70x with the "="
does not work: blisp write --chip bl70x --reset name_of_firmware.bin
or if "=" is not desired then "-c bl70x" could be used instead.

-c, --chip=<chip_type>    Chip Type
2023-02-19 15:48:48 +01:00
River 7669ebbbcb Update README.md
syntax error in instructions. this command as written will not work because if flag --chip is used it needs to be --chip=bl70x with the "="
does not work: blisp write --chip bl70x --reset name_of_firmware.bin
or if "=" is not desired then "-c bl70x" could be used instead.

-c, --chip=<chip_type>    Chip Type
2023-02-15 14:22:20 -08:00
porsolic 6424f9ddf8 Fix it to work under FreeBSD
Add sp_drain() where needed. Without it FreeBSD won't pass the handshake
phase.
Also decreate max buffer size.
Tested with Pinecil v2 and it can write and check new firmware.
2023-02-15 20:21:47 +01:00
porsolic 7fb2cc829c Fix UART baudrate
Set standard baudrate (460800) instead of non-standard (500000).
This enables opening of serial device under FreeBSD without error.
2023-02-15 20:21:47 +01:00
porsolic a67ab9d218 Fix build on FreeBSD 2023-02-15 20:21:47 +01:00
porsolic 3fff531334 Fix compiler warnings 2023-02-15 20:21:47 +01:00
porsolic 53b57c3158 Update README.md
Add missing part about git submodules.
Without it build system won't find dependencies.
2023-02-15 20:21:47 +01:00
Lee Lup Yuen 884142932d The "write" command is missing I think. Thanks :-) 2023-01-25 08:45:59 +01:00
53 changed files with 2840 additions and 451 deletions
+1
View File
@@ -0,0 +1 @@
use flake .
+130 -13
View File
@@ -2,25 +2,42 @@ name: Build
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
check-nix-flake:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
- name: Check Nix Flake
run: nix flake check --print-build-logs
check-nix-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
- name: Build package
run: nix build --print-build-logs
build-windows: build-windows:
runs-on: windows-2022 runs-on: windows-2022
defaults: defaults:
run: run:
shell: cmd shell: cmd
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
with:
submodules: "recursive"
- uses: lukka/get-cmake@latest - uses: lukka/get-cmake@latest
- name: Build blisp tool - name: Build blisp tool
run: | run: |
git submodule update --init --recursive
mkdir build mkdir build
cd build cd build
cmake .. -DBLISP_BUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release cmake .. -DBLISP_BUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release
cmake --build . --config Release cmake --build . --config Release
- name: Upload results - name: Upload results
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v4
with: with:
name: blisp Windows x64 build name: blips-windows-x86_64
path: | path: |
build/tools/blisp/Release/blisp.exe build/tools/blisp/Release/blisp.exe
if-no-files-found: error if-no-files-found: error
@@ -28,19 +45,20 @@ jobs:
build-macos: build-macos:
runs-on: macos-latest runs-on: macos-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
with:
submodules: "recursive"
- uses: lukka/get-cmake@latest - uses: lukka/get-cmake@latest
- name: Build blisp tool - name: Build blisp tool
run: | run: |
git submodule update --init --recursive
mkdir build mkdir build
cd build cd build
cmake .. -DBLISP_BUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release cmake .. -DBLISP_BUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release
cmake --build . cmake --build .
- name: Upload results - name: Upload results
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v4
with: with:
name: blisp macOS x64 build name: blips-apple-universal
path: | path: |
build/tools/blisp/blisp build/tools/blisp/blisp
if-no-files-found: error if-no-files-found: error
@@ -48,19 +66,118 @@ jobs:
build-linux: build-linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
with:
submodules: "recursive"
- uses: lukka/get-cmake@latest - uses: lukka/get-cmake@latest
- name: Build blisp tool - name: Build blisp tool
run: | run: |
git submodule update --init --recursive
mkdir build mkdir build
cd build cd build
cmake .. -DBLISP_BUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release cmake .. -DBLISP_BUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release
cmake --build . cmake --build .
- name: Upload results - name: Upload results
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v4
with: with:
name: blisp Linux x64 build name: blips-linux-x86_64
path: | path: |
build/tools/blisp/blisp build/tools/blisp/blisp
if-no-files-found: error if-no-files-found: error
build-linux-alternative-arch:
runs-on: ubuntu-latest
name: Build on ${{ matrix.distro }} ${{ matrix.arch }}
# Run steps on a matrix of 4 arch/distro combinations
strategy:
matrix:
include:
- arch: aarch64
distro: ubuntu_latest
- arch: armv7
distro: ubuntu_latest
- arch: riscv64
distro: ubuntu_latest
steps:
- uses: actions/checkout@v4
with:
submodules: "recursive"
- uses: uraimo/run-on-arch-action@v2
name: Build artifact
id: build
with:
arch: ${{ matrix.arch }}
distro: ${{ matrix.distro }}
# Create an artifacts directory
setup: |
mkdir -p "${PWD}/artifacts"
# Mount the artifacts directory as /artifacts in the container
dockerRunArgs: |
--volume "${PWD}/artifacts:/artifacts"
# Pass some environment variables to the container
env: | # YAML, but pipe character is necessary
artifact_name: blisp-linux-${{ matrix.arch }}
# The shell to run commands with in the container
shell: /bin/sh
# Install some dependencies in the container. This speeds up builds if
# you are also using githubToken. Any dependencies installed here will
# be part of the container image that gets cached, so subsequent
# builds don't have to re-install them. The image layer is cached
# publicly in your project's package repository, so it is vital that
# no secrets are present in the container state or logs.
install: |
case "${{ matrix.distro }}" in
ubuntu*|jessie|stretch|buster|bullseye)
apt-get update -q -y
apt-get install -q -y git cmake build-essential
;;
esac
# Produce a binary artifact and place it in the mounted volume
run: |
git config --global --add safe.directory /home/runner/work/blisp/blisp
mkdir build
cd build
cmake .. -DBLISP_BUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release
cmake --build . -j2
cp ./tools/blisp/blisp "/artifacts/${artifact_name}"
echo "Produced artifact at /artifacts/${artifact_name}"
- name: Upload results
uses: actions/upload-artifact@v4
with:
name: blisp-linux-${{ matrix.arch }}
path: |
artifacts/blisp-*
if-no-files-found: error
test-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: "recursive"
- uses: lukka/get-cmake@latest
- name: Build blisp tool & unit tests
run: |
mkdir build
cd build
cmake .. -DBLISP_BUILD_CLI=ON -DCOMPILE_TESTS=ON
cmake --build .
- name: Run unit tests
run: |
cd build
for f in $(find . -type f -executable -iname "*_test"); do
echo "Running test file $f"
"$f"
status=$?
if [ $status -ne 0 ]; then
echo "Test $f failed with exit code $status"
exit $status
fi
done
+2 -1
View File
@@ -77,4 +77,5 @@ fabric.properties
.idea/caches/build_file_checksums.ser .idea/caches/build_file_checksums.ser
build/ build/
.DS_Store .DS_Store
.cache/
+102 -38
View File
@@ -1,73 +1,137 @@
cmake_minimum_required(VERSION 3.22) cmake_minimum_required(VERSION 3.16)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
project(blisp C) project(blisp C)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_C_STANDARD 23) set(CMAKE_C_STANDARD 11)
option(BLISP_BUILD_CLI "Build CLI Tool" OFF) option(BLISP_BUILD_CLI "Build CLI Tool" OFF)
option(BLISP_USE_SYSTEM_LIBRARIES "Use system-installed libraries" "${CMAKE_USE_SYSTEM_LIBRARIES}")
option(COMPILE_TESTS "Compile the tests" OFF)
add_library(libblisp_obj OBJECT add_library(libblisp_obj OBJECT
lib/blisp.c lib/blisp.c
lib/blisp_easy.c
lib/blisp_util.c
lib/chip/blisp_chip_bl60x.c lib/chip/blisp_chip_bl60x.c
lib/chip/blisp_chip_bl70x.c lib/blisp_easy.c) lib/chip/blisp_chip_bl70x.c
lib/chip/blisp_chip_bl808.c)
target_include_directories(libblisp_obj PRIVATE ${CMAKE_SOURCE_DIR}/include/) target_include_directories(libblisp_obj PRIVATE ${CMAKE_SOURCE_DIR}/include/)
if (NOT CMAKE_C_COMPILER_ID MATCHES "MSVC")
target_compile_options(libblisp_obj PRIVATE -Wall -Wextra -Wpedantic)
else()
# MSVC does not support 'extra' and 'pedantic' levels to warnings.
# `/Wall` seems to generate way too many non-actionable output marked as warnings.
# We settle for `/W4`.
# https://learn.microsoft.com/en-us/cpp/build/reference/compiler-option-warning-level?view=msvc-170
target_compile_options(libblisp_obj PRIVATE -W4)
endif()
set_property(TARGET libblisp_obj PROPERTY POSITION_INDEPENDENT_CODE 1) set_property(TARGET libblisp_obj PROPERTY POSITION_INDEPENDENT_CODE 1)
add_library(libblisp SHARED $<TARGET_OBJECTS:libblisp_obj>) add_library(libblisp SHARED $<TARGET_OBJECTS:libblisp_obj>)
add_library(libblisp_static STATIC $<TARGET_OBJECTS:libblisp_obj>) add_library(libblisp_static STATIC $<TARGET_OBJECTS:libblisp_obj>)
set(BLISP_PUBLIC_HEADERS
include/blisp.h
include/blisp_easy.h
include/blisp_chip.h
include/blisp_struct.h
include/blisp_util.h)
set_target_properties(libblisp PROPERTIES set_target_properties(libblisp PROPERTIES
PUBLIC_HEADER "include/blisp.h" PUBLIC_HEADER "${BLISP_PUBLIC_HEADERS}"
VERSION 0.0.3 VERSION 0.0.5
SOVERSION 1 SOVERSION 1
LIBRARY_OUTPUT_DIRECTORY "shared" LIBRARY_OUTPUT_DIRECTORY "shared"
OUTPUT_NAME "blisp") OUTPUT_NAME "blisp")
set_target_properties(libblisp_static PROPERTIES set_target_properties(libblisp_static PROPERTIES
PUBLIC_HEADER "include/blisp.h" PUBLIC_HEADER "${BLISP_PUBLIC_HEADERS}"
VERSION 0.0.3 VERSION 0.0.5
SOVERSION 1 SOVERSION 1
ARCHIVE_OUTPUT_DIRECTORY "static" ARCHIVE_OUTPUT_DIRECTORY "static"
OUTPUT_NAME "blisp") OUTPUT_NAME "blisp")
target_sources(libblisp_obj PRIVATE if(BLISP_USE_SYSTEM_LIBRARIES)
find_package(Libserialport REQUIRED)
target_link_libraries(libblisp PUBLIC Libserialport::Libserialport)
target_link_libraries(libblisp_static PUBLIC Libserialport::Libserialport)
target_include_directories(libblisp_obj PUBLIC ${Libserialport_INCLUDE_DIRS})
else()
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
target_sources(libblisp_obj PRIVATE
${CMAKE_SOURCE_DIR}/vendor/libserialport/serialport.c ${CMAKE_SOURCE_DIR}/vendor/libserialport/serialport.c
${CMAKE_SOURCE_DIR}/vendor/libserialport/timing.c) ${CMAKE_SOURCE_DIR}/vendor/libserialport/timing.c)
target_include_directories(libblisp_obj PRIVATE ${CMAKE_SOURCE_DIR}/vendor/libserialport) target_include_directories(libblisp_obj PRIVATE ${CMAKE_SOURCE_DIR}/vendor/libserialport)
endif()
if(WIN32) if(WIN32)
target_link_libraries(libblisp PRIVATE Setupapi.lib) target_link_libraries(libblisp PRIVATE Setupapi.lib)
target_link_libraries(libblisp_static PRIVATE Setupapi.lib) target_link_libraries(libblisp_static PRIVATE Setupapi.lib)
target_compile_definitions(libblisp_obj PRIVATE LIBSERIALPORT_MSBUILD) target_compile_definitions(libblisp_obj PRIVATE LIBSERIALPORT_MSBUILD)
target_sources(libblisp_obj PRIVATE target_sources(libblisp_obj PRIVATE
${CMAKE_SOURCE_DIR}/vendor/libserialport/windows.c) ${CMAKE_SOURCE_DIR}/vendor/libserialport/windows.c)
elseif(UNIX AND NOT APPLE) elseif(UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
target_sources(libblisp_obj PRIVATE target_sources(libblisp_obj PRIVATE
${CMAKE_SOURCE_DIR}/vendor/libserialport/linux.c ${CMAKE_SOURCE_DIR}/vendor/libserialport/linux.c
${CMAKE_SOURCE_DIR}/vendor/libserialport/linux_termios.c) ${CMAKE_SOURCE_DIR}/vendor/libserialport/linux_termios.c)
target_compile_definitions(libblisp_obj PRIVATE target_compile_definitions(libblisp_obj PRIVATE
LIBSERIALPORT_ATBUILD LIBSERIALPORT_ATBUILD
HAVE_TERMIOS2_SPEED HAVE_TERMIOS2_SPEED
HAVE_STRUCT_TERMIOS2 HAVE_STRUCT_TERMIOS2
HAVE_DECL_BOTHER HAVE_DECL_BOTHER
"SP_API=__attribute__((visibility(\"default\")))" "SP_API=__attribute__((visibility(\"default\")))"
"SP_PRIV=__attribute__((visibility(\"hidden\")))") "SP_PRIV=__attribute__((visibility(\"hidden\")))")
write_file(${CMAKE_SOURCE_DIR}/vendor/libserialport/config.h "// bypass errors.") write_file(${CMAKE_SOURCE_DIR}/vendor/libserialport/config.h "// bypass errors.")
elseif(APPLE) elseif(UNIX AND ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
target_sources(libblisp_obj PRIVATE target_include_directories(libblisp_obj PRIVATE /usr/local/include/)
${CMAKE_SOURCE_DIR}/vendor/libserialport/macosx.c) target_link_libraries(libblisp PRIVATE -L/usr/local/lib usb serialport)
target_link_libraries(libblisp PRIVATE "-framework IOKit" "-framework CoreFoundation") target_link_libraries(libblisp_static PRIVATE -L/usr/local/lib usb serialport)
target_compile_definitions(libblisp_obj PRIVATE elseif(APPLE)
LIBSERIALPORT_ATBUILD target_sources(libblisp_obj PRIVATE
"SP_PRIV=__attribute__((visibility(\"hidden\")))" ${CMAKE_SOURCE_DIR}/vendor/libserialport/macosx.c)
"SP_API=__attribute__((visibility(\"default\")))") target_link_libraries(libblisp PRIVATE "-framework IOKit" "-framework CoreFoundation")
target_include_directories(libblisp_obj PRIVATE ${CMAKE_SOURCE_DIR}/vendor/libserialport) target_compile_definitions(libblisp_obj PRIVATE
write_file(${CMAKE_SOURCE_DIR}/vendor/libserialport/config.h "// bypass errors.") LIBSERIALPORT_ATBUILD
"SP_PRIV=__attribute__((visibility(\"hidden\")))"
"SP_API=__attribute__((visibility(\"default\")))")
target_include_directories(libblisp_obj PRIVATE ${CMAKE_SOURCE_DIR}/vendor/libserialport)
write_file(${CMAKE_SOURCE_DIR}/vendor/libserialport/config.h "// bypass errors.")
endif()
endif() endif()
include(GNUInstallDirs)
install(TARGETS libblisp libblisp_static
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
if(BLISP_BUILD_CLI) if(BLISP_BUILD_CLI)
add_subdirectory(tools/blisp) add_subdirectory(tools/blisp)
endif() endif()
if(COMPILE_TESTS)
# Bring in googletest & C++
enable_language(CXX)
enable_testing()
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.17.0
)
FetchContent_MakeAvailable(googletest)
add_library(GTest::GTest INTERFACE IMPORTED)
target_link_libraries(GTest::GTest INTERFACE gtest_main)
add_subdirectory(tools/blisp/src/file_parsers/dfu/tests)
add_subdirectory(tools/blisp/src/file_parsers/hex/tests)
endif(COMPILE_TESTS)
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env make -f
### global variables section
# static vars
BUILD_DIR:="build"
BUILD_BIN:="$(BUILD_DIR)/tools/blisp/blisp"
# dynamic vars
FILES_CMAKE:=$(shell find . -path ./$(BUILD_DIR) -prune -false -o -type f -name '*.cmake' -o -type f -name 'CMakeLists.txt')
FILES_SRC:=$(shell find . -path ./$(BUILD_DIR) -prune -false -o -type f -name '*.c' -o -type f -name '*.h')
### main targets section
# simplify build
build: $(FILES_CMAKE) $(FILES_SRC) Makefile
@echo "\n>>>> Generating build files in: $(BUILD_DIR) ...\n"
@cmake -S . -B $(BUILD_DIR) -DBLISP_BUILD_CLI=ON
@echo "\n>>>> Building...\n"
@cmake --build $(BUILD_DIR)
@echo "\n>>>> DONE: $(BUILD_BIN)\n"
# deleting output build directory with its content
clean:
-@rm -rf $(BUILD_DIR)/
# printf-like debug target
vars:
@echo "\n>>>> FILES_CMAKE:"
@echo "$(FILES_CMAKE)" | sed 's, ,\n,g'
@echo "\n>>>> FILES_SRC:"
@echo "$(FILES_SRC)" | sed 's, ,\n,g'
.PHONY: clean vars
+86 -22
View File
@@ -1,35 +1,51 @@
# Bouffalo Labs ISP tool & library [![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fpine64%2Fblisp&count_bg=%235791AC&title_bg=%23555555&icon=airplayaudio.svg&icon_color=%23D2D9DD&title=hits&edge_flat=false)](https://github.com/pine64/blisp/wiki/Update-Pinecil-V2)
[![GitHub all downloads](https://img.shields.io/github/downloads/pine64/blisp/total?color=5791ac&logo=docusign&logoColor=white)](https://github.com/pine64/blisp/releases/tag/v0.0.5)
[![Discord](https://img.shields.io/discord/463237927984693259?color=5791ac&logo=discord&logoColor=white)](https://discord.com/invite/pine64)
[![GitHub release](https://img.shields.io/github/v/release/pine64/blisp?color=5791ac)](https://github.com/pine64/blisp/releases/tag/v0.0.5)
Open source tool and library for flashing Bouffalo RISC-V MCUs. <img src="./img/Gradient-white-blue-03.png" align="left" width="60" > <br clear="left" />
# BLISP
Bouffalo Labs ISP (in-system-programming) tool & library: an open source tool to flash Bouffalo RISC-V MCUs.
**NOTE:** Library API and `blisp` tool cli arguments are not stable yet. **NOTE:** Library API and `blisp` tool cli arguments are not stable yet.
<br>
# Supported MCUs ## Supported MCUs
- [x] `bl60x` - BL602 / BL604 / TG7100C / LF686 / LF688
- [x] `bl60x` - BL602 / BL604
- [x] `bl70x` - BL702 / BL704 / BL706 - [x] `bl70x` - BL702 / BL704 / BL706
- [ ] `bl70xl` - BL702L / BL704L <br>
- [ ] `bl606p` - BL606P
- [ ] `bl61x` - BL616 / BL618
- [ ] `bl808` - BL808
# Supported OS ## Supported Devices
- [x] Windows | System | <img width="15" src="img/win32.png" /> Windows | <img width="15" src="https://cdn.simpleicons.org/Apple/5791ac" /> MacOS| <img width="17" src="https://cdn.simpleicons.org/Linux/5791ac" /> Linux| <img width="15" src="https://cdn.simpleicons.org/Freebsd/5791ac" /> FreeBSD |
- [x] Linux | :-----: | :------: | :------: | :------: | :------: |
- [x] Apple | Pinecil V2 |<img width="22" src="https://cdn.simpleicons.org/cachet/5791ac" />|<img width="22" src="https://cdn.simpleicons.org/cachet/5791ac" />| <img width="22" src="https://cdn.simpleicons.org/cachet/5791ac" />| <img width="22" src="https://cdn.simpleicons.org/cachet/5791ac" /> |
| Pinecone |<img width="22" src="https://cdn.simpleicons.org/cachet/5791ac" />|<img width="22" src="https://cdn.simpleicons.org/cachet/5791ac" />|<img width="22" src="https://cdn.simpleicons.org/cachet/5791ac" />| <img width="22" src="https://cdn.simpleicons.org/cachet/5791ac" /> |
<br>
# Building ## How to update Pinecil V2
## Clone repository Download the newest release of [Blisp updater here](https://github.com/pine64/blisp/releases/).
Check out the [wiki page](https://github.com/pine64/blisp/wiki/Update-Pinecil-V2) for install instructions.
<br><br>
## Building from code
### Clone repository
If you have not cloned this repository locally; clone the git repository locally by running If you have not cloned this repository locally; clone the git repository locally by running
```bash ```bash
git clone --recursive https://github.com/pine64/blisp.git git clone --recursive https://github.com/pine64/blisp.git
cd blisp cd blisp
git submodule update --init --recursive
``` ```
## Build the library and command line utility If vendor/argtable3 and vendor/libserialport/ are empty, this last step has
failed and should be investigated.
### Build the library and command line utility
For building `blisp` command line tool, use following commands: For building `blisp` command line tool, use following commands:
@@ -39,20 +55,68 @@ cmake -DBLISP_BUILD_CLI=ON ..
cmake --build . cmake --build .
``` ```
# Usage For building against preinstalled system libraries of the used vendor
libraries (e.g. for use by system maintainers), additionally define
`BLISP_USE_SYSTEM_LIBRARIES`, e.g. using following commands:
```bash
mkdir build && cd build
cmake -DBLISP_USE_SYSTEM_LIBRARIES=ON -DBLISP_BUILD_CLI=ON ..
cmake --build .
```
For BL70X, BL61X, BL808 and BL606P, connected via USB, you can use following command, which will auto-detect serial port: #### Need more build details? [See here](https://github.com/pine64/blisp/wiki/Update-Pinecil-V2#build-blisp-flasher-from-code).
## Usage
For BL70X, BL61X, BL808 and BL606P, connected via USB, you can use following command, which will auto-detect serial port on Windows:
```bash ```bash
blisp write --chip bl70x --reset name_of_firmware.bin .\blisp.exe write --chip=bl70x --reset .\name_of_firmware.bin
or
.\blisp.exe write -c bl70x --reset .\name_of_firmware.bin
``` ```
For BL60X, you need to specify also the serial port path: For BL60X, you need to specify also the serial port path:
```bash ```bash
blisp --chip bl60x --reset -p /dev/ttyUSB0 name_of_firmware.bin blisp write --chip bl60x --reset -p /dev/ttyUSB0 name_of_firmware.bin
``` ```
# How to flash Pinecil V2 If you wish to see additional debugging, set the environmental
variable LIBSERIALPORT_DEBUG before running. You can either export this
in your shell or change it for a single run via
Check out the [wiki page](https://github.com/pine64/blisp/wiki/Update-Pinecil-V2). ```bash
LIBSERIALPORT_DEBUG=y ./a.out write -c bl70x -p /dev/tty.usbmodem0000000200001
```
Because this is done at the lowest level of serial communication, the
displays aren't packet-aware or know about the chip's command set or such.
This is really only useful for debugging systems-level issues withing
the device or blisp itself.
## Running unit tests
```shell
mkdir build && cd build
cmake -DBLISP_BUILD_CLI=ON -DCOMPILE_TESTS=ON ..
cmake --build .
# Find all compiled unit test files; you can now run these directly
find . -type f -executable -iname "*_test" -print
```
## Troubleshooting
### macOS
Depending on your current system security settings, modern versions of macOS requires all software to be notarised before you are able to execute it. This is specially true for software that is downloaded directly from the internet.
If that is the case, you will get an error that looks like the following:
> **“blisp” cannot be opened because the developer cannot be verified.**
>
> macOS cannot verify that this app is free from malware.
In that case, you will need to remove the *quarantine* flag that macOS adds to the executable. After that you should be able to run **blisp** as normal.
```bash
xattr -d com.apple.quarantine blisp
```
+49
View File
@@ -0,0 +1,49 @@
{
lib,
self,
stdenv,
fetchFromGitHub,
argtable,
cmake,
libserialport,
pkg-config,
testers,
IOKit ? null,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "blisp";
version = "0.0.5-unstable";
src = self;
nativeBuildInputs = [
cmake
pkg-config
];
buildInputs = [
argtable
libserialport
] ++ lib.optional stdenv.hostPlatform.isDarwin IOKit;
cmakeFlags = [
"-DBLISP_BUILD_CLI=ON"
"-DBLISP_USE_SYSTEM_LIBRARIES=ON"
];
env.NIX_CFLAGS_COMPILE = lib.optionalString stdenv.hostPlatform.isDarwin "-Wno-error=implicit-function-declaration";
passthru.tests.version = testers.testVersion {
package = finalAttrs.finalPackage;
version = "v${finalAttrs.version}";
};
meta = with lib; {
description = "In-System-Programming (ISP) tool & library for Bouffalo Labs RISC-V Microcontrollers and SoCs";
license = licenses.mit;
mainProgram = "blisp";
homepage = "https://github.com/pine64/blisp";
platforms = platforms.unix;
maintainers = [ maintainers.bdd ];
};
})
+79
View File
@@ -0,0 +1,79 @@
# SPDX-License-Identifier: MIT
#[=======================================================================[.rst:
FindLibserialport
-------
Finds the sigrok serial port library (``libserialport``)
Imported Targets
^^^^^^^^^^^^^^^^
This module defines the following imported targets, if found:
``Libserialport::Libserialport``
The serialport library
Result Variables
^^^^^^^^^^^^^^^^
This module will define the following variables:
``Libserialport_FOUND``
True if the system has the serialport library.
``Libserialport_VERSION``
The version of the serialport library which was found.
``Libserialport_INCLUDE_DIRS``
Include directories needed to use ``libserialport``.
``Libserialport_LIBRARIES``
Libraries needed to link to ``libserialport``.
Cache Variables
^^^^^^^^^^^^^^^
The following cache variables may also be set:
``Libserialport_INCLUDE_DIR``
The directory containing ``libserialport.h``.
``Libserialport_LIBRARY``
The path to the ``libserialport`` library.
#]=======================================================================]
find_package(PkgConfig)
pkg_check_modules(PC_Libserialport QUIET libserialport)
find_path(Libserialport_INCLUDE_DIR
NAMES libserialport.h
PATHS "${PC_Libserialport_INCLUDE_DIRS}"
)
find_library(Libserialport_LIBRARY
NAMES serialport
HINTS "${PC_Libserialport_LIBRARY_DIRS}"
)
set(Foo_VERSION ${PC_Foo_VERSION})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libserialport
FOUND_VAR Libserialport_FOUND
REQUIRED_VARS
Libserialport_LIBRARY
Libserialport_INCLUDE_DIR
VERSION_VAR Libserialport_VERSION
)
if(Libserialport_FOUND)
set(Libserialport_LIBRARIES ${Libserialport_LIBRARY})
set(Libserialport_INCLUDE_DIRS ${Libserialport_INCLUDE_DIR})
set(Libserialport_DEFINITIONS ${PC_Liberialport_CFLAGS_OTHER})
endif()
if(Libserialport_FOUND AND NOT TARGET Libserialport::Libserialport)
add_library(Libserialport::Libserialport UNKNOWN IMPORTED)
set_target_properties(Libserialport::Libserialport PROPERTIES
IMPORTED_LOCATION "${Libserialport_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${PC_Libserialport_CFLAGS_OTHER}"
INTERFACE_INCLUDE_DIRECTORIES "${Libserialport_INCLUDE_DIR}"
)
endif()
+9
View File
@@ -0,0 +1,9 @@
(import (
let
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
in
fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
sha256 = lock.nodes.flake-compat.locked.narHash;
}
) { src = ./.; }).defaultNix
Generated
+27
View File
@@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1731319897,
"narHash": "sha256-PbABj4tnbWFMfBp6OcUK5iGy1QY+/Z96ZcLpooIbuEI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "dc460ec76cbff0e66e269457d7b728432263166c",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}
+44
View File
@@ -0,0 +1,44 @@
{
description = "A very basic flake";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
outputs =
{ self, nixpkgs, ... }@inputs:
let
systems = [
"x86_64-linux"
"aarch64-linux"
];
forEachSystem = nixpkgs.lib.genAttrs systems;
in
{
packages = forEachSystem (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
with pkgs;
{
blisp = callPackage ./blisp.nix { inherit self; };
default = self.packages.${system}.blisp;
}
);
devShells = forEachSystem (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
with pkgs;
{
default = mkShell {
name = "blisp-dev";
nativeBuildInputs = [ self.packages.${system}.default ];
};
}
);
};
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 598 B

+37 -40
View File
@@ -3,20 +3,8 @@
#define _LIBBLISP_H #define _LIBBLISP_H
#include <stdint.h> #include <stdint.h>
#include "blisp_chip.h" #include "blisp_chip.h"
#include "error_codes.h"
enum blisp_return {
BLISP_OK = 0,
BLISP_ERR_UNKNOWN = -1,
BLISP_ERR_NO_RESPONSE = -2,
BLISP_ERR_DEVICE_NOT_FOUND = -3,
BLISP_ERR_CANT_OPEN_DEVICE = -4,
// Can't auto-find device due it doesn't have native USB
BLISP_ERR_NO_AUTO_FIND_AVAILABLE = -5,
BLISP_ERR_PENDING = -6,
BLISP_ERR_CHIP_ERR = -7
};
struct blisp_segment_header { struct blisp_segment_header {
uint32_t dest_addr; uint32_t dest_addr;
@@ -28,6 +16,7 @@ struct blisp_segment_header {
struct blisp_device { struct blisp_device {
struct blisp_chip* chip; struct blisp_chip* chip;
void* serial_port; void* serial_port;
uint32_t serial_timeout; // in ms
bool is_usb; bool is_usb;
uint32_t current_baud_rate; uint32_t current_baud_rate;
uint8_t rx_buffer[5000]; // TODO: uint8_t rx_buffer[5000]; // TODO:
@@ -43,34 +32,42 @@ struct blisp_boot_info {
// TODO: Refactor variable names, so all will follow same semantic, like // TODO: Refactor variable names, so all will follow same semantic, like
// image_run, image_check etc. // image_run, image_check etc.
int32_t blisp_device_init(struct blisp_device* device, struct blisp_chip* chip); blisp_return_t blisp_device_init(struct blisp_device* device, struct blisp_chip* chip);
int32_t blisp_device_open(struct blisp_device* device, const char* port_name); blisp_return_t blisp_device_open(struct blisp_device* device, const char* port_name,
int32_t blisp_device_handshake(struct blisp_device* device, bool in_ef_loader); uint32_t baudrate);
int32_t blisp_device_get_boot_info(struct blisp_device* device, blisp_return_t blisp_device_handshake(struct blisp_device* device, bool in_ef_loader);
struct blisp_boot_info* boot_info); blisp_return_t blisp_device_get_boot_info(struct blisp_device* device,
int32_t blisp_device_load_boot_header(struct blisp_device* device, struct blisp_boot_info* boot_info);
uint8_t* boot_header); blisp_return_t blisp_device_load_boot_header(struct blisp_device* device,
int32_t blisp_device_load_segment_header( uint8_t* boot_header);
blisp_return_t blisp_device_load_segment_header(
struct blisp_device* device, struct blisp_device* device,
struct blisp_segment_header* segment_header); struct blisp_segment_header* segment_header);
int32_t blisp_device_load_segment_data(struct blisp_device* device, blisp_return_t blisp_device_load_segment_data(struct blisp_device* device,
uint8_t* segment_data, uint8_t* segment_data,
uint32_t segment_data_length); uint32_t segment_data_length);
int32_t blisp_device_write_memory(struct blisp_device* device, blisp_return_t blisp_device_write_memory(struct blisp_device* device,
uint32_t address, uint32_t address,
uint32_t value, uint32_t value,
bool wait_for_res); bool wait_for_res);
int32_t blisp_device_check_image(struct blisp_device* device); blisp_return_t blisp_device_check_image(struct blisp_device* device);
int32_t blisp_device_run_image(struct blisp_device* device); blisp_return_t blisp_device_run_image(struct blisp_device* device);
int32_t blisp_device_flash_erase(struct blisp_device* device, blisp_return_t blisp_device_flash_erase(struct blisp_device* device,
uint32_t start_address, uint32_t start_address,
uint32_t end_address); uint32_t end_address);
int32_t blisp_device_flash_write(struct blisp_device* device, blisp_return_t blisp_device_chip_erase(struct blisp_device* device);
uint32_t start_address, blisp_return_t blisp_device_flash_write(struct blisp_device* device,
uint8_t* payload, uint32_t start_address,
uint32_t payload_size); uint8_t* payload,
int32_t blisp_device_program_check(struct blisp_device* device); uint32_t payload_size);
int32_t blisp_device_reset(struct blisp_device* device);
blisp_return_t blisp_device_program_check(struct blisp_device* device);
blisp_return_t blisp_device_reset(struct blisp_device* device);
void blisp_device_close(struct blisp_device* device); void blisp_device_close(struct blisp_device* device);
#endif blisp_return_t bl808_load_clock_para(struct blisp_device* device,
bool irq_en, uint32_t baudrate);
blisp_return_t bl808_load_flash_para(struct blisp_device* device);
#endif
+4 -1
View File
@@ -28,4 +28,7 @@ extern struct blisp_chip blisp_chip_bl70x;
extern struct blisp_chip blisp_chip_bl808; extern struct blisp_chip blisp_chip_bl808;
extern struct blisp_chip blisp_chip_bl61x; extern struct blisp_chip blisp_chip_bl61x;
#endif extern struct bl808_bootheader_t bl808_header;
void fill_crcs(struct bl808_bootheader_t *bh);
#endif
+212
View File
@@ -9,6 +9,12 @@
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#if !defined(static_assert) && (defined(__GNUC__) || defined(__clang__)) \
&& defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \
&& __STDC_VERSION__ <= 201710L
#define static_assert _Static_assert
#endif
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct { typedef struct {
@@ -167,6 +173,212 @@ struct blflash_segment_header {
static_assert(sizeof(struct blflash_segment_header) == 16, static_assert(sizeof(struct blflash_segment_header) == 16,
"Segment header have wrong size"); "Segment header have wrong size");
struct bl808_spi_flash_cfg_t {
uint8_t ioMode; /*!< Serail flash interface mode,bit0-3:IF mode,bit4:unwrap */
uint8_t cReadSupport; /*!< Support continuous read mode,bit0:continuous read mode support,bit1:read mode cfg */
uint8_t clkDelay; /*!< SPI clock delay,bit0-3:delay,bit4-6:pad delay */
uint8_t clkInvert; /*!< SPI clock phase invert,bit0:clck invert,bit1:rx invert,bit2-4:pad delay,bit5-7:pad delay */
uint8_t resetEnCmd; /*!< Flash enable reset command */
uint8_t resetCmd; /*!< Flash reset command */
uint8_t resetCreadCmd; /*!< Flash reset continuous read command */
uint8_t resetCreadCmdSize; /*!< Flash reset continuous read command size */
uint8_t jedecIdCmd; /*!< JEDEC ID command */
uint8_t jedecIdCmdDmyClk; /*!< JEDEC ID command dummy clock */
uint8_t enter32BitsAddrCmd; /*!< Enter 32-bits addr command */
uint8_t exit32BitsAddrCmd; /*!< Exit 32-bits addr command */
uint8_t sectorSize; /*!< *1024bytes */
uint8_t mid; /*!< Manufacturer ID */
uint16_t pageSize; /*!< Page size */
uint8_t chipEraseCmd; /*!< Chip erase cmd */
uint8_t sectorEraseCmd; /*!< Sector erase command */
uint8_t blk32EraseCmd; /*!< Block 32K erase command,some Micron not support */
uint8_t blk64EraseCmd; /*!< Block 64K erase command */
uint8_t writeEnableCmd; /*!< Need before every erase or program */
uint8_t pageProgramCmd; /*!< Page program cmd */
uint8_t qpageProgramCmd; /*!< QIO page program cmd */
uint8_t qppAddrMode; /*!< QIO page program address mode */
uint8_t fastReadCmd; /*!< Fast read command */
uint8_t frDmyClk; /*!< Fast read command dummy clock */
uint8_t qpiFastReadCmd; /*!< QPI fast read command */
uint8_t qpiFrDmyClk; /*!< QPI fast read command dummy clock */
uint8_t fastReadDoCmd; /*!< Fast read dual output command */
uint8_t frDoDmyClk; /*!< Fast read dual output command dummy clock */
uint8_t fastReadDioCmd; /*!< Fast read dual io comamnd */
uint8_t frDioDmyClk; /*!< Fast read dual io command dummy clock */
uint8_t fastReadQoCmd; /*!< Fast read quad output comamnd */
uint8_t frQoDmyClk; /*!< Fast read quad output comamnd dummy clock */
uint8_t fastReadQioCmd; /*!< Fast read quad io comamnd */
uint8_t frQioDmyClk; /*!< Fast read quad io comamnd dummy clock */
uint8_t qpiFastReadQioCmd; /*!< QPI fast read quad io comamnd */
uint8_t qpiFrQioDmyClk; /*!< QPI fast read QIO dummy clock */
uint8_t qpiPageProgramCmd; /*!< QPI program command */
uint8_t writeVregEnableCmd; /*!< Enable write reg */
uint8_t wrEnableIndex; /*!< Write enable register index */
uint8_t qeIndex; /*!< Quad mode enable register index */
uint8_t busyIndex; /*!< Busy status register index */
uint8_t wrEnableBit; /*!< Write enable bit pos */
uint8_t qeBit; /*!< Quad enable bit pos */
uint8_t busyBit; /*!< Busy status bit pos */
uint8_t wrEnableWriteRegLen; /*!< Register length of write enable */
uint8_t wrEnableReadRegLen; /*!< Register length of write enable status */
uint8_t qeWriteRegLen; /*!< Register length of contain quad enable */
uint8_t qeReadRegLen; /*!< Register length of contain quad enable status */
uint8_t releasePowerDown; /*!< Release power down command */
uint8_t busyReadRegLen; /*!< Register length of contain busy status */
uint8_t readRegCmd[4]; /*!< Read register command buffer */
uint8_t writeRegCmd[4]; /*!< Write register command buffer */
uint8_t enterQpi; /*!< Enter qpi command */
uint8_t exitQpi; /*!< Exit qpi command */
uint8_t cReadMode; /*!< Config data for continuous read mode */
uint8_t cRExit; /*!< Config data for exit continuous read mode */
uint8_t burstWrapCmd; /*!< Enable burst wrap command */
uint8_t burstWrapCmdDmyClk; /*!< Enable burst wrap command dummy clock */
uint8_t burstWrapDataMode; /*!< Data and address mode for this command */
uint8_t burstWrapData; /*!< Data to enable burst wrap */
uint8_t deBurstWrapCmd; /*!< Disable burst wrap command */
uint8_t deBurstWrapCmdDmyClk; /*!< Disable burst wrap command dummy clock */
uint8_t deBurstWrapDataMode; /*!< Data and address mode for this command */
uint8_t deBurstWrapData; /*!< Data to disable burst wrap */
uint16_t timeEsector; /*!< 4K erase time */
uint16_t timeE32k; /*!< 32K erase time */
uint16_t timeE64k; /*!< 64K erase time */
uint16_t timePagePgm; /*!< Page program time */
uint16_t timeCe; /*!< Chip erase time in ms */
uint8_t pdDelay; /*!< Release power down command delay time for wake up */
uint8_t qeData; /*!< QE set data */
};
struct bl808_boot_flash_cfg_t {
uint32_t magiccode;
struct bl808_spi_flash_cfg_t cfg;
uint32_t crc32;
};
struct bl808_sys_clk_cfg_t {
uint8_t xtal_type;
uint8_t mcu_clk;
uint8_t mcu_clk_div;
uint8_t mcu_bclk_div;
uint8_t mcu_pbclk_div;
uint8_t lp_div;
uint8_t dsp_clk;
uint8_t dsp_clk_div;
uint8_t dsp_bclk_div;
uint8_t dsp_pbclk;
uint8_t dsp_pbclk_div;
uint8_t emi_clk;
uint8_t emi_clk_div;
uint8_t flash_clk_type;
uint8_t flash_clk_div;
uint8_t wifipll_pu;
uint8_t aupll_pu;
uint8_t cpupll_pu;
uint8_t mipipll_pu;
uint8_t uhspll_pu;
};
struct bl808_boot_clk_cfg_t {
uint32_t magiccode;
struct bl808_sys_clk_cfg_t cfg;
uint32_t crc32;
};
struct bl808_boot_basic_cfg_t {
uint32_t sign_type : 2; /* [1: 0] for sign */
uint32_t encrypt_type : 2; /* [3: 2] for encrypt */
uint32_t key_sel : 2; /* [5: 4] key slot */
uint32_t xts_mode : 1; /* [6] for xts mode */
uint32_t aes_region_lock : 1; /* [7] rsvd */
uint32_t no_segment : 1; /* [8] no segment info */
uint32_t rsvd_0 : 1; /* [9] boot2 enable(rsvd_0) */
uint32_t rsvd_1 : 1; /* [10] boot2 rollback(rsvd_1) */
uint32_t cpu_master_id : 4; /* [14: 11] master id */
uint32_t notload_in_bootrom : 1; /* [15] notload in bootrom */
uint32_t crc_ignore : 1; /* [16] ignore crc */
uint32_t hash_ignore : 1; /* [17] hash ignore */
uint32_t power_on_mm : 1; /* [18] power on mm */
uint32_t em_sel : 3; /* [21: 19] em_sel */
uint32_t cmds_en : 1; /* [22] command spliter enable */
uint32_t cmds_wrap_mode : 2; /* [24: 23] cmds wrap mode */
uint32_t cmds_wrap_len : 4; /* [28: 25] cmds wrap len */
uint32_t icache_invalid : 1; /* [29] icache invalid */
uint32_t dcache_invalid : 1; /* [30] dcache invalid */
uint32_t rsvd_3 : 1; /* [31] rsvd_3 */
uint32_t group_image_offset; /* flash controller offset */
uint32_t aes_region_len; /* aes region length */
uint32_t img_len_cnt; /* image length or segment count */
uint32_t hash[32 / 4]; /* hash of the image */
};
struct bl808_boot_cpu_cfg_t {
uint8_t config_enable; /* coinfig this cpu */
uint8_t halt_cpu; /* halt this cpu */
uint8_t cache_enable : 1; /* cache setting */
uint8_t cache_wa : 1; /* cache setting */
uint8_t cache_wb : 1; /* cache setting */
uint8_t cache_wt : 1; /* cache setting */
uint8_t cache_way_dis : 4; /* cache setting */
uint8_t rsvd;
uint32_t cache_range_h; /* cache range high */
uint32_t cache_range_l; /* cache range low */
uint32_t image_address_offset; /* image_address_offset */
uint32_t rsvd0; /* rsvd0 */
uint32_t msp_val; /* msp value */
};
struct bl808_aesiv_cfg_t {
uint8_t aesiv[16];
uint32_t crc32;
};
struct bl808_pkey_cfg_t {
uint8_t eckeyx[32]; /* ec key in boot header */
uint8_t eckeyy[32]; /* ec key in boot header */
uint32_t crc32;
};
struct bl808_sign_cfg_t {
uint32_t sig_len;
uint8_t signature[32];
uint32_t crc32;
};
struct bl808_bootheader_t {
uint32_t magiccode; /* 4 */
uint32_t rivison; /* 4 */
struct bl808_boot_flash_cfg_t flash_cfg; /* 4 + 84 + 4 */
struct bl808_boot_clk_cfg_t clk_cfg; /* 4 + 20 + 4 */
struct bl808_boot_basic_cfg_t basic_cfg; /* 4 + 4 + 4 + 4 + 4*8 */
struct bl808_boot_cpu_cfg_t cpu_cfg[3]; /*24*3 */
uint32_t boot2_pt_table_0_rsvd; /* address of partition table 0 */ /* 4 */
uint32_t boot2_pt_table_1_rsvd; /* address of partition table 1 */ /* 4 */
uint32_t flash_cfg_table_addr; /* address of flashcfg table list */ /* 4 */
uint32_t flash_cfg_table_len; /* flashcfg table list len */ /* 4 */
uint32_t rsvd0[8]; /* rsvd */
uint32_t rsvd1[8]; /* rsvd */
uint32_t rsvd3[5]; /* 20 */
uint32_t crc32; /* 4 */
};
static_assert(sizeof(struct bl808_bootheader_t) == 352,
"BL808 bootheader size mismatch");
#pragma pack(pop) #pragma pack(pop)
#endif #endif
+9 -39
View File
@@ -2,35 +2,20 @@
#ifndef _BLISP_UTIL_H #ifndef _BLISP_UTIL_H
#define _BLISP_UTIL_H #define _BLISP_UTIL_H
#include <stdarg.h> #include <stdint.h>
#include <stdio.h>
#ifdef WIN32 #ifdef WIN32
#include <windows.h> # include <windows.h>
#else #else
#include <time.h> # include <time.h>
#endif #endif
static void blisp_dlog(const char* format, ...) void blisp_dlog(const char* format, ...);
{
fflush(stdout);
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fputc('\n', stderr);
}
void blisp_dlog_no_nl(const char* format, ...);
static void sleep_ms(int milliseconds) { void sleep_ms(int milliseconds);
#ifdef WIN32
Sleep(milliseconds); uint32_t crc32_calculate(const void *data, size_t data_len);
#else
struct timespec ts;
ts.tv_sec = milliseconds / 1000;
ts.tv_nsec = (milliseconds % 1000) * 1000000;
nanosleep(&ts, NULL);
#endif
}
/** /**
* * Generated on Mon Jan 9 19:56:36 2023 * * Generated on Mon Jan 9 19:56:36 2023
@@ -80,19 +65,4 @@ static const uint32_t crc_table[256] = {
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
}; };
static uint32_t crc32_calculate(const void *data, size_t data_len) #endif
{
uint32_t crc = 0xffffffff;
const unsigned char *d = (const unsigned char *)data;
unsigned int tbl_idx;
while (data_len--) {
tbl_idx = (crc ^ *d) & 0xff;
crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff;
d++;
}
return (crc & 0xffffffff) ^ 0xffffffff;
}
#endif
+30
View File
@@ -0,0 +1,30 @@
#ifndef BLISP_S_RC_ERROR_CODES_H_
#define BLISP_S_RC_ERROR_CODES_H_
typedef enum {
BLISP_OK = 0,
// All error states must be <0.
// Generic error return; for when we are unsure what failed
BLISP_ERR_UNKNOWN = -1,
// Device did not respond, if serial link, could be that its not in boot
// loader
BLISP_ERR_NO_RESPONSE = -2,
// Failed to open a device, likely libusb or permissions
BLISP_ERR_DEVICE_NOT_FOUND = -3, // We could not find a device
BLISP_ERR_CANT_OPEN_DEVICE =
-4, // Couldn't open device; could it be permissions or its in use?
// Can't auto-find device due it doesn't have native USB
BLISP_ERR_NO_AUTO_FIND_AVAILABLE = -5,
BLISP_ERR_PENDING = -6, // Internal error for device is busy and to come back
BLISP_ERR_CHIP_ERR = -7, // Chip returned an error to us
BLISP_ERR_INVALID_CHIP_TYPE = -8, // unsupported chip type provided
BLISP_ERR_OUT_OF_MEMORY =
-9, // System could not allocate enough ram (highly unlikely)
BLISP_ERR_INVALID_COMMAND = -10, // Invalid user command provided
BLISP_ERR_CANT_OPEN_FILE = -11, // Cant open the firmware file to flash
BLISP_ERR_NOT_IMPLEMENTED = -12, // Non implemented function called
BLISP_ERR_API_ERROR = -13, // Errors outside our control from api's we
// integrate (Generally serial port/OS related)
} blisp_return_t;
#endif
+282 -84
View File
@@ -11,17 +11,40 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#endif #endif
#include <blisp_struct.h>
#define DEBUG #define DEBUG
int32_t blisp_device_init(struct blisp_device* device, static void drain(struct sp_port* port) {
struct blisp_chip* chip) { #if defined(__APPLE__) || defined(__FreeBSD__)
device->chip = chip; sp_drain(port);
device->is_usb = false; #else
return 0; (void)port; // unused
#endif
} }
int32_t blisp_device_open(struct blisp_device* device, const char* port_name) { blisp_return_t blisp_device_init(struct blisp_device* device,
int ret; struct blisp_chip* chip) {
device->chip = chip;
device->is_usb = false;
fill_crcs(&bl808_header);
if (device->chip->type == BLISP_CHIP_BL808) {
// TODO: For some reason the BL808 does not send pending ('PD') responses
// during long (i.e. erase) operations, so we must disable response
// timeouts. Further investigation is necessary.
device->serial_timeout = 0;
} else {
device->serial_timeout = 1000;
}
return BLISP_OK;
}
blisp_return_t blisp_device_open(struct blisp_device* device,
const char* port_name,
uint32_t baudrate) {
enum sp_return ret;
struct sp_port* serial_port = NULL; struct sp_port* serial_port = NULL;
if (port_name != NULL) { if (port_name != NULL) {
@@ -38,7 +61,7 @@ int32_t blisp_device_open(struct blisp_device* device, const char* port_name) {
ret = sp_list_ports(&port_list); ret = sp_list_ports(&port_list);
if (ret != SP_OK) { if (ret != SP_OK) {
blisp_dlog("Couldn't list ports, err: %d", ret); blisp_dlog("Couldn't list ports, err: %d", ret);
return BLISP_ERR_UNKNOWN; return BLISP_ERR_DEVICE_NOT_FOUND;
} }
for (int i = 0; port_list[i] != NULL; i++) { for (int i = 0; port_list[i] != NULL; i++) {
struct sp_port* port = port_list[i]; struct sp_port* port = port_list[i];
@@ -63,8 +86,7 @@ int32_t blisp_device_open(struct blisp_device* device, const char* port_name) {
ret = sp_open(serial_port, SP_MODE_READ_WRITE); ret = sp_open(serial_port, SP_MODE_READ_WRITE);
if (ret != SP_OK) { if (ret != SP_OK) {
blisp_dlog("SP open failed: %d", ret); blisp_dlog("SP open failed: %d", ret);
return BLISP_ERR_UNKNOWN; // TODO: Maybe this should be that it can't open return BLISP_ERR_CANT_OPEN_DEVICE;
// device?
} }
// TODO: Handle errors in following functions, although, none of them *should* // TODO: Handle errors in following functions, although, none of them *should*
// fail // fail
@@ -73,14 +95,10 @@ int32_t blisp_device_open(struct blisp_device* device, const char* port_name) {
sp_set_stopbits(serial_port, 1); sp_set_stopbits(serial_port, 1);
sp_set_flowcontrol(serial_port, SP_FLOWCONTROL_NONE); sp_set_flowcontrol(serial_port, SP_FLOWCONTROL_NONE);
uint32_t vid, pid; int vid, pid;
sp_get_port_usb_vid_pid(serial_port, &vid, &pid); sp_get_port_usb_vid_pid(serial_port, &vid, &pid);
device->is_usb = pid == 0xFFFF; device->is_usb = pid == 0xFFFF;
// if (device->is_usb) { device->current_baud_rate = baudrate;
// device->current_baud_rate = 2000000;
// } else {
device->current_baud_rate = 500000;
// }
#if 0 #if 0
int fd; int fd;
@@ -93,19 +111,19 @@ int32_t blisp_device_open(struct blisp_device* device, const char* port_name) {
#endif #endif
ret = sp_set_baudrate(serial_port, device->current_baud_rate); ret = sp_set_baudrate(serial_port, device->current_baud_rate);
if (ret != SP_OK) { if (ret != SP_OK) {
blisp_dlog("Set baud rate failed: %d... Also hello macOS user :)", ret); blisp_dlog("Set baud rate failed: %d... Also hello MacOS user :)", ret);
return BLISP_ERR_UNKNOWN; return BLISP_ERR_API_ERROR;
} }
device->serial_port = serial_port; device->serial_port = serial_port;
return BLISP_OK; return BLISP_OK;
} }
int32_t blisp_send_command(struct blisp_device* device, blisp_return_t blisp_send_command(struct blisp_device* device,
uint8_t command, uint8_t command,
void* payload, void* payload,
uint16_t payload_size, uint16_t payload_size,
bool add_checksum) { bool add_checksum) {
int ret; int ret;
struct sp_port* serial_port = device->serial_port; struct sp_port* serial_port = device->serial_port;
@@ -128,24 +146,23 @@ int32_t blisp_send_command(struct blisp_device* device,
sp_blocking_write(serial_port, device->tx_buffer, 4 + payload_size, 1000); sp_blocking_write(serial_port, device->tx_buffer, 4 + payload_size, 1000);
if (ret != (4 + payload_size)) { if (ret != (4 + payload_size)) {
blisp_dlog("Received error or not written all data: %d", ret); blisp_dlog("Received error or not written all data: %d", ret);
return BLISP_ERR_UNKNOWN; return BLISP_ERR_API_ERROR;
} }
#ifdef __APPLE__ drain(serial_port);
sp_drain(serial_port);
#endif
return BLISP_OK; return BLISP_OK;
} }
int32_t blisp_receive_response(struct blisp_device* device, blisp_return_t blisp_receive_response(struct blisp_device* device,
bool expect_payload) { bool expect_payload) {
// TODO: Check checksum // TODO: Check checksum
int ret; int ret;
struct sp_port* serial_port = device->serial_port; struct sp_port* serial_port = device->serial_port;
ret = sp_blocking_read(serial_port, &device->rx_buffer[0], 2, 1000); ret = sp_blocking_read(serial_port, &device->rx_buffer[0], 2, device->serial_timeout);
if (ret < 2) { if (ret < 2) {
blisp_dlog("Failed to receive response, ret: %d", ret); blisp_dlog("Failed to receive response, ret: %d", ret);
return BLISP_ERR_UNKNOWN; // TODO: Terrible return BLISP_ERR_NO_RESPONSE;
} else if (device->rx_buffer[0] == 'O' && device->rx_buffer[1] == 'K') { } else if (device->rx_buffer[0] == 'O' && device->rx_buffer[1] == 'K') {
if (expect_payload) { if (expect_payload) {
sp_blocking_read(serial_port, &device->rx_buffer[2], 2, sp_blocking_read(serial_port, &device->rx_buffer[2], 2,
@@ -167,11 +184,13 @@ int32_t blisp_receive_response(struct blisp_device* device,
} }
blisp_dlog("Failed to receive any response (err: %d, %d - %d)", ret, blisp_dlog("Failed to receive any response (err: %d, %d - %d)", ret,
device->rx_buffer[0], device->rx_buffer[1]); device->rx_buffer[0], device->rx_buffer[1]);
return BLISP_ERR_UNKNOWN; return BLISP_ERR_NO_RESPONSE;
} }
int32_t blisp_device_handshake(struct blisp_device* device, bool in_ef_loader) { blisp_return_t blisp_device_handshake(struct blisp_device* device,
bool in_ef_loader) {
int ret; int ret;
bool ok = false;
uint8_t handshake_buffer[600]; uint8_t handshake_buffer[600];
struct sp_port* serial_port = device->serial_port; struct sp_port* serial_port = device->serial_port;
@@ -185,8 +204,8 @@ int32_t blisp_device_handshake(struct blisp_device* device, bool in_ef_loader) {
sleep_ms(50); // Wait a bit so BootROM can init sleep_ms(50); // Wait a bit so BootROM can init
} }
uint32_t bytes_count = device->chip->handshake_byte_multiplier * uint32_t bytes_count = (uint32_t)(device->chip->handshake_byte_multiplier *
(float)device->current_baud_rate / 10.0f; (float)device->current_baud_rate / 10.0f);
if (bytes_count > 600) if (bytes_count > 600)
bytes_count = 600; bytes_count = 600;
memset(handshake_buffer, 'U', bytes_count); memset(handshake_buffer, 'U', bytes_count);
@@ -195,15 +214,15 @@ int32_t blisp_device_handshake(struct blisp_device* device, bool in_ef_loader) {
if (!in_ef_loader) { if (!in_ef_loader) {
if (device->is_usb) { if (device->is_usb) {
sp_blocking_write(serial_port, "BOUFFALOLAB5555RESET\0\0", 22, 100); sp_blocking_write(serial_port, "BOUFFALOLAB5555RESET\0\0", 22, 100);
#ifdef __APPLE__ drain(serial_port);
sp_drain(serial_port);
#endif
} }
} }
ret = sp_blocking_write(serial_port, handshake_buffer, bytes_count, 500); ret = sp_blocking_write(serial_port, handshake_buffer, bytes_count, 500);
// not sure about Apple part, but FreeBSD needs it
drain(serial_port);
if (ret < 0) { if (ret < 0) {
blisp_dlog("Handshake write failed, ret %d", ret); blisp_dlog("Handshake write failed, ret %d", ret);
return BLISP_ERR_UNKNOWN; return BLISP_ERR_API_ERROR;
} }
if (!in_ef_loader && !device->is_usb) { if (!in_ef_loader && !device->is_usb) {
@@ -211,21 +230,46 @@ int32_t blisp_device_handshake(struct blisp_device* device, bool in_ef_loader) {
sp_flush(serial_port, SP_BUF_INPUT); // Flush garbage out of RX sp_flush(serial_port, SP_BUF_INPUT); // Flush garbage out of RX
} }
ret = sp_blocking_read(serial_port, device->rx_buffer, 2, 50); if (device->chip->type == BLISP_CHIP_BL808) {
if (ret >= 2) { sleep_ms(300);
if (device->rx_buffer[0] == 'O' && device->rx_buffer[1] == 'K') { static const uint8_t second_handshake[] = { 0x50, 0x00, 0x08, 0x00, 0x38, 0xF0, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18 };
return BLISP_OK; ret = sp_blocking_write(serial_port, second_handshake, sizeof(second_handshake), 300);
if (ret < 0) {
blisp_dlog("Second handshake write failed, ret %d", ret);
return BLISP_ERR_API_ERROR;
} }
} }
ret = sp_blocking_read(serial_port, device->rx_buffer, 20, 50);
if (ret >= 2) {
for (uint8_t j = 0; j < (ret - 1); j++) {
if (device->rx_buffer[j] == 'O' && device->rx_buffer[j + 1] == 'K') {
ok = true;
}
}
}
if (ok) {
return BLISP_OK;
} else {
blisp_dlog("Received incorrect handshake response from chip (attempt %d/5).", i+1);
blisp_dlog_no_nl("Could not find 0x%02X 0x%02X ('O', 'K') in: ", 'O', 'K');
if (ret) {
for (uint8_t j=0; j <= ret; j++) {
blisp_dlog_no_nl("0x%02X ", device->rx_buffer[j]);
}
}
blisp_dlog("");
}
} }
blisp_dlog("Received no response from chip.");
blisp_dlog("Did not receive correct response from chip after 5 attempts.");
return BLISP_ERR_NO_RESPONSE; return BLISP_ERR_NO_RESPONSE;
} }
int32_t blisp_device_get_boot_info(struct blisp_device* device, blisp_return_t blisp_device_get_boot_info(struct blisp_device* device,
struct blisp_boot_info* boot_info) { struct blisp_boot_info* boot_info) {
int ret; blisp_return_t ret;
ret = blisp_send_command(device, 0x10, NULL, 0, false); ret = blisp_send_command(device, 0x10, NULL, 0, false);
if (ret < 0) if (ret < 0)
@@ -235,19 +279,22 @@ int32_t blisp_device_get_boot_info(struct blisp_device* device,
if (ret < 0) if (ret < 0)
return ret; return ret;
memcpy(boot_info->boot_rom_version, &device->rx_buffer[0], // TODO: Endianess; this may break on big endian machines
4); // TODO: Endianess memcpy(boot_info->boot_rom_version, &device->rx_buffer[0], 4);
if (device->chip->type == BLISP_CHIP_BL70X) { if (device->chip->type == BLISP_CHIP_BL70X) {
memcpy(boot_info->chip_id, &device->rx_buffer[16], 8); memcpy(boot_info->chip_id, &device->rx_buffer[16], 8);
} else {
memcpy(boot_info->chip_id, &device->rx_buffer[12], 6);
} }
// TODO: BL60X
return BLISP_OK; return BLISP_OK;
} }
// TODO: Use struct instead of uint8_t* // TODO: Use struct instead of uint8_t*
int32_t blisp_device_load_boot_header(struct blisp_device* device, blisp_return_t blisp_device_load_boot_header(struct blisp_device* device,
uint8_t* boot_header) { uint8_t* boot_header) {
int ret; blisp_return_t ret;
ret = blisp_send_command(device, 0x11, boot_header, 176, false); ret = blisp_send_command(device, 0x11, boot_header, 176, false);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -258,10 +305,10 @@ int32_t blisp_device_load_boot_header(struct blisp_device* device,
return BLISP_OK; return BLISP_OK;
} }
int32_t blisp_device_load_segment_header( blisp_return_t blisp_device_load_segment_header(
struct blisp_device* device, struct blisp_device* device,
struct blisp_segment_header* segment_header) { struct blisp_segment_header* segment_header) {
int ret; blisp_return_t ret;
ret = blisp_send_command(device, 0x17, segment_header, 16, false); ret = blisp_send_command(device, 0x17, segment_header, 16, false);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -272,10 +319,10 @@ int32_t blisp_device_load_segment_header(
return BLISP_OK; return BLISP_OK;
} }
int32_t blisp_device_load_segment_data(struct blisp_device* device, blisp_return_t blisp_device_load_segment_data(struct blisp_device* device,
uint8_t* segment_data, uint8_t* segment_data,
uint32_t segment_data_length) { uint32_t segment_data_length) {
int ret; blisp_return_t ret;
ret = blisp_send_command(device, 0x18, segment_data, segment_data_length, ret = blisp_send_command(device, 0x18, segment_data, segment_data_length,
false); false);
if (ret < 0) if (ret < 0)
@@ -287,8 +334,8 @@ int32_t blisp_device_load_segment_data(struct blisp_device* device,
return BLISP_OK; return BLISP_OK;
} }
int32_t blisp_device_check_image(struct blisp_device* device) { blisp_return_t blisp_device_check_image(struct blisp_device* device) {
int ret; blisp_return_t ret;
ret = blisp_send_command(device, 0x19, NULL, 0, false); ret = blisp_send_command(device, 0x19, NULL, 0, false);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -299,11 +346,11 @@ int32_t blisp_device_check_image(struct blisp_device* device) {
return BLISP_OK; return BLISP_OK;
} }
int32_t blisp_device_write_memory(struct blisp_device* device, blisp_return_t blisp_device_write_memory(struct blisp_device* device,
uint32_t address, uint32_t address,
uint32_t value, uint32_t value,
bool wait_for_res) { bool wait_for_res) {
int ret; blisp_return_t ret;
uint8_t payload[8]; uint8_t payload[8];
*(uint32_t*)(payload) = address; *(uint32_t*)(payload) = address;
*(uint32_t*)(payload + 4) = value; // TODO: Endianness *(uint32_t*)(payload + 4) = value; // TODO: Endianness
@@ -319,8 +366,8 @@ int32_t blisp_device_write_memory(struct blisp_device* device,
return BLISP_OK; return BLISP_OK;
} }
int32_t blisp_device_run_image(struct blisp_device* device) { blisp_return_t blisp_device_run_image(struct blisp_device* device) {
int ret; blisp_return_t ret;
if (device->chip->type == BLISP_CHIP_BL70X) { // ERRATA if (device->chip->type == BLISP_CHIP_BL70X) { // ERRATA
ret = blisp_device_write_memory(device, 0x4000F100, 0x4E424845, true); ret = blisp_device_write_memory(device, 0x4000F100, 0x4E424845, true);
@@ -347,34 +394,46 @@ int32_t blisp_device_run_image(struct blisp_device* device) {
return BLISP_OK; return BLISP_OK;
} }
int32_t blisp_device_flash_erase(struct blisp_device* device, blisp_return_t blisp_device_flash_erase(struct blisp_device* device,
uint32_t start_address, uint32_t start_address,
uint32_t end_address) { uint32_t end_address) {
uint8_t payload[8]; uint8_t payload[8];
*(uint32_t*)(payload + 0) = start_address; *(uint32_t*)(payload + 0) = start_address;
*(uint32_t*)(payload + 4) = end_address; *(uint32_t*)(payload + 4) = end_address;
int ret = blisp_send_command(device, 0x30, payload, 8, true); blisp_return_t ret = blisp_send_command(device, 0x30, payload, 8, true);
if (ret < 0) if (ret != BLISP_OK)
return ret; return ret;
do { do {
ret = blisp_receive_response(device, false); ret = blisp_receive_response(device, false);
} while (ret == BLISP_ERR_PENDING); } while (ret == BLISP_ERR_PENDING);
return 0; return ret;
} }
int32_t blisp_device_flash_write(struct blisp_device* device, blisp_return_t blisp_device_chip_erase(struct blisp_device* device) {
uint32_t start_address, blisp_return_t ret = blisp_send_command(device, 0x3C, NULL, 0, true);
uint8_t* payload, if (ret != BLISP_OK)
uint32_t payload_size) { return ret;
do {
ret = blisp_receive_response(device, false);
} while (ret == BLISP_ERR_PENDING);
return ret;
}
blisp_return_t blisp_device_flash_write(struct blisp_device* device,
uint32_t start_address,
uint8_t* payload,
uint32_t payload_size) {
// TODO: Add max payload size (8184?) // TODO: Add max payload size (8184?)
// TODO: Don't use malloc + add check // TODO: Don't use malloc + add check
uint8_t* buffer = malloc(4 + payload_size); uint8_t* buffer = malloc(4 + payload_size);
*((uint32_t*)(buffer)) = start_address; *((uint32_t*)(buffer)) = start_address;
memcpy(buffer + 4, payload, payload_size); memcpy(buffer + 4, payload, payload_size);
int ret = blisp_send_command(device, 0x31, buffer, payload_size + 4, true); blisp_return_t ret =
blisp_send_command(device, 0x31, buffer, payload_size + 4, true);
if (ret < 0) if (ret < 0)
goto exit1; goto exit1;
ret = blisp_receive_response(device, false); ret = blisp_receive_response(device, false);
@@ -383,7 +442,7 @@ exit1:
return ret; return ret;
} }
int32_t blisp_device_program_check(struct blisp_device* device) { blisp_return_t blisp_device_program_check(struct blisp_device* device) {
int ret = blisp_send_command(device, 0x3A, NULL, 0, true); int ret = blisp_send_command(device, 0x3A, NULL, 0, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
@@ -391,11 +450,11 @@ int32_t blisp_device_program_check(struct blisp_device* device) {
if (ret < 0) if (ret < 0)
return ret; return ret;
return 0; return BLISP_OK;
} }
int32_t blisp_device_reset(struct blisp_device* device) { blisp_return_t blisp_device_reset(struct blisp_device* device) {
int ret = blisp_send_command(device, 0x21, NULL, 0, true); blisp_return_t ret = blisp_send_command(device, 0x21, NULL, 0, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = blisp_receive_response(device, false); ret = blisp_receive_response(device, false);
@@ -408,4 +467,143 @@ int32_t blisp_device_reset(struct blisp_device* device) {
void blisp_device_close(struct blisp_device* device) { void blisp_device_close(struct blisp_device* device) {
struct sp_port* serial_port = device->serial_port; struct sp_port* serial_port = device->serial_port;
sp_close(serial_port); sp_close(serial_port);
} }
blisp_return_t bl808_load_clock_para(struct blisp_device* device,
bool irq_en, uint32_t baudrate) {
#define bl808_load_clock_para_payload_size 36
static_assert(bl808_load_clock_para_payload_size == sizeof(struct bl808_boot_clk_cfg_t) + 8,
"BL808 clock parameter struct size mismatch");
uint8_t payload[bl808_load_clock_para_payload_size] = { 0 };
uint32_t irq_enable = irq_en ? 1 : 0;
memcpy(&payload[0], &irq_enable, 4);
memcpy(&payload[4], &baudrate, 4);
memcpy(&payload[8], &bl808_header.clk_cfg, sizeof(struct bl808_boot_clk_cfg_t));
blisp_return_t ret = blisp_send_command(device, 0x22, payload,
bl808_load_clock_para_payload_size, true);
if (ret < 0)
return ret;
ret = blisp_receive_response(device, false);
if (ret < 0)
return ret;
return BLISP_OK;
}
blisp_return_t bl808_load_flash_para(struct blisp_device* device) {
// TODO: I don't understand why these parameters are the way they are,
// but at least they are labeled. Also, flash_io_mode and flash_clk_delay
// seem to be duplicated in the main spi_flash_cfg_t struct?
const uint8_t flash_pin = 0x4;
const uint8_t flash_clk_cfg = 0x41;
const uint8_t flash_io_mode = 0x01;
const uint8_t flash_clk_delay = 0;
// Yes, these values are (slightly) different to the ones in blisp_chip_bl808.c
// These values were obtained by observing the raw bytes sent by Bouffalo's
// own flashing software. So for whatever reason, the flash configuration needs
// to be different when flashing the chip vs. when the chip is running normally.
static const struct bl808_spi_flash_cfg_t cfg = {
.ioMode = 0x04,
.cReadSupport = 0x01,
.clkDelay = 0,
.clkInvert = 0,
.resetEnCmd = 0x66,
.resetCmd = 0x99,
.resetCreadCmd = 0xff,
.resetCreadCmdSize = 0x03,
.jedecIdCmd = 0x9f,
.jedecIdCmdDmyClk = 0,
.enter32BitsAddrCmd = 0xb7,
.exit32BitsAddrCmd = 0xe9,
.sectorSize = 0x04,
.mid = 0xef,
.pageSize = 0x100,
.chipEraseCmd = 0xc7,
.sectorEraseCmd = 0x20,
.blk32EraseCmd = 0x52,
.blk64EraseCmd = 0xd8,
.writeEnableCmd = 0x06,
.pageProgramCmd = 0x02,
.qpageProgramCmd = 0x32,
.qppAddrMode = 0,
.fastReadCmd = 0x0b,
.frDmyClk = 0x01,
.qpiFastReadCmd = 0x0b,
.qpiFrDmyClk = 0x01,
.fastReadDoCmd = 0x3b,
.frDoDmyClk = 0x01,
.fastReadDioCmd = 0xbb,
.frDioDmyClk = 0,
.fastReadQoCmd = 0x6b,
.frQoDmyClk = 0x01,
.fastReadQioCmd = 0xeb,
.frQioDmyClk = 0x02,
.qpiFastReadQioCmd = 0xeb,
.qpiFrQioDmyClk = 0x02,
.qpiPageProgramCmd = 0x02,
.writeVregEnableCmd = 0x50,
.wrEnableIndex = 0,
.qeIndex = 0x01,
.busyIndex = 0,
.wrEnableBit = 0x01,
.qeBit = 0x01,
.busyBit = 0,
.wrEnableWriteRegLen = 0x02,
.wrEnableReadRegLen = 0x01,
.qeWriteRegLen = 0x01,
.qeReadRegLen = 0x01,
.releasePowerDown = 0xab,
.busyReadRegLen = 0x01,
.readRegCmd[0] = 0x05,
.readRegCmd[1] = 0x35,
.readRegCmd[2] = 0,
.readRegCmd[3] = 0,
.writeRegCmd[0] = 0x01,
.writeRegCmd[1] = 0x31,
.writeRegCmd[2] = 0,
.writeRegCmd[3] = 0,
.enterQpi = 0x38,
.exitQpi = 0xff,
.cReadMode = 0xa0,
.cRExit = 0xff,
.burstWrapCmd = 0x77,
.burstWrapCmdDmyClk = 0x03,
.burstWrapDataMode = 0x02,
.burstWrapData = 0x40,
.deBurstWrapCmd = 0x77,
.deBurstWrapCmdDmyClk = 0x03,
.deBurstWrapDataMode = 0x02,
.deBurstWrapData = 0xf0,
.timeEsector = 0x12c,
.timeE32k = 0x4b0,
.timeE64k = 0x4b0,
.timePagePgm = 0x05,
.timeCe = 0x80e8,
.pdDelay = 0x03,
.qeData = 0,
};
#define bl808_load_flash_para_payload_size 88
static_assert(bl808_load_flash_para_payload_size == sizeof(struct bl808_spi_flash_cfg_t) + 4,
"BL808 flash parameter struct size mismatch");
uint8_t payload[bl808_load_flash_para_payload_size] = { 0 };
payload[0] = flash_pin;
payload[1] = flash_clk_cfg;
payload[2] = flash_io_mode;
payload[3] = flash_clk_delay;
memcpy(&payload[4], &cfg, sizeof(struct bl808_spi_flash_cfg_t));
blisp_return_t ret = blisp_send_command(device, 0x3b, payload,
bl808_load_flash_para_payload_size, true);
if (ret < 0)
return ret;
ret = blisp_receive_response(device, false);
if (ret < 0)
return ret;
return BLISP_OK;
}
+30 -22
View File
@@ -6,12 +6,16 @@
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
static int64_t blisp_easy_transport_read(struct blisp_easy_transport* transport, static blisp_return_t blisp_easy_transport_read(
void* buffer, struct blisp_easy_transport* transport,
uint32_t size) { void* buffer,
uint32_t size) {
if (transport->type == 0) { if (transport->type == 0) {
// TODO: Implement reading more than available // TODO: Implement reading more than available
memcpy(buffer, (uint8_t*)transport->data.memory.data_location + transport->data.memory.current_position, size); memcpy(buffer,
(uint8_t*)transport->data.memory.data_location +
transport->data.memory.current_position,
size);
transport->data.memory.current_position += size; transport->data.memory.current_position += size;
return size; return size;
} else { } else {
@@ -19,11 +23,14 @@ static int64_t blisp_easy_transport_read(struct blisp_easy_transport* transport,
} }
} }
static int64_t blisp_easy_transport_size(struct blisp_easy_transport* transport) { static blisp_return_t blisp_easy_transport_size(
struct blisp_easy_transport* transport) {
if (transport->type == 0) { if (transport->type == 0) {
return transport->data.memory.data_size; return transport->data.memory.data_size;
} else { } else {
// TODO: Implement // TODO: Implement
printf("%s() Warning: calling non-implemented function\n", __func__);
return BLISP_ERR_NOT_IMPLEMENTED;
} }
} }
@@ -63,7 +70,6 @@ int32_t blisp_easy_load_segment_data(
const uint16_t buffer_max_size = 4092; const uint16_t buffer_max_size = 4092;
#endif #endif
uint32_t sent_data = 0; uint32_t sent_data = 0;
uint32_t buffer_size = 0; uint32_t buffer_size = 0;
#ifdef _WIN32 #ifdef _WIN32
@@ -90,7 +96,7 @@ int32_t blisp_easy_load_segment_data(
sent_data += buffer_size; sent_data += buffer_size;
blisp_easy_report_progress(progress_callback, sent_data, segment_size); blisp_easy_report_progress(progress_callback, sent_data, segment_size);
} }
return 0; return BLISP_OK;
} }
int32_t blisp_easy_load_ram_image( int32_t blisp_easy_load_ram_image(
@@ -141,10 +147,10 @@ int32_t blisp_easy_load_ram_image(
return BLISP_OK; return BLISP_OK;
} }
int32_t blisp_easy_load_ram_app(struct blisp_device* device, int32_t blisp_easy_load_ram_app(
struct blisp_easy_transport* app_transport, struct blisp_device* device,
blisp_easy_progress_callback progress_callback) struct blisp_easy_transport* app_transport,
{ blisp_easy_progress_callback progress_callback) {
int32_t ret; int32_t ret;
// TODO: Rework // TODO: Rework
// region boot header fill // region boot header fill
@@ -291,7 +297,6 @@ int32_t blisp_easy_load_ram_app(struct blisp_device* device,
boot_header.crc32 = 0xDEADBEEF; boot_header.crc32 = 0xDEADBEEF;
// endregion // endregion
ret = blisp_device_load_boot_header(device, (uint8_t*)&boot_header); ret = blisp_device_load_boot_header(device, (uint8_t*)&boot_header);
if (ret != BLISP_OK) { if (ret != BLISP_OK) {
blisp_dlog("Failed to load boot header, ret: %d.", ret); blisp_dlog("Failed to load boot header, ret: %d.", ret);
@@ -302,9 +307,9 @@ int32_t blisp_easy_load_ram_app(struct blisp_device* device,
.dest_addr = device->chip->tcm_address, .dest_addr = device->chip->tcm_address,
.length = blisp_easy_transport_size(app_transport), .length = blisp_easy_transport_size(app_transport),
.reserved = 0, .reserved = 0,
.crc32 = 0 .crc32 = 0};
}; segment_header.crc32 = crc32_calculate(
segment_header.crc32 = crc32_calculate(&segment_header, 3 * sizeof(uint32_t)); // TODO: Make function &segment_header, 3 * sizeof(uint32_t)); // TODO: Make function
ret = blisp_device_load_segment_header(device, &segment_header); ret = blisp_device_load_segment_header(device, &segment_header);
if (ret != 0) { if (ret != 0) {
@@ -312,14 +317,14 @@ int32_t blisp_easy_load_ram_app(struct blisp_device* device,
return ret; return ret;
} }
ret = blisp_easy_load_segment_data(device, blisp_easy_transport_size(app_transport), ret = blisp_easy_load_segment_data(device,
blisp_easy_transport_size(app_transport),
app_transport, progress_callback); app_transport, progress_callback);
if (ret != 0) { if (ret != 0) {
// TODO: Error printing // TODO: Error printing
return ret; return ret;
} }
return BLISP_OK; return BLISP_OK;
} }
@@ -329,7 +334,7 @@ int32_t blisp_easy_flash_write(struct blisp_device* device,
uint32_t data_size, uint32_t data_size,
blisp_easy_progress_callback progress_callback) { blisp_easy_progress_callback progress_callback) {
int32_t ret; int32_t ret;
#ifdef __APPLE__ #if defined(__APPLE__) || defined(__FreeBSD__)
const uint16_t buffer_max_size = 372 * 1; const uint16_t buffer_max_size = 372 * 1;
#else #else
const uint16_t buffer_max_size = 2052; const uint16_t buffer_max_size = 2052;
@@ -349,13 +354,16 @@ int32_t blisp_easy_flash_write(struct blisp_device* device,
if (buffer_size > buffer_max_size) { if (buffer_size > buffer_max_size) {
buffer_size = buffer_max_size; buffer_size = buffer_max_size;
} }
blisp_easy_transport_read(data_transport, buffer, ret = blisp_easy_transport_read(data_transport, buffer, buffer_size);
buffer_size); // TODO: Error Handling if (ret < BLISP_OK) {
fprintf(stderr, "Failed to read firmware chunk! (ret:%d)\n ", ret);
return ret;
}
ret = blisp_device_flash_write(device, flash_location + sent_data, buffer, ret = blisp_device_flash_write(device, flash_location + sent_data, buffer,
buffer_size); buffer_size);
if (ret < BLISP_OK) { if (ret < BLISP_OK) {
// TODO: Error logigng: fprintf(stderr, "Failed to write firmware! (ret: fprintf(stderr, "Failed to write firmware! (ret:%d)\n ", ret);
// %d)\n", ret);
return ret; return ret;
} }
sent_data += buffer_size; sent_data += buffer_size;
+55
View File
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: MIT
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#ifdef WIN32
# include <windows.h>
#else
# include <time.h>
#endif
#include "blisp_util.h"
void blisp_dlog(const char* format, ...)
{
fflush(stdout);
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fputc('\n', stderr);
}
void blisp_dlog_no_nl(const char* format, ...) {
fflush(stdout);
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
}
void sleep_ms(int milliseconds) {
#ifdef WIN32
Sleep(milliseconds);
#else
struct timespec ts;
ts.tv_sec = milliseconds / 1000;
ts.tv_nsec = (milliseconds % 1000) * 1000000;
nanosleep(&ts, NULL);
#endif
}
uint32_t crc32_calculate(const void *data, size_t data_len)
{
uint32_t crc = 0xffffffff;
const unsigned char *d = (const unsigned char *)data;
unsigned int tbl_idx;
while (data_len--) {
tbl_idx = (crc ^ *d) & 0xff;
crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff;
d++;
}
return (crc & 0xffffffff) ^ 0xffffffff;
}
+2
View File
@@ -6,6 +6,8 @@
int64_t blisp_chip_bl60x_get_eflash_loader(uint8_t clk_type, uint8_t** firmware_buf_ptr) int64_t blisp_chip_bl60x_get_eflash_loader(uint8_t clk_type, uint8_t** firmware_buf_ptr)
{ {
(void)clk_type; // unused
uint8_t* firmware_buf = malloc(sizeof(bl60x_eflash_loader_bin)); uint8_t* firmware_buf = malloc(sizeof(bl60x_eflash_loader_bin));
memcpy(firmware_buf, bl60x_eflash_loader_bin, sizeof(bl60x_eflash_loader_bin)); memcpy(firmware_buf, bl60x_eflash_loader_bin, sizeof(bl60x_eflash_loader_bin));
*(firmware_buf + 0xE0) = 4; // TODO: 40 MHz clock *(firmware_buf + 0xE0) = 4; // TODO: 40 MHz clock
+2
View File
@@ -6,6 +6,8 @@
int64_t blisp_chip_bl70x_get_eflash_loader(uint8_t clk_type, uint8_t** firmware_buf_ptr) int64_t blisp_chip_bl70x_get_eflash_loader(uint8_t clk_type, uint8_t** firmware_buf_ptr)
{ {
(void) clk_type; // ununsed
uint8_t* firmware_buf = malloc(sizeof(bl70x_eflash_loader_bin)); uint8_t* firmware_buf = malloc(sizeof(bl70x_eflash_loader_bin));
memcpy(firmware_buf, bl70x_eflash_loader_bin, sizeof(bl70x_eflash_loader_bin)); memcpy(firmware_buf, bl70x_eflash_loader_bin, sizeof(bl70x_eflash_loader_bin));
*(firmware_buf + 0xE0) = 1; // TODO: 32 MHz clock *(firmware_buf + 0xE0) = 1; // TODO: 32 MHz clock
+224 -4
View File
@@ -1,11 +1,231 @@
// SPDX-License-Identifier: MIT /*
* Some parts of this source code belongs to Bouffalo Labs
* COPYRIGHT(c) 2020 Bouffalo Lab , License: Apache
*/
#include "blisp.h" #include "blisp.h"
#include "blisp_struct.h"
#include "blisp_util.h"
#include <stddef.h>
struct blisp_chip blisp_chip_bl808 = { struct blisp_chip blisp_chip_bl808 = {
.type = BLISP_CHIP_BL808, .type = BLISP_CHIP_BL808,
.type_str = "bl808", .type_str = "bl808",
.usb_isp_available = true, // TODO: Only for BL808D :-( .usb_isp_available = true, // TODO: Only for BL808D :-(
.default_xtal = "-", // ? .default_xtal = "-", // XXX: bfl software marks this as "Auto (0x07)"
.handshake_byte_multiplier = 0.003f, .handshake_byte_multiplier = 0.006f,
.get_eflash_loader = NULL .load_eflash_loader = NULL
}; };
struct bl808_bootheader_t bl808_header = {
.magiccode = 0x504e4642,
.rivison = 0x00000001,
/*flash config */
.flash_cfg.magiccode = 0x47464346,
.flash_cfg.cfg.ioMode = 0x11, /*!< Serail flash interface mode,bit0-3:IF mode,bit4:unwrap */
.flash_cfg.cfg.cReadSupport = 0x00, /*!< Support continuous read mode,bit0:continuous read mode support,bit1:read mode cfg */
.flash_cfg.cfg.clkDelay = 0x01, /*!< SPI clock delay,bit0-3:delay,bit4-6:pad delay */
.flash_cfg.cfg.clkInvert = 0x01, /*!< SPI clock phase invert,bit0:clck invert,bit1:rx invert,bit2-4:pad delay,bit5-7:pad delay */
.flash_cfg.cfg.resetEnCmd = 0x66, /*!< Flash enable reset command */
.flash_cfg.cfg.resetCmd = 0x99, /*!< Flash reset command */
.flash_cfg.cfg.resetCreadCmd = 0xff, /*!< Flash reset continuous read command */
.flash_cfg.cfg.resetCreadCmdSize = 0x03, /*!< Flash reset continuous read command size */
.flash_cfg.cfg.jedecIdCmd = 0x9f, /*!< JEDEC ID command */
.flash_cfg.cfg.jedecIdCmdDmyClk = 0x00, /*!< JEDEC ID command dummy clock */
.flash_cfg.cfg.enter32BitsAddrCmd = 0xb7, /*!< Enter 32-bits addr command */
.flash_cfg.cfg.exit32BitsAddrCmd = 0xe9, /*!< Exit 32-bits addr command */
.flash_cfg.cfg.sectorSize = 0x04, /*!< *1024bytes */
.flash_cfg.cfg.mid = 0x00, /*!< Manufacturer ID */
.flash_cfg.cfg.pageSize = 0x100, /*!< Page size */
.flash_cfg.cfg.chipEraseCmd = 0xc7, /*!< Chip erase cmd */
.flash_cfg.cfg.sectorEraseCmd = 0x20, /*!< Sector erase command */
.flash_cfg.cfg.blk32EraseCmd = 0x52, /*!< Block 32K erase command,some Micron not support */
.flash_cfg.cfg.blk64EraseCmd = 0xd8, /*!< Block 64K erase command */
.flash_cfg.cfg.writeEnableCmd = 0x06, /*!< Need before every erase or program */
.flash_cfg.cfg.pageProgramCmd = 0x02, /*!< Page program cmd */
.flash_cfg.cfg.qpageProgramCmd = 0x32, /*!< QIO page program cmd */
.flash_cfg.cfg.qppAddrMode = 0x00, /*!< QIO page program address mode */
.flash_cfg.cfg.fastReadCmd = 0x0b, /*!< Fast read command */
.flash_cfg.cfg.frDmyClk = 0x01, /*!< Fast read command dummy clock */
.flash_cfg.cfg.qpiFastReadCmd = 0x0b, /*!< QPI fast read command */
.flash_cfg.cfg.qpiFrDmyClk = 0x01, /*!< QPI fast read command dummy clock */
.flash_cfg.cfg.fastReadDoCmd = 0x3b, /*!< Fast read dual output command */
.flash_cfg.cfg.frDoDmyClk = 0x01, /*!< Fast read dual output command dummy clock */
.flash_cfg.cfg.fastReadDioCmd = 0xbb, /*!< Fast read dual io comamnd */
.flash_cfg.cfg.frDioDmyClk = 0x00, /*!< Fast read dual io command dummy clock */
.flash_cfg.cfg.fastReadQoCmd = 0x6b, /*!< Fast read quad output comamnd */
.flash_cfg.cfg.frQoDmyClk = 0x01, /*!< Fast read quad output comamnd dummy clock */
.flash_cfg.cfg.fastReadQioCmd = 0xeb, /*!< Fast read quad io comamnd */
.flash_cfg.cfg.frQioDmyClk = 0x02, /*!< Fast read quad io comamnd dummy clock */
.flash_cfg.cfg.qpiFastReadQioCmd = 0xeb, /*!< QPI fast read quad io comamnd */
.flash_cfg.cfg.qpiFrQioDmyClk = 0x02, /*!< QPI fast read QIO dummy clock */
.flash_cfg.cfg.qpiPageProgramCmd = 0x02, /*!< QPI program command */
.flash_cfg.cfg.writeVregEnableCmd = 0x50, /*!< Enable write reg */
.flash_cfg.cfg.wrEnableIndex = 0x00, /*!< Write enable register index */
.flash_cfg.cfg.qeIndex = 0x01, /*!< Quad mode enable register index */
.flash_cfg.cfg.busyIndex = 0x00, /*!< Busy status register index */
.flash_cfg.cfg.wrEnableBit = 0x01, /*!< Write enable bit pos */
.flash_cfg.cfg.qeBit = 0x01, /*!< Quad enable bit pos */
.flash_cfg.cfg.busyBit = 0x00, /*!< Busy status bit pos */
.flash_cfg.cfg.wrEnableWriteRegLen = 0x02, /*!< Register length of write enable */
.flash_cfg.cfg.wrEnableReadRegLen = 0x01, /*!< Register length of write enable status */
.flash_cfg.cfg.qeWriteRegLen = 0x02, /*!< Register length of contain quad enable */
.flash_cfg.cfg.qeReadRegLen = 0x01, /*!< Register length of contain quad enable status */
.flash_cfg.cfg.releasePowerDown = 0xab, /*!< Release power down command */
.flash_cfg.cfg.busyReadRegLen = 0x01, /*!< Register length of contain busy status */
.flash_cfg.cfg.readRegCmd[0] = 0x05, /*!< Read register command buffer */
.flash_cfg.cfg.readRegCmd[1] = 0x35, /*!< Read register command buffer */
.flash_cfg.cfg.readRegCmd[2] = 0x00, /*!< Read register command buffer */
.flash_cfg.cfg.readRegCmd[3] = 0x00, /*!< Read register command buffer */
.flash_cfg.cfg.writeRegCmd[0] = 0x01, /*!< Write register command buffer */
.flash_cfg.cfg.writeRegCmd[1] = 0x01, /*!< Write register command buffer */
.flash_cfg.cfg.writeRegCmd[2] = 0x00, /*!< Write register command buffer */
.flash_cfg.cfg.writeRegCmd[3] = 0x00, /*!< Write register command buffer */
.flash_cfg.cfg.enterQpi = 0x38, /*!< Enter qpi command */
.flash_cfg.cfg.exitQpi = 0xff, /*!< Exit qpi command */
.flash_cfg.cfg.cReadMode = 0x20, /*!< Config data for continuous read mode */
.flash_cfg.cfg.cRExit = 0xf0, /*!< Config data for exit continuous read mode */
.flash_cfg.cfg.burstWrapCmd = 0x77, /*!< Enable burst wrap command */
.flash_cfg.cfg.burstWrapCmdDmyClk = 0x03, /*!< Enable burst wrap command dummy clock */
.flash_cfg.cfg.burstWrapDataMode = 0x02, /*!< Data and address mode for this command */
.flash_cfg.cfg.burstWrapData = 0x40, /*!< Data to enable burst wrap */
.flash_cfg.cfg.deBurstWrapCmd = 0x77, /*!< Disable burst wrap command */
.flash_cfg.cfg.deBurstWrapCmdDmyClk = 0x03, /*!< Disable burst wrap command dummy clock */
.flash_cfg.cfg.deBurstWrapDataMode = 0x02, /*!< Data and address mode for this command */
.flash_cfg.cfg.deBurstWrapData = 0xf0, /*!< Data to disable burst wrap */
.flash_cfg.cfg.timeEsector = 300, /*!< 4K erase time */
.flash_cfg.cfg.timeE32k = 1200, /*!< 32K erase time */
.flash_cfg.cfg.timeE64k = 1200, /*!< 64K erase time */
.flash_cfg.cfg.timePagePgm = 50, /*!< Page program time */
.flash_cfg.cfg.timeCe = 30000, /*!< Chip erase time in ms */
.flash_cfg.cfg.pdDelay = 20, /*!< Release power down command delay time for wake up */
.flash_cfg.cfg.qeData = 0, /*!< QE set data */
.flash_cfg.crc32 = 0xdeadbeef,
/* clock cfg */
.clk_cfg.magiccode = 0x47464350,
.clk_cfg.cfg.xtal_type = 0x07, /*!< 0:None,1:24M,2:32M,3:38.4M,4:40M,5:26M,6:RC32M */
.clk_cfg.cfg.mcu_clk = 0x04, /*!< mcu_clk 0:RC32M,1:Xtal,2:cpupll 400M,3:wifipll 192M,4:wifipll 320M */
.clk_cfg.cfg.mcu_clk_div = 0x00,
.clk_cfg.cfg.mcu_bclk_div = 0x00,
.clk_cfg.cfg.mcu_pbclk_div = 0x03,
.clk_cfg.cfg.lp_div = 0x01,
.clk_cfg.cfg.dsp_clk = 0x03, /* 0:RC32M,1:Xtal,2:wifipll 240M,3:wifipll 320M,4:cpupll 400M */
.clk_cfg.cfg.dsp_clk_div = 0x00,
.clk_cfg.cfg.dsp_bclk_div = 0x01,
.clk_cfg.cfg.dsp_pbclk = 0x02, /* 0:RC32M,1:Xtal,2:wifipll 160M,3:cpupll 160M,4:wifipll 240M */
.clk_cfg.cfg.dsp_pbclk_div = 0x00,
.clk_cfg.cfg.emi_clk = 0x02, /*!< 0:mcu pbclk,1:cpupll 200M,2:wifipll 320M,3:cpupll 400M */
.clk_cfg.cfg.emi_clk_div = 0x01,
.clk_cfg.cfg.flash_clk_type = 0x01, /*!< 0:wifipll 120M,1:xtal,2:cpupll 100M,3:wifipll 80M,4:bclk,5:wifipll 96M */
.clk_cfg.cfg.flash_clk_div = 0x00,
.clk_cfg.cfg.wifipll_pu = 0x01,
.clk_cfg.cfg.aupll_pu = 0x01,
.clk_cfg.cfg.cpupll_pu = 0x01,
.clk_cfg.cfg.mipipll_pu = 0x01,
.clk_cfg.cfg.uhspll_pu = 0x01,
.clk_cfg.crc32 = 0xdeadbeef,
/* basic cfg */
.basic_cfg.sign_type = 0x0, /* [1: 0] for sign */
.basic_cfg.encrypt_type = 0x0, /* [3: 2] for encrypt */
.basic_cfg.key_sel = 0x0, /* [5: 4] key slot */
.basic_cfg.xts_mode = 0x0, /* [6] for xts mode */
.basic_cfg.aes_region_lock = 0x0, /* [7] rsvd */
.basic_cfg.no_segment = 0x1, /* [8] no segment info */
.basic_cfg.rsvd_0 = 0x0, /* [9] boot2 enable(rsvd_0) */
.basic_cfg.rsvd_1 = 0x0, /* [10] boot2 rollback(rsvd_1) */
.basic_cfg.cpu_master_id = 0x0, /* [14: 11] master id */
.basic_cfg.notload_in_bootrom = 0x0, /* [15] notload in bootrom */
.basic_cfg.crc_ignore = 0x1, /* [16] ignore crc */
.basic_cfg.hash_ignore = 0x1, /* [17] hash ignore */
.basic_cfg.power_on_mm = 0x1, /* [18] power on mm */
.basic_cfg.em_sel = 0x1, /* [21: 19] em_sel */
.basic_cfg.cmds_en = 0x1, /* [22] command spliter enable */
#if 0
# 0 : cmds bypass wrap commands to macro, original mode;
# 1 : cmds handle wrap commands, original mode;
# 2 : cmds bypass wrap commands to macro, cmds force wrap16 * 4 splitted into two wrap8 * 4;
# 3 : cmds handle wrap commands, cmds force wrap16 * 4 splitted into two wrap8 * 4
#endif
.basic_cfg.cmds_wrap_mode = 0x1, /* [24: 23] cmds wrap mode */
#if 0
# 0 : SF_CTRL_WRAP_LEN_8, 1 : SF_CTRL_WRAP_LEN_16, 2 : SF_CTRL_WRAP_LEN_32,
# 3 : SF_CTRL_WRAP_LEN_64, 9 : SF_CTRL_WRAP_LEN_4096
#endif
.basic_cfg.cmds_wrap_len = 0x9, /* [28: 25] cmds wrap len */
.basic_cfg.icache_invalid = 0x1, /* [29] icache invalid */
.basic_cfg.dcache_invalid = 0x1, /* [30] dcache invalid */
.basic_cfg.rsvd_3 = 0x0, /* [31] rsvd_3 */
#ifdef BFLB_BOOT2
.basic_cfg.group_image_offset = 0x00002000, /* flash controller offset */
#else
.basic_cfg.group_image_offset = 0x00001000, /* flash controller offset */
#endif
.basic_cfg.aes_region_len = 0x00000000, /* aes region length */
.basic_cfg.img_len_cnt = 0x00010000, /* image length or segment count */
.basic_cfg.hash = { 0xdeadbeef }, /* hash of the image */
/* cpu cfg */
.cpu_cfg[0].config_enable = 0x01, /* coinfig this cpu */
.cpu_cfg[0].halt_cpu = 0x0, /* halt this cpu */
.cpu_cfg[0].cache_enable = 0x0, /* cache setting :only for BL Cache */
.cpu_cfg[0].cache_wa = 0x0, /* cache setting :only for BL Cache*/
.cpu_cfg[0].cache_wb = 0x0, /* cache setting :only for BL Cache*/
.cpu_cfg[0].cache_wt = 0x0, /* cache setting :only for BL Cache*/
.cpu_cfg[0].cache_way_dis = 0x0, /* cache setting :only for BL Cache*/
.cpu_cfg[0].rsvd = 0x0,
.cpu_cfg[0].cache_range_h = 0x00000000,
.cpu_cfg[0].cache_range_l = 0x00000000,
/* image_address_offset */
.cpu_cfg[0].image_address_offset = 0x0,
.cpu_cfg[0].rsvd0 = 0x58000000, /* rsvd0 */
.cpu_cfg[0].msp_val = 0x00000000, /* msp value */
/* cpu cfg */
.cpu_cfg[1].config_enable = 0x0, /* coinfig this cpu */
.cpu_cfg[1].halt_cpu = 0x0, /* halt this cpu */
.cpu_cfg[1].cache_enable = 0x0, /* cache setting :only for BL Cache */
.cpu_cfg[1].cache_wa = 0x0, /* cache setting :only for BL Cache*/
.cpu_cfg[1].cache_wb = 0x0, /* cache setting :only for BL Cache*/
.cpu_cfg[1].cache_wt = 0x0, /* cache setting :only for BL Cache*/
.cpu_cfg[1].cache_way_dis = 0x0, /* cache setting :only for BL Cache*/
.cpu_cfg[1].rsvd = 0x0,
.cpu_cfg[1].cache_range_h = 0x00000000,
.cpu_cfg[1].cache_range_l = 0x00000000,
/* image_address_offset */
.cpu_cfg[1].image_address_offset = 0x0,
.cpu_cfg[1].rsvd0 = 0x58000000, /* rsvd0 */
.cpu_cfg[1].msp_val = 0x00000000, /* msp value */
/* address of partition table 0 */ /* 4 */
.boot2_pt_table_0_rsvd = 0x00000000,
/* address of partition table 1 */ /* 4 */
.boot2_pt_table_1_rsvd = 0x00000000,
/* address of flashcfg table list */ /* 4 */
.flash_cfg_table_addr = 0x00000000,
/* flashcfg table list len */ /* 4 */
.flash_cfg_table_len = 0x00000000,
.rsvd1[0] = 0x20000320,
.rsvd1[1] = 0x00000000,
.rsvd1[2] = 0x2000F038,
.rsvd1[3] = 0x18000000,
.crc32 = 0xdeadbeef /* 4 */
};
void fill_crcs(struct bl808_bootheader_t *bh) {
bh->flash_cfg.crc32 = crc32_calculate((unsigned char *) &bh->flash_cfg.cfg, sizeof(struct bl808_spi_flash_cfg_t));
bh->clk_cfg.crc32 = crc32_calculate((unsigned char *) &bh->clk_cfg.cfg, sizeof(struct bl808_sys_clk_cfg_t));
bh->crc32 = crc32_calculate((unsigned char *) bh, sizeof(struct bl808_bootheader_t) - 4);
}
+9
View File
@@ -0,0 +1,9 @@
(import (
let
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
in
fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
sha256 = lock.nodes.flake-compat.locked.narHash;
}
) { src = ./.; }).shellNix
+28 -6
View File
@@ -1,20 +1,42 @@
set(ARGTABLE3_ENABLE_TESTS OFF CACHE BOOL "Enable unit tests") set(ARGTABLE3_ENABLE_TESTS OFF CACHE BOOL "Enable unit tests")
set(ARGTABLE3_ENABLE_EXAMPLES OFF CACHE BOOL "Enable examples") set(ARGTABLE3_ENABLE_EXAMPLES OFF CACHE BOOL "Enable examples")
#set(ARGTABLE3_REPLACE_GETOPT OFF CACHE BOOL "Replace getopt in the system C library") #set(ARGTABLE3_REPLACE_GETOPT OFF CACHE BOOL "Replace getopt in the system C library")
add_subdirectory(${CMAKE_SOURCE_DIR}/vendor/argtable3 ${CMAKE_CURRENT_BINARY_DIR}/argtable3)
add_executable(blisp src/main.c src/cmd/write.c src/util.c src/common.c src/cmd/iot.c) add_executable(blisp src/main.c src/cmd/write.c src/util.c src/common.c src/cmd/iot.c)
target_include_directories(blisp PRIVATE add_subdirectory(src/file_parsers)
"${CMAKE_SOURCE_DIR}/include"
if(BLISP_USE_SYSTEM_LIBRARIES)
find_package(Argtable3 REQUIRED)
else()
add_subdirectory(${CMAKE_SOURCE_DIR}/vendor/argtable3 ${CMAKE_CURRENT_BINARY_DIR}/argtable3)
target_include_directories(blisp PRIVATE
"${CMAKE_SOURCE_DIR}/vendor/argtable3/src") "${CMAKE_SOURCE_DIR}/vendor/argtable3/src")
endif()
target_include_directories(blisp PRIVATE
"${CMAKE_SOURCE_DIR}/include")
target_link_libraries(blisp PRIVATE target_link_libraries(blisp PRIVATE
argtable3 argtable3::argtable3
libblisp_static) libblisp_static file_parsers)
if (NOT CMAKE_C_COMPILER_ID MATCHES "MSVC")
target_compile_options(libblisp_obj PRIVATE -Wall -Wextra -Wpedantic)
else()
# MSVC does not support 'extra' and 'pedantic' levels to warnings.
# `/Wall` seems to generate way too many non-actionable output marked as warnings.
# We settle for `/W4`.
# https://learn.microsoft.com/en-us/cpp/build/reference/compiler-option-warning-level?view=msvc-170
target_compile_options(libblisp_obj PRIVATE -W4)
endif()
if (WIN32) if (WIN32)
target_link_libraries(blisp PRIVATE Setupapi.lib) target_link_libraries(blisp PRIVATE Setupapi.lib)
elseif (APPLE) elseif (APPLE)
target_link_libraries(blisp PRIVATE "-framework IOKit" "-framework CoreFoundation") target_link_libraries(blisp PRIVATE "-framework IOKit" "-framework CoreFoundation")
endif () endif ()
install(TARGETS blisp DESTINATION bin)
+11 -3
View File
@@ -2,12 +2,20 @@
#ifndef BLISP_CMD_H #ifndef BLISP_CMD_H
#define BLISP_CMD_H #define BLISP_CMD_H
#include <stdint.h> #if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
#include <unistd.h>
#elif defined(_WIN32) || defined(WIN32)
#include <io.h>
#define R_OK 4
#define access _access
#endif
#include <stdint.h>
#include "error_codes.h"
struct cmd { struct cmd {
const char* name; const char* name;
int8_t (*args_init)(); blisp_return_t (*args_init)();
uint8_t (*args_parse_exec)(int argc, char** argv); blisp_return_t (*args_parse_exec)(int argc, char** argv);
void (*args_print_syntax)(); void (*args_print_syntax)();
void (*args_free)(); void (*args_free)();
}; };
+92 -44
View File
@@ -1,7 +1,8 @@
#include <argtable3.h>
#include <blisp_easy.h> #include <blisp_easy.h>
#include "../cmd.h" #include "../cmd.h"
#include "../common.h" #include "../common.h"
#include <argtable3.h>
#define REG_EXTENDED 1 #define REG_EXTENDED 1
#define REG_ICASE (REG_EXTENDED << 1) #define REG_ICASE (REG_EXTENDED << 1)
@@ -9,22 +10,55 @@
static struct arg_rex* cmd; static struct arg_rex* cmd;
static struct arg_file* single_download; static struct arg_file* single_download;
static struct arg_int* single_download_location; static struct arg_int* single_download_location;
static struct arg_str *port_name, *chip_type; // TODO: Make this common static struct arg_str *port_name, *chip_type; // TODO: Make this common
static struct arg_int *baudrate;
static struct arg_lit* reset; static struct arg_lit* reset;
static struct arg_lit* chiperase;
static struct arg_end* end; static struct arg_end* end;
static void* cmd_iot_argtable[7]; static void* cmd_iot_argtable[9];
static void cmd_iot_args_print_glossary();
void blisp_single_download() blisp_return_t blisp_single_download(void) {
{
struct blisp_device device; struct blisp_device device;
int32_t ret; blisp_return_t ret;
if (blisp_common_init_device(&device, port_name, chip_type) != 0) { uint32_t baud = DEFAULT_BAUDRATE;
return; if (baudrate->count == 1) {
if (*baudrate->ival < 0) {
fprintf(stderr, "Baud rate cannot be negative!\n");
return BLISP_ERR_INVALID_COMMAND;
} else {
baud = *baudrate->ival;
}
} }
if (blisp_common_prepare_flash(&device) != 0) { if (access(single_download->filename[0], R_OK) != 0) {
// TODO: Error handling // File not accessible, error out.
fprintf(stderr, "Input firmware not found: %s\n", single_download->filename[0]);
cmd_iot_args_print_glossary(); /* Print help to assist user */
/* No need to free memory, will now exit with ret code 1 */
return 1;
}
ret = blisp_common_init_device(&device, port_name, chip_type, baud);
if (ret != BLISP_OK) {
return ret;
}
ret = blisp_common_prepare_flash(&device);
if (ret != BLISP_OK) {
// TODO: user-friendly error messages
fprintf(stderr, "Failed to initialize device, ret: %d\n", ret);
goto exit1;
}
if (chiperase->count) {
printf("Performing a chip erase, this might take a while...\n");
ret = blisp_device_chip_erase(&device);
if (ret == BLISP_OK) {
printf("Erase complete!\n");
} else {
fprintf(stderr, "Failed to erase, ret: %d\n", ret);
}
goto exit1; goto exit1;
} }
@@ -32,6 +66,7 @@ void blisp_single_download()
if (data_file == NULL) { if (data_file == NULL) {
fprintf(stderr, "Failed to open data file \"%s\".\n", fprintf(stderr, "Failed to open data file \"%s\".\n",
single_download->filename[0]); single_download->filename[0]);
ret = BLISP_ERR_CANT_OPEN_FILE;
goto exit1; goto exit1;
} }
fseek(data_file, 0, SEEK_END); fseek(data_file, 0, SEEK_END);
@@ -39,11 +74,11 @@ void blisp_single_download()
rewind(data_file); rewind(data_file);
printf("Erasing the area, this might take a while...\n"); printf("Erasing the area, this might take a while...\n");
ret = ret = blisp_device_flash_erase(
blisp_device_flash_erase(&device, *single_download_location->ival, &device, *single_download_location->ival,
*single_download_location->ival + data_file_size + 1); *single_download_location->ival + data_file_size - 1);
if (ret != BLISP_OK) { if (ret != BLISP_OK) {
fprintf(stderr, "Failed to erase.\n"); fprintf(stderr, "Failed to erase, ret: %d\n", ret);
goto exit2; goto exit2;
} }
@@ -51,90 +86,103 @@ void blisp_single_download()
struct blisp_easy_transport data_transport = struct blisp_easy_transport data_transport =
blisp_easy_transport_new_from_file(data_file); blisp_easy_transport_new_from_file(data_file);
ret = blisp_easy_flash_write(&device, &data_transport, *single_download_location->ival, ret = blisp_easy_flash_write(&device, &data_transport,
data_file_size, *single_download_location->ival, data_file_size,
blisp_common_progress_callback); blisp_common_progress_callback);
if (ret < BLISP_OK) { if (ret != BLISP_OK) {
fprintf(stderr, "Failed to write data to flash.\n"); fprintf(stderr, "Failed to write data to flash, ret: %d\n", ret);
goto exit2; goto exit2;
} }
printf("Checking program...\n"); printf("Checking program...\n");
ret = blisp_device_program_check(&device); ret = blisp_device_program_check(&device);
if (ret != BLISP_OK) { if (ret != BLISP_OK) {
fprintf(stderr, "Failed to check program.\n"); fprintf(stderr, "Failed to check program, ret: %d\n", ret);
goto exit2; goto exit2;
} }
printf("Program OK!\n"); printf("Program OK!\n");
if (reset->count > 0) { // TODO: could be common if (reset->count > 0) { // TODO: could be common
blisp_device_reset(&device);
printf("Resetting the chip.\n"); printf("Resetting the chip.\n");
ret = blisp_device_reset(&device);
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to reset chip, ret: %d\n", ret);
goto exit2;
}
}
if (ret == BLISP_OK) {
printf("Download complete!\n");
} }
printf("Download complete!\n");
exit2: exit2:
if (data_file != NULL) if (data_file != NULL)
fclose(data_file); fclose(data_file);
exit1: exit1:
blisp_device_close(&device); blisp_device_close(&device);
return ret;
} }
int8_t cmd_iot_args_init() { blisp_return_t cmd_iot_args_init(void) {
cmd_iot_argtable[0] = cmd = size_t index = 0;
cmd_iot_argtable[index++] = cmd =
arg_rex1(NULL, NULL, "iot", NULL, REG_ICASE, NULL); arg_rex1(NULL, NULL, "iot", NULL, REG_ICASE, NULL);
cmd_iot_argtable[1] = chip_type = cmd_iot_argtable[index++] = chip_type =
arg_str1("c", "chip", "<chip_type>", "Chip Type"); arg_str1("c", "chip", "<chip_type>", "Chip Type");
cmd_iot_argtable[2] = port_name = cmd_iot_argtable[index++] = port_name =
arg_str0("p", "port", "<port_name>", arg_str0("p", "port", "<port_name>",
"Name/Path to the Serial Port (empty for search)"); "Name/Path to the Serial Port (empty for search)");
cmd_iot_argtable[3] = reset = cmd_iot_argtable[index++] = baudrate =
arg_int0("b", "baudrate", "<baud rate>",
"Serial baud rate (default: " XSTR(DEFAULT_BAUDRATE) ")");
cmd_iot_argtable[index++] = reset =
arg_lit0(NULL, "reset", "Reset chip after write"); arg_lit0(NULL, "reset", "Reset chip after write");
cmd_iot_argtable[4] = single_download = cmd_iot_argtable[index++] = chiperase =
arg_lit0(NULL, "chiperase", "Do not write any data; erase the entire chip instead");
cmd_iot_argtable[index++] = single_download =
arg_file0("s", "single-down", "<file>", "Single download file"); arg_file0("s", "single-down", "<file>", "Single download file");
cmd_iot_argtable[5] = single_download_location = cmd_iot_argtable[index++] = single_download_location =
arg_int0("l", "single-down-loc", NULL, "Single download offset"); arg_int0("l", "single-down-loc", NULL, "Single download offset");
cmd_iot_argtable[6] = end = arg_end(10); cmd_iot_argtable[index++] = end = arg_end(10);
if (arg_nullcheck(cmd_iot_argtable) != 0) { if (arg_nullcheck(cmd_iot_argtable) != 0) {
fprintf(stderr, "insufficient memory\n"); fprintf(stderr, "insufficient memory\n");
return -1; return BLISP_ERR_OUT_OF_MEMORY;
} }
return 0; return BLISP_OK;
} }
void cmd_iot_args_print_glossary() { void cmd_iot_args_print_glossary(void) {
fputs("Usage: blisp", stdout); fputs("Usage: blisp", stdout);
arg_print_syntax(stdout, cmd_iot_argtable, "\n"); arg_print_syntax(stdout, cmd_iot_argtable, "\n");
puts("Flashes firmware as Bouffalo's DevCube"); puts("Flashes firmware as Bouffalo's DevCube");
arg_print_glossary(stdout, cmd_iot_argtable, " %-25s %s\n"); arg_print_glossary(stdout, cmd_iot_argtable, " %-25s %s\n");
} }
uint8_t cmd_iot_parse_exec(int argc, char** argv) { blisp_return_t cmd_iot_parse_exec(int argc, char** argv) {
int errors = arg_parse(argc, argv, cmd_iot_argtable); int errors = arg_parse(argc, argv, cmd_iot_argtable);
if (errors == 0) { if (errors == 0) {
if (single_download->count == 1 && single_download_location->count == 1) { if (chiperase->count || (single_download->count == 1 && single_download_location->count == 1)) {
blisp_single_download(); return blisp_single_download();
return 1;
} else { } else {
return 0; return BLISP_ERR_INVALID_COMMAND;
} }
} else if (cmd->count == 1) { } else if (cmd->count == 1) {
cmd_iot_args_print_glossary(); cmd_iot_args_print_glossary();
return 1; return BLISP_OK;
} }
return 0; return BLISP_ERR_INVALID_COMMAND;
} }
void cmd_iot_args_print_syntax() { void cmd_iot_args_print_syntax(void) {
arg_print_syntax(stdout, cmd_iot_argtable, "\n"); arg_print_syntax(stdout, cmd_iot_argtable, "\n");
} }
void cmd_iot_free() { void cmd_iot_free(void) {
arg_freetable(cmd_iot_argtable, arg_freetable(cmd_iot_argtable,
sizeof(cmd_iot_argtable) / sizeof(cmd_iot_argtable[0])); sizeof(cmd_iot_argtable) / sizeof(cmd_iot_argtable[0]));
} }
struct cmd cmd_iot = {"iot", cmd_iot_args_init, cmd_iot_parse_exec, struct cmd cmd_iot = {"iot", cmd_iot_args_init, cmd_iot_parse_exec,
cmd_iot_args_print_syntax, cmd_iot_free}; cmd_iot_args_print_syntax, cmd_iot_free};
+112 -61
View File
@@ -1,14 +1,15 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include <argtable3.h>
#include <blisp.h> #include <blisp.h>
#include <blisp_easy.h>
#include <blisp_struct.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "../cmd.h" #include "../cmd.h"
#include "../common.h" #include "../common.h"
#include "../util.h" #include "../util.h"
#include <argtable3.h> #include "parse_file.h"
#include <blisp_easy.h>
#include <blisp_struct.h>
#define REG_EXTENDED 1 #define REG_EXTENDED 1
#define REG_ICASE (REG_EXTENDED << 1) #define REG_ICASE (REG_EXTENDED << 1)
@@ -16,9 +17,11 @@
static struct arg_rex* cmd; static struct arg_rex* cmd;
static struct arg_file* binary_to_write; static struct arg_file* binary_to_write;
static struct arg_str *port_name, *chip_type; static struct arg_str *port_name, *chip_type;
static struct arg_int *baudrate;
static struct arg_lit* reset; static struct arg_lit* reset;
static struct arg_end* end; static struct arg_end* end;
static void* cmd_write_argtable[6]; static void* cmd_write_argtable[7];
static void cmd_write_args_print_glossary();
void fill_up_boot_header(struct bfl_boot_header* boot_header) { void fill_up_boot_header(struct bfl_boot_header* boot_header) {
memcpy(boot_header->magiccode, "BFNP", 4); memcpy(boot_header->magiccode, "BFNP", 4);
@@ -164,63 +167,104 @@ void fill_up_boot_header(struct bfl_boot_header* boot_header) {
boot_header->crc32 = 0xDEADBEEF; boot_header->crc32 = 0xDEADBEEF;
} }
void blisp_flash_firmware() { blisp_return_t blisp_flash_firmware(void) {
struct blisp_device device; struct blisp_device device;
int32_t ret; blisp_return_t ret = BLISP_OK;
if (blisp_common_init_device(&device, port_name, chip_type) != 0) { uint32_t baud = DEFAULT_BAUDRATE;
return; if (baudrate->count == 1) {
if (*baudrate->ival < 0) {
fprintf(stderr, "Baud rate cannot be negative!\n");
return BLISP_ERR_INVALID_COMMAND;
} else {
baud = *baudrate->ival;
}
} }
if (blisp_common_prepare_flash(&device) != 0) { if (access(binary_to_write->filename[0], R_OK) != 0) {
// File not accessible, error out.
fprintf(stderr, "Input firmware not found: %s\n", binary_to_write->filename[0]);
cmd_write_args_print_glossary(); /* Print help to assist user */
/* No need to free memory, will now exit with ret code 1 */
return BLISP_ERR_CANT_OPEN_FILE;
}
ret = blisp_common_init_device(&device, port_name, chip_type, baud);
if (ret != BLISP_OK) {
return ret;
}
ret = blisp_common_prepare_flash(&device);
if (ret != BLISP_OK) {
// TODO: Error handling // TODO: Error handling
goto exit1; goto exit1;
} }
FILE* firmware_file = fopen(binary_to_write->filename[0], "rb"); parsed_firmware_file_t parsed_file;
if (firmware_file == NULL) { memset(&parsed_file, 0, sizeof(parsed_file));
fprintf(stderr, "Failed to open firmware file \"%s\".\n", if (parse_firmware_file(binary_to_write->filename[0], &parsed_file) < 0) {
binary_to_write->filename[0]); // `parse_firmware_file` doesn't return `blisp_return_t`
// so we default to the generic error.
ret = BLISP_ERR_UNKNOWN;
goto exit1; goto exit1;
} }
fseek(firmware_file, 0, SEEK_END);
int64_t firmware_file_size = ftell(firmware_file);
rewind(firmware_file);
struct bfl_boot_header boot_header; // If we are injecting a bootloader section, make it, erase flash, and flash
fill_up_boot_header(&boot_header); // it. Then when we do firmware later on; it will be located afterwards
// the header filles up to a flash erase boundry so this stack should be safe
// __should__
const uint32_t firmware_base_address = 0x2000; if (parsed_file.needs_boot_struct) {
printf("Erasing flash, this might take a while...\n"); // Create a default boot header section in ram to be written out
ret = struct bfl_boot_header boot_header;
blisp_device_flash_erase(&device, firmware_base_address, fill_up_boot_header(&boot_header);
firmware_base_address + firmware_file_size + 1); printf("Erasing flash to flash boot header\n");
if (ret != BLISP_OK) { ret = blisp_device_flash_erase(&device, 0x0000,
fprintf(stderr, "Failed to erase flash.\n"); sizeof(struct bfl_boot_header));
goto exit2;
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to erase flash.\n");
goto exit2;
}
// Now burn the header
printf("Flashing boot header...\n");
ret = blisp_device_flash_write(&device, 0x0000, (uint8_t*)&boot_header,
sizeof(struct bfl_boot_header));
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to write boot header.\n");
goto exit2;
}
// Move the firmware to-be-flashed beyond the boot header area
parsed_file.payload_address += 0x2000;
} }
ret = // Now that optional boot header is done, we clear out the flash for the new
blisp_device_flash_erase(&device, 0x0000, sizeof(struct bfl_boot_header)); // firmware; and flash it in.
printf("Erasing flash for firmware, this might take a while...\n");
ret = blisp_device_flash_erase(
&device, parsed_file.payload_address,
parsed_file.payload_address + parsed_file.payload_length);
if (ret != BLISP_OK) { if (ret != BLISP_OK) {
fprintf(stderr, "Failed to erase flash.\n"); fprintf(stderr,
"Failed to erase flash. Tried to erase from 0x%08zx to 0x%08zx\n",
parsed_file.payload_address,
parsed_file.payload_address + parsed_file.payload_length + 1);
goto exit2; goto exit2;
} }
printf("Flashing boot header...\n"); printf("Flashing the firmware %zu bytes @ 0x%08zx...\n",
ret = blisp_device_flash_write(&device, 0x0000, (uint8_t*)&boot_header, parsed_file.payload_length, parsed_file.payload_address);
sizeof(struct bfl_boot_header));
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to write boot header.\n");
goto exit2;
}
printf("Flashing the firmware...\n");
struct blisp_easy_transport data_transport = struct blisp_easy_transport data_transport =
blisp_easy_transport_new_from_file(firmware_file); blisp_easy_transport_new_from_memory(parsed_file.payload,
parsed_file.payload_length);
ret = blisp_easy_flash_write(&device, &data_transport, firmware_base_address, ret = blisp_easy_flash_write(
firmware_file_size, &device, &data_transport, parsed_file.payload_address,
blisp_common_progress_callback); parsed_file.payload_length, blisp_common_progress_callback);
if (ret < BLISP_OK) {
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to write app to flash.\n"); fprintf(stderr, "Failed to write app to flash.\n");
goto exit2; goto exit2;
} }
@@ -242,57 +286,64 @@ void blisp_flash_firmware() {
printf("Flash complete!\n"); printf("Flash complete!\n");
exit2: exit2:
if (firmware_file != NULL) if (parsed_file.payload != NULL)
fclose(firmware_file); free(parsed_file.payload);
exit1: exit1:
blisp_device_close(&device); blisp_device_close(&device);
return ret;
} }
int8_t cmd_write_args_init() { blisp_return_t cmd_write_args_init(void) {
cmd_write_argtable[0] = cmd = size_t index = 0;
cmd_write_argtable[index++] = cmd =
arg_rex1(NULL, NULL, "write", NULL, REG_ICASE, NULL); arg_rex1(NULL, NULL, "write", NULL, REG_ICASE, NULL);
cmd_write_argtable[1] = chip_type = cmd_write_argtable[index++] = chip_type =
arg_str1("c", "chip", "<chip_type>", "Chip Type"); arg_str1("c", "chip", "<chip_type>", "Chip Type");
cmd_write_argtable[2] = port_name = cmd_write_argtable[index++] = port_name =
arg_str0("p", "port", "<port_name>", arg_str0("p", "port", "<port_name>",
"Name/Path to the Serial Port (empty for search)"); "Name/Path to the Serial Port (empty for search)");
cmd_write_argtable[3] = reset = cmd_write_argtable[index++] = baudrate =
arg_int0("b", "baudrate", "<baud rate>",
"Serial baud rate (default: " XSTR(DEFAULT_BAUDRATE) ")");
cmd_write_argtable[index++] = reset =
arg_lit0(NULL, "reset", "Reset chip after write"); arg_lit0(NULL, "reset", "Reset chip after write");
cmd_write_argtable[4] = binary_to_write = cmd_write_argtable[index++] = binary_to_write =
arg_file1(NULL, NULL, "<input>", "Binary to write"); arg_file1(NULL, NULL, "<input>", "Binary to write");
cmd_write_argtable[5] = end = arg_end(10); cmd_write_argtable[index++] = end = arg_end(10);
if (arg_nullcheck(cmd_write_argtable) != 0) { if (arg_nullcheck(cmd_write_argtable) != 0) {
fprintf(stderr, "insufficient memory\n"); fprintf(stderr, "insufficient memory\n");
return -1; return BLISP_ERR_OUT_OF_MEMORY;
} }
return 0; return BLISP_OK;
} }
void cmd_write_args_print_glossary() { void cmd_write_args_print_glossary(void) {
fputs("Usage: blisp", stdout); fputs("Usage: blisp", stdout);
arg_print_syntax(stdout, cmd_write_argtable, "\n"); arg_print_syntax(stdout, cmd_write_argtable, "\n");
puts("Writes firmware to SPI Flash"); puts("Writes firmware to SPI Flash");
arg_print_glossary(stdout, cmd_write_argtable, " %-25s %s\n"); arg_print_glossary(stdout, cmd_write_argtable, " %-25s %s\n");
} }
uint8_t cmd_write_parse_exec(int argc, char** argv) { blisp_return_t cmd_write_parse_exec(int argc, char** argv) {
int errors = arg_parse(argc, argv, cmd_write_argtable); int errors = arg_parse(argc, argv, cmd_write_argtable);
if (errors == 0) { if (errors == 0) {
blisp_flash_firmware(); // TODO: Error code? return blisp_flash_firmware(); // TODO: Error code?
return 1;
} else if (cmd->count == 1) { } else if (cmd->count == 1) {
cmd_write_args_print_glossary(); cmd_write_args_print_glossary();
return 1; return BLISP_OK;
} }
return 0; return BLISP_ERR_INVALID_COMMAND;
} }
void cmd_write_args_print_syntax() { void cmd_write_args_print_syntax(void) {
arg_print_syntax(stdout, cmd_write_argtable, "\n"); arg_print_syntax(stdout, cmd_write_argtable, "\n");
} }
void cmd_write_free() { void cmd_write_free(void) {
arg_freetable(cmd_write_argtable, arg_freetable(cmd_write_argtable,
sizeof(cmd_write_argtable) / sizeof(cmd_write_argtable[0])); sizeof(cmd_write_argtable) / sizeof(cmd_write_argtable[0]));
} }
+110 -48
View File
@@ -3,23 +3,28 @@
#include <argtable3.h> #include <argtable3.h>
#include <blisp.h> #include <blisp.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "blisp_easy.h" #include "blisp_easy.h"
#include "blisp_util.h"
#include "error_codes.h"
#include "util.h" #include "util.h"
void blisp_common_progress_callback(uint32_t current_value, uint32_t max_value) { void blisp_common_progress_callback(uint32_t current_value,
printf("%" PRIu32 "b / %ldb (%.2f%%)\n", current_value, max_value, uint32_t max_value) {
printf("%" PRIu32 "b / %u (%.2f%%)\n", current_value, max_value,
(((float)current_value / (float)max_value) * 100.0f)); (((float)current_value / (float)max_value) * 100.0f));
} }
int32_t blisp_common_init_device(struct blisp_device* device, struct arg_str* port_name, struct arg_str* chip_type) blisp_return_t blisp_common_init_device(struct blisp_device* device,
{ struct arg_str* port_name,
struct arg_str* chip_type,
uint32_t baudrate) {
if (chip_type->count == 0) { if (chip_type->count == 0) {
fprintf(stderr, "Chip type is invalid.\n"); fprintf(stderr, "Chip type is invalid.\n");
return -1; return BLISP_ERR_INVALID_CHIP_TYPE;
} }
struct blisp_chip* chip = NULL; struct blisp_chip* chip = NULL;
@@ -28,59 +33,115 @@ int32_t blisp_common_init_device(struct blisp_device* device, struct arg_str* po
chip = &blisp_chip_bl70x; chip = &blisp_chip_bl70x;
} else if (strcmp(chip_type->sval[0], "bl60x") == 0) { } else if (strcmp(chip_type->sval[0], "bl60x") == 0) {
chip = &blisp_chip_bl60x; chip = &blisp_chip_bl60x;
} else if (strcmp(chip_type->sval[0], "bl808") == 0) {
chip = &blisp_chip_bl808;
} else { } else {
fprintf(stderr, "Chip type is invalid.\n"); fprintf(stderr, "Chip type is invalid.\n");
return -1; return BLISP_ERR_INVALID_CHIP_TYPE;
} }
int32_t ret; blisp_return_t ret;
ret = blisp_device_init(device, chip); ret = blisp_device_init(device, chip);
if (ret != BLISP_OK) { if (ret != BLISP_OK) {
fprintf(stderr, "Failed to init device.\n"); fprintf(stderr, "Failed to init device, ret: %d\n", ret);
return -1; return ret;
} }
ret = blisp_device_open(device, ret = blisp_device_open(device,
port_name->count == 1 ? port_name->sval[0] : NULL); port_name->count == 1 ? port_name->sval[0] : NULL,
baudrate);
if (ret != BLISP_OK) { if (ret != BLISP_OK) {
fprintf(stderr, ret == BLISP_ERR_DEVICE_NOT_FOUND ? "Device not found\n" : "Failed to open device.\n"); if (ret == BLISP_ERR_DEVICE_NOT_FOUND) {
return -1; fprintf(stderr, "Device not found\n");
} else {
fprintf(stderr, "Failed to open device, ret: %d\n", ret);
}
return ret;
} }
return 0; return BLISP_OK;
} }
/** /**
* Prepares chip to access flash * Prepares chip to access flash
* this means performing handshake, and loading eflash_loader if needed. * this means performing handshake, and loading eflash_loader if needed.
*/ */
int32_t blisp_common_prepare_flash(struct blisp_device* device) { blisp_return_t blisp_common_prepare_flash(struct blisp_device* device) {
int32_t ret = 0; blisp_return_t ret = 0;
uint32_t previous_timeout;
printf("Sending a handshake...\n");
ret = blisp_device_handshake(device, false);
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to handshake with device.\n");
return -1;
}
printf("Handshake successful!\nGetting chip info...\n");
struct blisp_boot_info boot_info; struct blisp_boot_info boot_info;
// We may already be in communication with the chip from a previous
// invocation of this command. In that case, it will not respond to our
// handshake. We detect this by trying to send a command to it, using a
// (relatively) short timeout.
//
// NOTE: This appears to be how BouffaloLab software does it as well.
//
// NOTE: Modifying the timeout is mandatory for BL808;
// see blisp.c:blisp_device_init()
previous_timeout = device->serial_timeout;
device->serial_timeout = 500;
printf("Testing if we can skip the handshake...\n");
ret = blisp_device_get_boot_info(device, &boot_info); ret = blisp_device_get_boot_info(device, &boot_info);
if (ret != BLISP_OK) { device->serial_timeout = previous_timeout;
fprintf(stderr, "Failed to get boot info.\n");
return -1; if (ret == BLISP_OK) {
printf("Skipping handshake!\n");
} else {
printf("We can't; ignore the previous error.\n");
printf("Sending a handshake...\n");
ret = blisp_device_handshake(device, false);
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to handshake with device, ret: %d\n", ret);
return ret;
}
printf("Handshake successful!\nGetting chip info...\n");
ret = blisp_device_get_boot_info(device, &boot_info);
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to get boot info, ret: %d\n", ret);
return ret;
}
} }
printf( // TODO: Do we want this to print in big endian to match the output
"BootROM version %d.%d.%d.%d, ChipID: " // of Bouffalo's software?
"%02X%02X%02X%02X%02X%02X%02X%02X\n", if (device->chip->type == BLISP_CHIP_BL70X) {
boot_info.boot_rom_version[0], boot_info.boot_rom_version[1], printf(
boot_info.boot_rom_version[2], boot_info.boot_rom_version[3], "BootROM version %d.%d.%d.%d, ChipID: "
boot_info.chip_id[0], boot_info.chip_id[1], boot_info.chip_id[2], "%02X%02X%02X%02X%02X%02X%02X%02X\n",
boot_info.chip_id[3], boot_info.chip_id[4], boot_info.chip_id[5], boot_info.boot_rom_version[0], boot_info.boot_rom_version[1],
boot_info.chip_id[6], boot_info.chip_id[7]); boot_info.boot_rom_version[2], boot_info.boot_rom_version[3],
boot_info.chip_id[0], boot_info.chip_id[1], boot_info.chip_id[2],
boot_info.chip_id[3], boot_info.chip_id[4], boot_info.chip_id[5],
boot_info.chip_id[6], boot_info.chip_id[7]);
} else {
printf(
"BootROM version %d.%d.%d.%d, ChipID: "
"%02X%02X%02X%02X%02X%02X\n",
boot_info.boot_rom_version[0], boot_info.boot_rom_version[1],
boot_info.boot_rom_version[2], boot_info.boot_rom_version[3],
boot_info.chip_id[0], boot_info.chip_id[1], boot_info.chip_id[2],
boot_info.chip_id[3], boot_info.chip_id[4], boot_info.chip_id[5]);
}
if (device->chip->type == BLISP_CHIP_BL808) {
printf("Setting clock parameters ...\n");
ret = bl808_load_clock_para(device, true, device->current_baud_rate);
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to set clock parameters, ret: %d\n", ret);
return ret;
}
printf("Setting flash parameters ...\n");
ret = bl808_load_flash_para(device);
if (ret != BLISP_OK) {
fprintf(stderr, "Failed to set flash parameters, ret: %d\n", ret);
return ret;
}
}
if (device->chip->load_eflash_loader == NULL) { if (device->chip->load_eflash_loader == NULL) {
return 0; return BLISP_OK;
} }
if (boot_info.boot_rom_version[0] == 255 && if (boot_info.boot_rom_version[0] == 255 &&
@@ -88,21 +149,24 @@ int32_t blisp_common_prepare_flash(struct blisp_device* device) {
boot_info.boot_rom_version[2] == 255 && boot_info.boot_rom_version[2] == 255 &&
boot_info.boot_rom_version[3] == 255) { boot_info.boot_rom_version[3] == 255) {
printf("Device already in eflash_loader.\n"); printf("Device already in eflash_loader.\n");
return 0; return BLISP_OK;
} }
uint8_t* eflash_loader_buffer = NULL; uint8_t* eflash_loader_buffer = NULL;
// TODO: Error check // TODO: Error check
int64_t eflash_loader_buffer_length = device->chip->load_eflash_loader(0, &eflash_loader_buffer); int64_t eflash_loader_buffer_length =
device->chip->load_eflash_loader(0, &eflash_loader_buffer);
struct blisp_easy_transport eflash_loader_transport = struct blisp_easy_transport eflash_loader_transport =
blisp_easy_transport_new_from_memory(eflash_loader_buffer, eflash_loader_buffer_length); blisp_easy_transport_new_from_memory(eflash_loader_buffer,
eflash_loader_buffer_length);
ret = blisp_easy_load_ram_app(device, &eflash_loader_transport, blisp_common_progress_callback); ret = blisp_easy_load_ram_app(device, &eflash_loader_transport,
blisp_common_progress_callback);
if (ret != BLISP_OK) { if (ret != BLISP_OK) {
fprintf(stderr, "Failed to load eflash_loader, ret: %d\n", ret); fprintf(stderr, "Failed to load eflash_loader, ret: %d\n", ret);
ret = -1;
goto exit1; goto exit1;
} }
@@ -111,28 +175,26 @@ int32_t blisp_common_prepare_flash(struct blisp_device* device) {
ret = blisp_device_check_image(device); ret = blisp_device_check_image(device);
if (ret != 0) { if (ret != 0) {
fprintf(stderr, "Failed to check image.\n"); fprintf(stderr, "Failed to check image, ret: %d\n", ret);
ret = -1;
goto exit1; goto exit1;
} }
ret = blisp_device_run_image(device); ret = blisp_device_run_image(device);
if (ret != BLISP_OK) { if (ret != BLISP_OK) {
fprintf(stderr, "Failed to run image.\n"); fprintf(stderr, "Failed to run image, ret: %d\n", ret);
ret = -1;
goto exit1; goto exit1;
} }
printf("Sending a handshake...\n"); printf("Sending a handshake...\n");
ret = blisp_device_handshake(device, true); ret = blisp_device_handshake(device, true);
if (ret != BLISP_OK) { if (ret != BLISP_OK) {
fprintf(stderr, "Failed to handshake with device.\n"); fprintf(stderr, "Failed to handshake with device, ret: %d\n", ret);
ret = -1;
goto exit1; goto exit1;
} }
printf("Handshake with eflash_loader successful.\n"); printf("Handshake with eflash_loader successful.\n");
exit1: exit1:
if (eflash_loader_buffer != NULL) if (eflash_loader_buffer != NULL)
free(eflash_loader_buffer); free(eflash_loader_buffer);
return ret; return ret;
} }
+7 -2
View File
@@ -6,8 +6,13 @@
#include <blisp.h> #include <blisp.h>
#include <argtable3.h> #include <argtable3.h>
int32_t blisp_common_prepare_flash(struct blisp_device* device); // https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html
#define DEFAULT_BAUDRATE 460800
#define STR(x) #x
#define XSTR(x) STR(x)
blisp_return_t blisp_common_prepare_flash(struct blisp_device* device);
void blisp_common_progress_callback(uint32_t current_value, uint32_t max_value); void blisp_common_progress_callback(uint32_t current_value, uint32_t max_value);
int32_t blisp_common_init_device(struct blisp_device* device, struct arg_str* port_name, struct arg_str* chip_type); blisp_return_t blisp_common_init_device(struct blisp_device* device, struct arg_str* port_name, struct arg_str* chip_type, uint32_t baudrate);
#endif // BLISP_COMMON_H #endif // BLISP_COMMON_H
@@ -0,0 +1,27 @@
list(APPEND ADD_INCLUDE
"${CMAKE_CURRENT_SOURCE_DIR}/bin"
"${CMAKE_CURRENT_SOURCE_DIR}/dfu"
"${CMAKE_CURRENT_SOURCE_DIR}/hex"
"${CMAKE_CURRENT_SOURCE_DIR}"
)
file(GLOB_RECURSE sources
)
list(APPEND ADD_SRCS ${sources})
add_library(file_parsers STATIC
"${CMAKE_CURRENT_SOURCE_DIR}/bin/bin_file.c"
"${CMAKE_CURRENT_SOURCE_DIR}/dfu/dfu_file.c"
"${CMAKE_CURRENT_SOURCE_DIR}/dfu/dfu_crc.c"
"${CMAKE_CURRENT_SOURCE_DIR}/hex/hex_file.c"
"${CMAKE_CURRENT_SOURCE_DIR}/parse_file.c"
"${CMAKE_CURRENT_SOURCE_DIR}/get_file_contents.c"
)
target_include_directories(file_parsers PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/bin
${CMAKE_CURRENT_SOURCE_DIR}/dfu
${CMAKE_CURRENT_SOURCE_DIR}/hex
${CMAKE_CURRENT_SOURCE_DIR}
)
@@ -0,0 +1,15 @@
#include <stdio.h>
#include "parse_file.h"
int bin_file_parse(const char* file_path_on_disk,
uint8_t** payload,
size_t* payload_length,
size_t* payload_address) {
// Bin files a dumb so we cant do any fancy logic
*payload_address = 0; // We cant know otherwise
ssize_t len = get_file_contents(file_path_on_disk, payload);
if (len > 0) {
*payload_length = len;
}
return len;
}
@@ -0,0 +1,24 @@
//
// Created by ralim on 01/08/23.
//
#ifndef BLISP_BIN_FILE_H
#define BLISP_BIN_FILE_H
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
int bin_file_parse(const char* file_path_on_disk,
uint8_t** payload,
size_t* payload_length,
size_t* payload_address);
#ifdef __cplusplus
};
#endif
#endif // BLISP_BIN_FILE_H
@@ -0,0 +1,53 @@
//
// Created by ralim on 26/09/22.
//
#include "dfu_file.h"
static const unsigned long crc32_table[]
= { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d };
uint32_t
crc32_byte(uint32_t accum, uint8_t delta) {
return crc32_table[(accum ^ delta) & 0xff] ^ (accum >> 8);
}
+294
View File
@@ -0,0 +1,294 @@
//
// Created by ralim on 25/09/22.
//
#include "dfu_file.h"
#include <stdlib.h>
#include "parse_file.h"
#if defined(_MSC_VER)
#include <sys\types.h>
#endif
#define DFU_SUFFIX_LENGTH 16
#define LMDFU_PREFIX_LENGTH 8
#define LPCDFU_PREFIX_LENGTH 16
struct dfu_file {
/* File name */
const char* name;
/* Pointer to file loaded into memory */
const uint8_t* firmware;
/* Different sizes */
struct {
off_t total;
off_t firmware;
int prefix;
int suffix;
} size;
/* From prefix fields */
uint32_t lmdfu_address;
/* From prefix fields */
uint32_t prefix_type;
/* From DFU suffix fields */
uint32_t dwCRC;
uint16_t bcdDFU;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
};
enum prefix_type {
ZERO_PREFIX,
DFUSE_PREFIX,
LMDFU_PREFIX,
LPCDFU_UNENCRYPTED_PREFIX
};
struct dfu_file parse_dfu_suffix(const uint8_t* file_contents,
size_t file_contents_length);
ssize_t parse_target(const uint8_t* data,
uint8_t* out_ealt,
uint8_t** out_data,
size_t* out_data_size,
size_t* out_data_address);
ssize_t get_file_contents(const char* file_path_on_disk,
uint8_t** file_contents);
/* Parse a .dfu file and extract its payload and metadata
* Returns 0 if file parsed correctly, negative on error
* Inputs:
* - File path to read from
*
* Outputs:
* - File payload contents
* - File payload start address
*
* Usage:
* uint8_t* payload=NULL;
* size_t payload_length=0;
* int res = dfu_file_path("test.dfu",&payload,&payload_length);
* ...
* free(payload);
*/
int dfu_file_parse(const char* file_path_on_disk,
uint8_t** payload,
size_t* payload_length,
size_t* payload_address) {
uint8_t* dfu_file_contents = NULL;
ssize_t file_size = get_file_contents(file_path_on_disk, &dfu_file_contents);
// Bubble up the result if it was an error instead of size (a negative value)
if (file_size < 0) {
return file_size;
}
if (file_size == 0 || dfu_file_contents == NULL) {
return PARSED_ERROR_CANT_OPEN_FILE;
}
// Parse DFU data
struct dfu_file dfu_info = parse_dfu_suffix(dfu_file_contents, file_size);
if (dfu_info.size.firmware == 0) {
return PARSED_ERROR_BAD_DFU;
}
// Check if its for a BL* chip
// if (dfu_info.idVendor != 0x28E9) {
// free(dfu_file_contents);
// return -1;
// }
// Okay we have done validation, walk firmware and extract the blob and the
// offset
size_t data_consumed = 0;
while (data_consumed < dfu_info.size.firmware) {
uint8_t ealt = 0;
uint8_t* blob = NULL;
size_t blob_size = 0;
size_t blob_address = 0;
ssize_t res = parse_target(dfu_info.firmware + data_consumed, &ealt, &blob,
&blob_size, &blob_address);
if (res < 0) {
break;
}
if (ealt == 0 && blob_size > 0) {
// Firmware slot, lets prep this and return
*payload = calloc(blob_size, 1);
*payload_length = blob_size;
*payload_address = blob_address;
memcpy(*payload, blob, blob_size);
free(dfu_file_contents);
return 1;
}
data_consumed += res;
}
return 0;
}
// Read next target, output data+size+alt. Returns bytes consumed
ssize_t parse_target(const uint8_t* data,
uint8_t* out_ealt,
uint8_t** out_data,
size_t* out_data_size,
size_t* out_data_address) {
if (data == NULL || out_ealt == NULL || out_data == NULL ||
out_data_size == NULL) {
return -99;
}
if (data[0] != 'T' || data[1] != 'a') {
return -1;
}
*out_ealt = data[6];
uint8_t* tdata = (uint8_t*)data + 6 + 1 + 4 + 255;
uint32_t len_tdata = *((uint32_t*)tdata);
tdata += 4;
uint32_t num_images = *((uint32_t*)tdata);
tdata += 4;
ssize_t blob_length = 6 + 1 + 4 + 255 + 8 + len_tdata;
// Now read all the image blobs from this target
for (int i = 0; i < num_images; i++) {
uint32_t address = *((uint32_t*)tdata);
tdata += 4;
uint32_t len = *((uint32_t*)tdata);
tdata += 4;
*out_data = tdata;
*out_data_size = len;
*out_data_address = address;
return blob_length;
// tdata+=len;
}
return blob_length;
}
static int probe_prefix(struct dfu_file* file) {
const uint8_t* prefix = file->firmware;
file->size.prefix = 0;
if (file->size.total < LMDFU_PREFIX_LENGTH)
return 1;
if (prefix[0] == 'D' && prefix[1] == 'f' && prefix[2] == 'u' &&
prefix[3] == 'S' && prefix[4] == 'e') {
// DfuSe header
// https://sourceforge.net/p/dfu-util/dfu-util/ci/master/tree/dfuse-pack.py#l110
file->size.prefix = 11;
file->prefix_type = DFUSE_PREFIX;
uint8_t numTargets = prefix[10];
printf("Number DFU Targets: %d\n", numTargets);
}
if ((prefix[0] == 0x01) && (prefix[1] == 0x00)) {
uint32_t payload_length =
(prefix[7] << 24) | (prefix[6] << 16) | (prefix[5] << 8) | prefix[4];
uint32_t expected_payload_length =
(uint32_t)file->size.total - LMDFU_PREFIX_LENGTH - file->size.suffix;
if (payload_length != expected_payload_length)
return 1;
file->prefix_type = LMDFU_PREFIX;
file->size.prefix = LMDFU_PREFIX_LENGTH;
file->lmdfu_address = 1024 * ((prefix[3] << 8) | prefix[2]);
} else if (((prefix[0] & 0x3f) == 0x1a) && ((prefix[1] & 0x3f) == 0x3f)) {
file->prefix_type = LPCDFU_UNENCRYPTED_PREFIX;
file->size.prefix = LPCDFU_PREFIX_LENGTH;
}
if (file->size.prefix + file->size.suffix > file->size.total)
return 1;
return 0;
}
struct dfu_file parse_dfu_suffix(const uint8_t* file_contents,
const size_t file_contents_length) {
// This is nearly 1:1 based on
// https://sourceforge.net/p/dfu-util/dfu-util/ci/master/tree/src/dfu_file.c#l368
struct dfu_file output;
memset(&output, 0, sizeof(output));
output.firmware = file_contents;
output.size.total = (off_t)file_contents_length;
/* Check for possible DFU file suffix by trying to parse one */
uint32_t crc = 0xffffffff;
const uint8_t* dfu_suffix;
int missing_suffix = 0;
const char* reason;
if (file_contents_length < DFU_SUFFIX_LENGTH) {
reason = "File too short for DFU suffix";
missing_suffix = 1;
output.size.firmware = 0;
return output;
}
dfu_suffix = file_contents + file_contents_length - DFU_SUFFIX_LENGTH;
if (dfu_suffix[10] != 'D' || dfu_suffix[9] != 'F' || dfu_suffix[8] != 'U') {
reason = "Invalid DFU suffix signature";
missing_suffix = 1;
output.size.firmware = 0;
return output;
}
// Calculate contents CRC32
for (int i = 0; i < file_contents_length - 4; i++) {
crc = crc32_byte(crc, file_contents[i]);
}
output.dwCRC = (dfu_suffix[15] << 24) + (dfu_suffix[14] << 16) +
(dfu_suffix[13] << 8) + dfu_suffix[12];
if (output.dwCRC != crc) {
reason = "DFU suffix CRC does not match";
missing_suffix = 1;
output.size.firmware = 0;
return output;
}
/* At this point we believe we have a DFU suffix
so we require further checks to succeed */
output.bcdDFU = (dfu_suffix[7] << 8) + dfu_suffix[6];
output.size.suffix = dfu_suffix[11];
if (output.size.suffix < DFU_SUFFIX_LENGTH) {
fprintf(stderr, "Unsupported DFU suffix length %d", output.size.suffix);
output.size.firmware = 0;
return output;
}
if (output.size.suffix > file_contents_length) {
fprintf(stderr, "Invalid DFU suffix length %d", output.size.suffix);
output.size.firmware = 0;
return output;
}
output.idVendor = (dfu_suffix[5] << 8) + dfu_suffix[4];
output.idProduct = (dfu_suffix[3] << 8) + dfu_suffix[2];
output.bcdDevice = (dfu_suffix[1] << 8) + dfu_suffix[0];
const int res = probe_prefix(&output);
if (output.size.prefix) {
const uint8_t* data = file_contents;
if (output.prefix_type == DFUSE_PREFIX) {
} else if (output.prefix_type == LMDFU_PREFIX) {
printf(
"Possible TI Stellaris DFU prefix with "
"the following properties\n"
"Address: 0x%08x\n"
"Payload length: %d\n",
output.lmdfu_address,
data[4] | (data[5] << 8) | (data[6] << 16) | (data[7] << 24));
} else if (output.prefix_type == LPCDFU_UNENCRYPTED_PREFIX) {
printf(
"Possible unencrypted NXP LPC DFU prefix with "
"the following properties\n"
"Payload length: %d kiByte\n",
data[2] >> 1 | (data[3] << 7));
} else {
fprintf(stderr, "Unknown DFU prefix type");
}
output.firmware =
output.firmware + output.size.prefix; // shift past prefix
}
output.size.firmware =
output.size.total - (output.size.suffix + output.size.prefix);
return output;
}
@@ -0,0 +1,27 @@
//
// Created by ralim on 26/09/22.
//
#ifndef BLISP_DFU_FILE_H
#define BLISP_DFU_FILE_H
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
// Parse the dfu file and returns 0 if ok, or -ve on error parsing
int dfu_file_parse(const char* file_path_on_disk,
uint8_t** payload,
size_t* payload_length,
size_t* payload_address);
// Internal
uint32_t crc32_byte(uint32_t accum, uint8_t delta);
#ifdef __cplusplus
};
#endif
#endif // BLISP_DFU_FILE_H
@@ -0,0 +1,10 @@
add_executable(dfu_file_test test_dfu_file.cpp ../dfu_file.c ../dfu_crc.c ../../get_file_contents.c)
target_link_libraries(dfu_file_test
PRIVATE
GTest::GTest
)
include(GoogleTest)
include_directories(dfu_file_test PRIVATE ../ ../../)
target_compile_definitions(dfu_file_test PUBLIC "SOURCE_DIR=\"${CMAKE_SOURCE_DIR}\"")
gtest_discover_tests(dfu_file_test)
Binary file not shown.
@@ -0,0 +1,17 @@
//
// Created by ralim on 26/09/22.
//
#include <gtest/gtest.h>
#include "dfu_file.h"
TEST(DFU_FILE_PARSER, ParseTestFile) {
uint8_t* payload = nullptr;
size_t payload_size = 0;
size_t payload_address = 0;
int res = dfu_file_parse(SOURCE_DIR
"/tools/blisp/src/file_parsers/dfu/tests/test.dfu",
&payload, &payload_size, &payload_address);
ASSERT_EQ(res, 1);
ASSERT_EQ(payload_size, 1337);
ASSERT_EQ(payload_address, 0x11223344);
}
@@ -0,0 +1,48 @@
#include <stdio.h>
#include <stdlib.h>
#include "parse_file.h"
// Returns file size _or_ negative on error
ssize_t get_file_contents(const char* file_path_on_disk,
uint8_t** file_contents) {
size_t read_count;
size_t file_size = 0;
size_t read_total = 0;
FILE* f;
if (file_contents == NULL) {
return -99;
}
f = fopen(file_path_on_disk, "rb");
if (f <= 0) {
fprintf(stderr, "Could not open file %s for reading\n", file_path_on_disk);
return -1;
}
fseek(f, 0, SEEK_END);
file_size = ftell(f);
fseek(f, 0, SEEK_SET);
*file_contents = calloc(file_size, sizeof(uint8_t));
while (read_total < file_size) {
size_t to_read = file_size - read_total;
/* read() limit on Linux, slightly below MAX_INT on Windows */
if (to_read > 0x7ffff000)
to_read = 0x7ffff000;
read_count = fread((*file_contents) + read_total, 1, to_read, f);
if (read_count == 0)
break;
// If error and not end of file, break
if (read_count == -1 && !feof(f))
break;
read_total += read_count;
}
if (read_total != file_size) {
fprintf(stderr, "Could only read %lld of %lld bytes from %s",
(long long)read_total, (long long)file_size, file_path_on_disk);
return -1;
}
fclose(f);
return (ssize_t)file_size;
}
+261
View File
@@ -0,0 +1,261 @@
#include "hex_file.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "parse_file.h"
// Convert ASCII hex character to integer
static int hex_to_int(char c) {
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
return -1;
}
// Convert 2 ASCII hex characters to a byte
static int hex_byte_to_int(const char* str) {
int high = hex_to_int(str[0]);
int low = hex_to_int(str[1]);
if (high < 0 || low < 0)
return -1;
return (high << 4) | low;
}
// Parse a single Intel HEX line into the record type and data
// Returns: Record Type on success, negative error code on failure
static int parse_hex_line(const char* line,
uint8_t* data_buffer,
uint32_t* address,
uint32_t* base_address,
uint32_t* max_address,
uint32_t min_address) {
size_t len = strlen(line);
// Line must start with ':' and have at least 11 characters (:BBAAAATTCC)
if (line[0] != ':' || len < 11) {
return HEX_PARSE_ERROR_INVALID_FORMAT;
}
// Extract record fields
int byte_count = hex_byte_to_int(line + 1);
if (byte_count < 0)
return HEX_PARSE_ERROR_INVALID_FORMAT;
// Make sure line is long enough
if (len < (size_t)(11 + byte_count * 2)) {
return HEX_PARSE_ERROR_INVALID_FORMAT;
}
int addr_high = hex_byte_to_int(line + 3);
int addr_low = hex_byte_to_int(line + 5);
if (addr_high < 0 || addr_low < 0)
return HEX_PARSE_ERROR_INVALID_FORMAT;
uint16_t record_address = (addr_high << 8) | addr_low;
int record_type = hex_byte_to_int(line + 7);
if (record_type < 0)
return HEX_PARSE_ERROR_INVALID_FORMAT;
// Verify checksum
uint8_t checksum = 0;
for (int i = 1; i < 9 + byte_count * 2; i += 2) {
int value = hex_byte_to_int(line + i);
if (value < 0) {
return HEX_PARSE_ERROR_INVALID_FORMAT;
}
checksum += value;
}
int file_checksum = hex_byte_to_int(line + 9 + byte_count * 2);
if (file_checksum < 0) {
return HEX_PARSE_ERROR_INVALID_FORMAT;
}
checksum = ~checksum + 1; // Two's complement
// Verify checksum
if (checksum != file_checksum) {
return HEX_PARSE_ERROR_CHECKSUM;
}
// Process the record based on record type
switch (record_type) {
case HEX_RECORD_DATA: {
uint32_t absolute_address = *base_address + record_address;
*address = absolute_address;
// Update max address if this data extends beyond current max
if (absolute_address + byte_count > *max_address) {
*max_address = absolute_address + byte_count;
}
// Parse data bytes
for (int i = 0; i < byte_count; i++) {
int value = hex_byte_to_int(line + 9 + i * 2);
if (value < 0)
return HEX_PARSE_ERROR_INVALID_FORMAT;
// Make sure we don't write outside our buffer
if (data_buffer != NULL) {
size_t buf_offset = absolute_address - min_address + i;
data_buffer[buf_offset] = value;
}
}
break;
}
case HEX_RECORD_EOF:
// End of file, nothing to do
break;
case HEX_RECORD_EXTENDED_SEGMENT:
// Set segment base address (offset = value * 16)
if (byte_count != 2)
return HEX_PARSE_ERROR_INVALID_FORMAT;
int value_high = hex_byte_to_int(line + 9);
int value_low = hex_byte_to_int(line + 11);
if (value_high < 0 || value_low < 0)
return HEX_PARSE_ERROR_INVALID_FORMAT;
*base_address = ((value_high << 8) | value_low) << 4;
break;
case HEX_RECORD_EXTENDED_LINEAR:
// Set high-order 16 bits of address
if (byte_count != 2)
return HEX_PARSE_ERROR_INVALID_FORMAT;
value_high = hex_byte_to_int(line + 9);
value_low = hex_byte_to_int(line + 11);
if (value_high < 0 || value_low < 0)
return HEX_PARSE_ERROR_INVALID_FORMAT;
*base_address = ((value_high << 8) | value_low) << 16;
break;
case HEX_RECORD_START_LINEAR:
// Start linear address - store as a potential entry point
// but not crucial for firmware extraction
break;
case HEX_RECORD_START_SEGMENT:
// Start segment address - similar to above
break;
default:
return HEX_PARSE_ERROR_UNSUPPORTED_RECORD;
}
return record_type;
}
int hex_file_parse(const char* file_path_on_disk,
uint8_t** payload,
size_t* payload_length,
size_t* payload_address) {
FILE* file = fopen(file_path_on_disk, "r");
if (!file) {
fprintf(stderr, "Could not open file %s for reading\n", file_path_on_disk);
return PARSED_ERROR_CANT_OPEN_FILE;
}
// First pass: Find start and end addresses, and thus size of the payload
char line[512];
uint32_t base_address = 0;
uint32_t address = 0;
uint32_t min_address = 0xFFFFFFFF;
uint32_t max_address = 0;
bool found_data = false;
// First pass to determine memory range
while (fgets(line, sizeof(line), file)) {
size_t len = strlen(line);
// Trim trailing newline and carriage return
while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
line[--len] = 0;
}
if (len == 0 || line[0] != ':')
continue;
int result =
parse_hex_line(line, NULL, &address, &base_address, &max_address, 0);
if (result < 0) {
fclose(file);
return result;
}
// Check if this is a data record (type 0)
if (result == HEX_RECORD_DATA) {
found_data = true;
if (address < min_address) {
min_address = address;
}
}
// If we hit EOF record, we're done
if (result == HEX_RECORD_EOF) {
break;
}
}
// If no data was found, return error
if (!found_data) {
fclose(file);
return HEX_PARSE_ERROR_INVALID_FORMAT;
}
// Calculate payload size
size_t size = max_address - min_address;
if (size > (1024 * 1024 * 128)) { // Limit to 128 MB
fclose(file);
return HEX_PARSE_ERROR_TOO_LARGE;
}
// Allocate memory for the payload
*payload = (uint8_t*)calloc(size, sizeof(uint8_t));
if (!*payload) {
fclose(file);
return -1;
}
// Clear the memory to ensure all bytes are initialized
memset(*payload, 0, size);
// Second pass: actually parse the data and fill out the buffer with the data
rewind(file);
base_address = 0;
while (fgets(line, sizeof(line), file)) {
size_t len = strlen(line);
// Trim trailing newline and carriage return
while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
line[--len] = 0;
}
if (len == 0 || line[0] != ':')
continue;
// When parsing for real, data is written to the payload buffer
// with addresses relative to min_address
uint32_t dummy_max = 0;
int result = parse_hex_line(line, *payload, &address, &base_address,
&dummy_max, min_address);
if (result < 0) {
free(*payload);
*payload = NULL;
fclose(file);
return result;
}
// If we hit EOF record, we're done
if (result == HEX_RECORD_EOF) {
break;
}
}
fclose(file);
// Set output parameters
*payload_length = size;
*payload_address = min_address;
return 0;
}
@@ -0,0 +1,49 @@
//
// Created for Intel HEX file parsing
//
#ifndef BLISP_HEX_FILE_H
#define BLISP_HEX_FILE_H
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
// Error codes specific to hex parsing
#define HEX_PARSE_ERROR_INVALID_FORMAT -0x2001
#define HEX_PARSE_ERROR_CHECKSUM -0x2002
#define HEX_PARSE_ERROR_UNSUPPORTED_RECORD -0x2003
#define HEX_PARSE_ERROR_TOO_LARGE -0x2004
// Intel HEX record types
typedef enum {
HEX_RECORD_DATA = 0x00, // Data record
HEX_RECORD_EOF = 0x01, // End of file record
HEX_RECORD_EXTENDED_SEGMENT = 0x02, // Extended segment address record
HEX_RECORD_START_SEGMENT = 0x03, // Start segment address record
HEX_RECORD_EXTENDED_LINEAR = 0x04, // Extended linear address record
HEX_RECORD_START_LINEAR = 0x05 // Start linear address record
} hex_record_type_t;
// Parse an Intel HEX file and return a contiguous memory block
// Parameters:
// file_path_on_disk: Path to the Intel HEX file
// payload: Pointer to the buffer that will hold the parsed data
// payload_length: Size of the payload
// payload_address: Start address of the payload
// Returns:
// 0 on success, negative value on error
int hex_file_parse(const char* file_path_on_disk,
uint8_t** payload,
size_t* payload_length,
size_t* payload_address);
#ifdef __cplusplus
};
#endif
#endif // BLISP_HEX_FILE_H
@@ -0,0 +1,10 @@
add_executable(hex_file_test test_hex_file.cpp ../hex_file.c )
target_link_libraries(hex_file_test
PRIVATE
GTest::GTest
)
include(GoogleTest)
include_directories(hex_file_test PRIVATE ../ ../../)
target_compile_definitions(hex_file_test PUBLIC "SOURCE_DIR=\"${CMAKE_SOURCE_DIR}\"")
gtest_discover_tests(hex_file_test)
@@ -0,0 +1,9 @@
:02000004230FC8
:10FC0000400196000500000021005A000200070094
:10FC10000100000000001E000000000000000000C5
:10FC2000000000000000040001007602A40184032B
:10FC3000000000000A0001000700000000000000B2
:10FC4000140000001A000100000000000000040081
:10FC50005A00010082005A008C001E00A5001E0000
:10FC60008C001E005A001E00020000000000000070
:00000001FF
@@ -0,0 +1,47 @@
// Intel hex file parser test
#include <gtest/gtest.h>
#include "hex_file.h"
#include "parse_file.h"
TEST(HEX_FILE_PARSER, ParseTestFile) {
uint8_t* payload = nullptr;
size_t payload_size = 0;
size_t payload_address = 0;
int res = hex_file_parse(SOURCE_DIR
"/tools/blisp/src/file_parsers/hex/tests/test.hex",
&payload, &payload_size, &payload_address);
// Shall return 0 on success
ASSERT_EQ(res, 0);
// The expected base address is 0x230F0000 + 0xFC00 = 0x230FFC00
ASSERT_EQ(payload_address, 0x230FFC00);
// There are 7 data records of 16 bytes each, so payload size should be 0x70
// (112 bytes)
ASSERT_EQ(payload_size, 0x70);
// Optionally, check the first few bytes for expected values
ASSERT_EQ(payload[0], 0x40);
ASSERT_EQ(payload[1], 0x01);
ASSERT_EQ(payload[2], 0x96);
ASSERT_EQ(payload[3], 0x00);
// Clean up
free(payload);
}
TEST(HEX_FILE_PARSER, ParseNonExistentFile) {
uint8_t* payload = nullptr;
size_t payload_size = 0;
size_t payload_address = 0;
int res = hex_file_parse(SOURCE_DIR "/non_existent_file.hex", &payload,
&payload_size, &payload_address);
ASSERT_EQ(res, PARSED_ERROR_CANT_OPEN_FILE);
}
TEST(HEX_FILE_PARSER, ParseInvalidFormat) {
// This test would require creating an invalid hex file
// For simplicity, we'll skip actual implementation
// but in a real test suite we would create a file with invalid format
// and verify that it returns HEX_PARSE_ERROR_INVALID_FORMAT
}
+49
View File
@@ -0,0 +1,49 @@
#include "parse_file.h"
#include <string.h>
#include "bin_file.h"
#include "dfu_file.h"
#include "hex_file.h"
const char* get_filename_ext(const char* filename) {
const char* dot = strrchr(filename, '.');
if (!dot || dot == filename)
return "";
return dot + 1;
}
#define FLASH_MAP_ADDR 0x23000000
int parse_firmware_file(const char* file_path_on_disk,
parsed_firmware_file_t* parsed_results) {
// Switchcase on the extension of the file
const char* ext = get_filename_ext(file_path_on_disk);
int res = PARSED_ERROR_INVALID_FILETYPE;
if (strncmp(ext, "dfu", 3) == 0 || strncmp(ext, "DFU", 3) == 0) {
printf("Input file identified as a .dfu file\n");
// Handle as a .dfu file
res = dfu_file_parse(file_path_on_disk, &parsed_results->payload,
&parsed_results->payload_length,
&parsed_results->payload_address);
} else if (strncmp(ext, "bin", 3) == 0 || strncmp(ext, "BIN", 3) == 0) {
printf("Input file identified as a .bin file\n");
// Raw binary file
res = bin_file_parse(file_path_on_disk, &parsed_results->payload,
&parsed_results->payload_length,
&parsed_results->payload_address);
} else if (strncmp(ext, "hex", 3) == 0 || strncmp(ext, "HEX", 3) == 0) {
printf("Input file identified as a .hex file\n");
// Intel HEX file
res = hex_file_parse(file_path_on_disk, &parsed_results->payload,
&parsed_results->payload_length,
&parsed_results->payload_address);
}
// Normalise address, some builds will base the firmware at flash start but
// for the flasher we use 0 base (i.e. offsets into flash)
if (parsed_results->payload_address >= FLASH_MAP_ADDR) {
parsed_results->payload_address -= FLASH_MAP_ADDR;
}
// If the firmware starts at "0" we need to pre-pend a boot sector later on
parsed_results->needs_boot_struct = parsed_results->payload_address == 0;
return res;
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef PARSE_FILE_H_
#define PARSE_FILE_H_
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> /* ssize_t */
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
#include "parsed_firmware_file.h"
#define PARSED_ERROR_INVALID_FILETYPE -0x1000
#define PARSED_ERROR_CANT_OPEN_FILE -0x1001
#define PARSED_ERROR_TOO_BIG -0x1001 /* Input expands to be too big */
#define PARSED_ERROR_BAD_DFU -0x1002 /* DFU file provided but not valid */
// This attempts to parse the given file, and returns the parsed version of that
// file. This will handle any repacking required to create one contigious file
// Eg if the input file has holes,they will be 0x00 filled
// And headers etc are parsed to determine start position
int parse_firmware_file(const char* file_path_on_disk,
parsed_firmware_file_t* parsed_results);
// Internal util
ssize_t get_file_contents(const char* file_path_on_disk,
uint8_t** file_contents);
#endif // PARSE_FILE_H_
@@ -0,0 +1,17 @@
#ifndef PARSED_FIRMWARE_H_
#define PARSED_FIRMWARE_H_
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
// Parsed firmware file is a generic struct that we parse from a user input
// firmware file This is used so that we can (relatively) seamlessly handle
// .bin, .hex and .def files
typedef struct {
bool needs_boot_struct; // If true, boot struct should be generated
uint8_t* payload; // The main firmware payload
size_t payload_length; // Size of the payload
size_t payload_address; // Start address of the payload
} parsed_firmware_file_t;
#endif // PARSED_FIRMWARE_H_
+25 -19
View File
@@ -14,7 +14,7 @@ static struct arg_lit* version;
static struct arg_end* end; static struct arg_end* end;
static void* argtable[3]; static void* argtable[3];
int8_t args_init() { blisp_return_t args_init() {
argtable[0] = help = arg_lit0(NULL, "help", "print this help and exit"); argtable[0] = help = arg_lit0(NULL, "help", "print this help and exit");
argtable[1] = version = argtable[1] = version =
arg_lit0(NULL, "version", "print version information and exit"); arg_lit0(NULL, "version", "print version information and exit");
@@ -22,10 +22,10 @@ int8_t args_init() {
if (arg_nullcheck(argtable) != 0) { if (arg_nullcheck(argtable) != 0) {
fprintf(stderr, "insufficient memory\n"); fprintf(stderr, "insufficient memory\n");
return -1; return BLISP_ERR_OUT_OF_MEMORY;
} }
return 0; return BLISP_OK;
} }
void print_help() { void print_help() {
@@ -43,14 +43,14 @@ int8_t args_parse_exec(int argc, char** argv) {
if (error == 0) { if (error == 0) {
if (help->count) { if (help->count) {
print_help(); print_help();
return 1; return BLISP_OK;
} else if (version->count) { } else if (version->count) {
printf("blisp v0.0.3\n"); printf("blisp v0.0.5\n");
printf("Copyright (C) 2023 Marek Kraus and PINE64 Community\n"); printf("Copyright (C) 2023 Marek Kraus and PINE64 Community\n");
return 1; return BLISP_OK;
} }
} }
return 0; return BLISP_ERR_INVALID_COMMAND;
} }
void args_free() { void args_free() {
@@ -58,27 +58,29 @@ void args_free() {
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
int exit_code = 0; blisp_return_t ret = args_init();
if (ret != 0) {
if (args_init() != 0) {
exit_code = -1;
goto exit; goto exit;
} }
for (uint8_t i = 0; i < cmds_count; i++) { for (uint8_t i = 0; i < cmds_count; i++) {
if (cmds[i]->args_init() != 0) { ret = cmds[i]->args_init();
exit_code = -1; if (ret != BLISP_OK) {
goto exit;
}
}
// Try and parse as a help request
{
ret = args_parse_exec(argc, argv);
if (ret == BLISP_OK) {
goto exit; goto exit;
} }
} }
if (args_parse_exec(argc, argv)) {
goto exit;
}
uint8_t command_found = false; uint8_t command_found = false;
for (uint8_t i = 0; i < cmds_count; i++) { for (uint8_t i = 0; i < cmds_count; i++) {
if (cmds[i]->args_parse_exec(argc, argv)) { ret = cmds[i]->args_parse_exec(argc, argv);
if (ret != BLISP_ERR_INVALID_COMMAND) {
command_found = true; command_found = true;
break; break;
} }
@@ -93,5 +95,9 @@ exit:
cmds[i]->args_free(); cmds[i]->args_free();
} }
args_free(); args_free();
return exit_code; // Make error codes more intuitive, but converting to +ve mirror
if (ret < 0) {
ret = -ret;
}
return ret;
} }
+5
View File
@@ -35,6 +35,11 @@ ssize_t util_get_binary_folder(char* buffer, uint32_t buffer_size) {
#elif defined(__APPLE__) #elif defined(__APPLE__)
util_get_executable_path(buffer, buffer_size); util_get_executable_path(buffer, buffer_size);
char* pos = strrchr(buffer, '/'); char* pos = strrchr(buffer, '/');
#elif __FreeBSD__
if (readlink("/proc/curproc/file", buffer, buffer_size) <= 0) {
return -1;
}
char* pos = strrchr(buffer, '/');
#else #else
if (GetModuleFileName(NULL, buffer, buffer_size) <= 0) { if (GetModuleFileName(NULL, buffer, buffer_size) <= 0) {
return -1; return -1;
+3 -3
View File
@@ -4,9 +4,7 @@
#include <stdint.h> #include <stdint.h>
#ifdef __linux__ #if defined(_MSC_VER)
#include <unistd.h>
#elif defined(_MSC_VER)
#include <BaseTsd.h> #include <BaseTsd.h>
typedef SSIZE_T ssize_t; typedef SSIZE_T ssize_t;
#include <windows.h> #include <windows.h>
@@ -15,6 +13,8 @@ typedef SSIZE_T ssize_t;
#include <sys/syslimits.h> #include <sys/syslimits.h>
#include <assert.h> #include <assert.h>
#include <sys/types.h> #include <sys/types.h>
#else
#include <unistd.h>
#endif #endif
ssize_t util_get_binary_folder(char* buffer, uint32_t buffer_size); ssize_t util_get_binary_folder(char* buffer, uint32_t buffer_size);