mirror of
https://github.com/pine64/blisp.git
synced 2025-06-16 17:44:45 +00:00
Compare commits
110 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e45941c45e | ||
|
0d997dfb1e | ||
|
a7f857e63b | ||
|
010f6b4d3a | ||
|
d47d3f9a20 | ||
|
feb324443b | ||
|
a67a771bd6 | ||
|
1cef97ca89 | ||
|
bfe472e71c | ||
|
2268e535d4 | ||
|
cb32800728 | ||
|
da463d79fd | ||
|
1fb33da291 | ||
|
17f6234a4a | ||
|
108c387d31 | ||
|
ebae66c392 | ||
|
c2fc20452c | ||
|
39388c6b2c | ||
|
d51e7bcc1e | ||
|
d63612c256 | ||
|
98784b1776 | ||
|
3490c37581 | ||
|
be86373d37 | ||
|
81faf3f213 | ||
|
7a85414ece | ||
|
c41d128e73 | ||
|
d2fef0af22 | ||
|
2203a250e3 | ||
|
713e444656 | ||
|
3b47993de7 | ||
|
f601b6b965 | ||
|
48af2aded0 | ||
|
f1b93a1881 | ||
|
048a724082 | ||
|
37571bc5f1 | ||
![]() |
8914260b60 | ||
|
2e931f80db | ||
|
ec078224bd | ||
|
33c3f36b98 | ||
|
f6f2013c8e | ||
|
729609f2c0 | ||
|
89488b3bb5 | ||
|
491dd4f8c0 | ||
|
5306720e5d | ||
|
bac4f4b49f | ||
|
6ec0e9e862 | ||
|
6e2d40b9c4 | ||
|
fced48570a | ||
|
179a4ea267 | ||
|
2ad3ae7b50 | ||
|
de4a9cd5e6 | ||
|
0b363c620a | ||
|
e7eeef5f85 | ||
|
aaf07b7724 | ||
|
8c3b93cbec | ||
|
cc9ef81934 | ||
|
9cb381d03e | ||
|
f47bc9f948 | ||
|
4b8713ecd4 | ||
|
935ee4a12c | ||
|
55198e9612 | ||
|
63dff45156 | ||
|
a98a5090b3 | ||
|
55f40caa60 | ||
|
7618f24c97 | ||
|
fb31f9a742 | ||
|
28d0743742 | ||
|
042b9a72f0 | ||
|
eb55ab4702 | ||
|
ca4aca7219 | ||
|
6f174eaffe | ||
|
a59d4f7a32 | ||
|
93703a7c2e | ||
|
6f508d3db8 | ||
|
565c9ff913 | ||
|
e219e50efb | ||
|
5a0ae8abc3 | ||
|
0275fad1db | ||
|
e63ca04be5 | ||
|
8c21c18b3a | ||
|
23ca06a336 | ||
|
5ebcf881b6 | ||
|
cda17f2713 | ||
|
933851a775 | ||
|
32e2a64390 | ||
|
c157261bf2 | ||
|
b54d820408 | ||
|
9d4294f308 | ||
|
44f5c12b40 | ||
|
f2605801a4 | ||
|
670ec95507 | ||
|
f8acfa2ac1 | ||
|
3d4dfe8b81 | ||
|
4afdfff4b7 | ||
|
7669ebbbcb | ||
|
6424f9ddf8 | ||
|
7fb2cc829c | ||
|
a67ab9d218 | ||
|
3fff531334 | ||
|
53b57c3158 | ||
|
884142932d | ||
|
5e09eca00d | ||
|
5a6cd281c3 | ||
|
2141e33c2b | ||
|
a7c69dbcee | ||
|
10b150ee76 | ||
|
cbac0733ee | ||
|
3325f3725e | ||
|
626522e074 | ||
|
b941e60fbd |
157
.github/workflows/build.yml
vendored
Normal file
157
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,157 @@
|
||||
name: Build
|
||||
on: [push, pull_request]
|
||||
|
||||
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:
|
||||
runs-on: windows-2022
|
||||
defaults:
|
||||
run:
|
||||
shell: cmd
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- uses: lukka/get-cmake@latest
|
||||
- name: Build blisp tool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DBLISP_BUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build . --config Release
|
||||
- name: Upload results
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: blips-windows-x86_64
|
||||
path: |
|
||||
build/tools/blisp/Release/blisp.exe
|
||||
if-no-files-found: error
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- uses: lukka/get-cmake@latest
|
||||
- name: Build blisp tool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DBLISP_BUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build .
|
||||
- name: Upload results
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: blips-apple-universal
|
||||
path: |
|
||||
build/tools/blisp/blisp
|
||||
if-no-files-found: error
|
||||
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- uses: lukka/get-cmake@latest
|
||||
- name: Build blisp tool
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DBLISP_BUILD_CLI=ON -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build .
|
||||
- name: Upload results
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: blips-linux-x86_64
|
||||
path: |
|
||||
build/tools/blisp/blisp
|
||||
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
|
111
CMakeLists.txt
111
CMakeLists.txt
@ -1,9 +1,13 @@
|
||||
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)
|
||||
|
||||
set(CMAKE_C_STANDARD 23)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
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
|
||||
lib/blisp.c
|
||||
@ -17,56 +21,89 @@ set_property(TARGET libblisp_obj PROPERTY POSITION_INDEPENDENT_CODE 1)
|
||||
add_library(libblisp SHARED $<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
|
||||
PUBLIC_HEADER "include/blisp.h"
|
||||
VERSION 0.0.1
|
||||
PUBLIC_HEADER "${BLISP_PUBLIC_HEADERS}"
|
||||
VERSION 0.0.4
|
||||
SOVERSION 1
|
||||
LIBRARY_OUTPUT_DIRECTORY "shared"
|
||||
OUTPUT_NAME "blisp")
|
||||
|
||||
set_target_properties(libblisp_static PROPERTIES
|
||||
PUBLIC_HEADER "include/blisp.h"
|
||||
VERSION 0.0.1
|
||||
SOVERSION 2
|
||||
PUBLIC_HEADER "${BLISP_PUBLIC_HEADERS}"
|
||||
VERSION 0.0.4
|
||||
SOVERSION 1
|
||||
ARCHIVE_OUTPUT_DIRECTORY "static"
|
||||
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/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)
|
||||
target_link_libraries(libblisp_obj PRIVATE Setupapi.lib)
|
||||
target_compile_definitions(libblisp_obj PRIVATE LIBSERIALPORT_MSBUILD)
|
||||
target_sources(libblisp_obj PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/vendor/libserialport/windows.c)
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
target_sources(libblisp_obj PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/vendor/libserialport/linux.c
|
||||
${CMAKE_SOURCE_DIR}/vendor/libserialport/linux_termios.c)
|
||||
target_compile_definitions(libblisp_obj PRIVATE
|
||||
LIBSERIALPORT_ATBUILD
|
||||
HAVE_TERMIOS2_SPEED
|
||||
HAVE_STRUCT_TERMIOS2
|
||||
HAVE_DECL_BOTHER
|
||||
"SP_API=__attribute__((visibility(\"default\")))"
|
||||
"SP_PRIV=__attribute__((visibility(\"hidden\")))")
|
||||
write_file(${CMAKE_SOURCE_DIR}/vendor/libserialport/config.h "// bypass errors.")
|
||||
elseif(APPLE)
|
||||
target_sources(libblisp_obj PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/vendor/libserialport/macosx.c)
|
||||
target_link_libraries(libblisp PRIVATE "-framework IOKit" "-framework CoreFoundation")
|
||||
target_compile_definitions(libblisp_obj PRIVATE
|
||||
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.")
|
||||
if(WIN32)
|
||||
target_link_libraries(libblisp PRIVATE Setupapi.lib)
|
||||
target_link_libraries(libblisp_static PRIVATE Setupapi.lib)
|
||||
target_compile_definitions(libblisp_obj PRIVATE LIBSERIALPORT_MSBUILD)
|
||||
target_sources(libblisp_obj PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/vendor/libserialport/windows.c)
|
||||
elseif(UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
target_sources(libblisp_obj PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/vendor/libserialport/linux.c
|
||||
${CMAKE_SOURCE_DIR}/vendor/libserialport/linux_termios.c)
|
||||
target_compile_definitions(libblisp_obj PRIVATE
|
||||
LIBSERIALPORT_ATBUILD
|
||||
HAVE_TERMIOS2_SPEED
|
||||
HAVE_STRUCT_TERMIOS2
|
||||
HAVE_DECL_BOTHER
|
||||
"SP_API=__attribute__((visibility(\"default\")))"
|
||||
"SP_PRIV=__attribute__((visibility(\"hidden\")))")
|
||||
write_file(${CMAKE_SOURCE_DIR}/vendor/libserialport/config.h "// bypass errors.")
|
||||
elseif(UNIX AND ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
target_include_directories(libblisp_obj PRIVATE /usr/local/include/)
|
||||
target_link_libraries(libblisp PRIVATE -L/usr/local/lib usb serialport)
|
||||
target_link_libraries(libblisp_static PRIVATE -L/usr/local/lib usb serialport)
|
||||
elseif(APPLE)
|
||||
target_sources(libblisp_obj PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/vendor/libserialport/macosx.c)
|
||||
target_link_libraries(libblisp PRIVATE "-framework IOKit" "-framework CoreFoundation")
|
||||
target_compile_definitions(libblisp_obj PRIVATE
|
||||
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()
|
||||
|
||||
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)
|
||||
add_subdirectory(tools/blisp)
|
||||
endif()
|
||||
|
||||
|
||||
if(COMPILE_TESTS)
|
||||
add_subdirectory(tools/blisp/src/cmd/dfu/tests)
|
||||
endif(COMPILE_TESTS)
|
||||
|
35
Makefile
Normal file
35
Makefile
Normal 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
|
||||
|
98
README.md
98
README.md
@ -1,34 +1,51 @@
|
||||
# Bouffalo Labs ISP tool & library
|
||||
[](https://github.com/pine64/blisp/wiki/Update-Pinecil-V2)
|
||||
[](https://github.com/pine64/blisp/releases/tag/v0.0.4)
|
||||
[](https://discord.com/invite/pine64)
|
||||
[](https://github.com/pine64/blisp/releases/tag/v0.0.4)
|
||||
|
||||
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.
|
||||
<br>
|
||||
|
||||
# Supported MCUs
|
||||
|
||||
- [x] `bl60x` - BL602 / BL604
|
||||
## Supported MCUs
|
||||
- [x] `bl60x` - BL602 / BL604 / TG7100C / LF686 / LF688
|
||||
- [x] `bl70x` - BL702 / BL704 / BL706
|
||||
- [ ] `bl606p` - BL606P
|
||||
- [ ] `bl61x` - BL616 / BL618
|
||||
- [ ] `bl808` - BL808
|
||||
<br>
|
||||
|
||||
# Supported OS
|
||||
- [x] Windows
|
||||
- [x] Linux
|
||||
- [ ] Apple (WIP: work-in-progress)
|
||||
## Supported Devices
|
||||
| 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 |
|
||||
| :-----: | :------: | :------: | :------: | :------: |
|
||||
| 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>
|
||||
|
||||
## How to update Pinecil V2
|
||||
|
||||
# Building
|
||||
Download the newest release of [Blisp updater here](https://github.com/pine64/blisp/releases/).
|
||||
|
||||
## Clone repository
|
||||
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
|
||||
|
||||
```bash
|
||||
git clone --recursive https://github.com/pine64/blisp.git
|
||||
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:
|
||||
|
||||
@ -38,20 +55,59 @@ cmake -DBLISP_BUILD_CLI=ON ..
|
||||
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
|
||||
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:
|
||||
|
||||
```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.
|
||||
|
||||
## 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
blisp.nix
Normal file
49
blisp.nix
Normal 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.4-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
cmake/FindLibserialport.cmake
Normal file
79
cmake/FindLibserialport.cmake
Normal 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
default.nix
Normal file
9
default.nix
Normal 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
|
27
flake.lock
generated
Normal file
27
flake.lock
generated
Normal 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
flake.nix
Normal file
44
flake.nix
Normal 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 ];
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
BIN
img/Gradient-white-blue-03.png
Normal file
BIN
img/Gradient-white-blue-03.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
img/win32.png
Normal file
BIN
img/win32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 598 B |
@ -3,20 +3,8 @@
|
||||
#define _LIBBLISP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "blisp_chip.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
|
||||
};
|
||||
#include "error_codes.h"
|
||||
|
||||
struct blisp_segment_header {
|
||||
uint32_t dest_addr;
|
||||
|
@ -9,6 +9,12 @@
|
||||
#include <assert.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)
|
||||
|
||||
typedef struct {
|
||||
|
30
include/error_codes.h
Normal file
30
include/error_codes.h
Normal 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
|
136
lib/blisp.c
136
lib/blisp.c
@ -13,15 +13,22 @@
|
||||
|
||||
#define DEBUG
|
||||
|
||||
int32_t blisp_device_init(struct blisp_device* device,
|
||||
struct blisp_chip* chip) {
|
||||
device->chip = chip;
|
||||
device->is_usb = false;
|
||||
return 0;
|
||||
static void drain(struct sp_port* port) {
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
sp_drain(port);
|
||||
#endif
|
||||
}
|
||||
|
||||
int32_t blisp_device_open(struct blisp_device* device, const char* port_name) {
|
||||
int ret;
|
||||
blisp_return_t blisp_device_init(struct blisp_device* device,
|
||||
struct blisp_chip* chip) {
|
||||
device->chip = chip;
|
||||
device->is_usb = false;
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
blisp_return_t blisp_device_open(struct blisp_device* device,
|
||||
const char* port_name) {
|
||||
blisp_return_t ret;
|
||||
struct sp_port* serial_port = NULL;
|
||||
|
||||
if (port_name != NULL) {
|
||||
@ -38,7 +45,7 @@ int32_t blisp_device_open(struct blisp_device* device, const char* port_name) {
|
||||
ret = sp_list_ports(&port_list);
|
||||
if (ret != SP_OK) {
|
||||
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++) {
|
||||
struct sp_port* port = port_list[i];
|
||||
@ -63,8 +70,7 @@ int32_t blisp_device_open(struct blisp_device* device, const char* port_name) {
|
||||
ret = sp_open(serial_port, SP_MODE_READ_WRITE);
|
||||
if (ret != SP_OK) {
|
||||
blisp_dlog("SP open failed: %d", ret);
|
||||
return BLISP_ERR_UNKNOWN; // TODO: Maybe this should be that it can't open
|
||||
// device?
|
||||
return BLISP_ERR_CANT_OPEN_DEVICE;
|
||||
}
|
||||
// TODO: Handle errors in following functions, although, none of them *should*
|
||||
// fail
|
||||
@ -73,13 +79,13 @@ int32_t blisp_device_open(struct blisp_device* device, const char* port_name) {
|
||||
sp_set_stopbits(serial_port, 1);
|
||||
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);
|
||||
device->is_usb = pid == 0xFFFF;
|
||||
// if (device->is_usb) {
|
||||
// device->current_baud_rate = 2000000;
|
||||
// } else {
|
||||
device->current_baud_rate = 500000;
|
||||
device->current_baud_rate = 460800;
|
||||
// }
|
||||
|
||||
#if 0
|
||||
@ -93,19 +99,19 @@ int32_t blisp_device_open(struct blisp_device* device, const char* port_name) {
|
||||
#endif
|
||||
ret = sp_set_baudrate(serial_port, device->current_baud_rate);
|
||||
if (ret != SP_OK) {
|
||||
blisp_dlog("Set baud rate failed: %d... Also hello macOS user :)", ret);
|
||||
return BLISP_ERR_UNKNOWN;
|
||||
blisp_dlog("Set baud rate failed: %d... Also hello MacOS user :)", ret);
|
||||
return BLISP_ERR_API_ERROR;
|
||||
}
|
||||
device->serial_port = serial_port;
|
||||
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
int32_t blisp_send_command(struct blisp_device* device,
|
||||
uint8_t command,
|
||||
void* payload,
|
||||
uint16_t payload_size,
|
||||
bool add_checksum) {
|
||||
blisp_return_t blisp_send_command(struct blisp_device* device,
|
||||
uint8_t command,
|
||||
void* payload,
|
||||
uint16_t payload_size,
|
||||
bool add_checksum) {
|
||||
int ret;
|
||||
struct sp_port* serial_port = device->serial_port;
|
||||
|
||||
@ -128,20 +134,22 @@ int32_t blisp_send_command(struct blisp_device* device,
|
||||
sp_blocking_write(serial_port, device->tx_buffer, 4 + payload_size, 1000);
|
||||
if (ret != (4 + payload_size)) {
|
||||
blisp_dlog("Received error or not written all data: %d", ret);
|
||||
return BLISP_ERR_UNKNOWN;
|
||||
return BLISP_ERR_API_ERROR;
|
||||
}
|
||||
drain(serial_port);
|
||||
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
int32_t blisp_receive_response(struct blisp_device* device,
|
||||
bool expect_payload) {
|
||||
blisp_return_t blisp_receive_response(struct blisp_device* device,
|
||||
bool expect_payload) {
|
||||
// TODO: Check checksum
|
||||
int ret;
|
||||
struct sp_port* serial_port = device->serial_port;
|
||||
ret = sp_blocking_read(serial_port, &device->rx_buffer[0], 2, 1000);
|
||||
if (ret < 2) {
|
||||
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') {
|
||||
if (expect_payload) {
|
||||
sp_blocking_read(serial_port, &device->rx_buffer[2], 2,
|
||||
@ -163,10 +171,11 @@ int32_t blisp_receive_response(struct blisp_device* device,
|
||||
}
|
||||
blisp_dlog("Failed to receive any response (err: %d, %d - %d)", ret,
|
||||
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;
|
||||
uint8_t handshake_buffer[600];
|
||||
struct sp_port* serial_port = device->serial_port;
|
||||
@ -191,12 +200,15 @@ int32_t blisp_device_handshake(struct blisp_device* device, bool in_ef_loader) {
|
||||
if (!in_ef_loader) {
|
||||
if (device->is_usb) {
|
||||
sp_blocking_write(serial_port, "BOUFFALOLAB5555RESET\0\0", 22, 100);
|
||||
drain(serial_port);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
blisp_dlog("Handshake write failed, ret %d", ret);
|
||||
return BLISP_ERR_UNKNOWN;
|
||||
return BLISP_ERR_API_ERROR;
|
||||
}
|
||||
|
||||
if (!in_ef_loader && !device->is_usb) {
|
||||
@ -215,9 +227,9 @@ int32_t blisp_device_handshake(struct blisp_device* device, bool in_ef_loader) {
|
||||
return BLISP_ERR_NO_RESPONSE;
|
||||
}
|
||||
|
||||
int32_t blisp_device_get_boot_info(struct blisp_device* device,
|
||||
struct blisp_boot_info* boot_info) {
|
||||
int ret;
|
||||
blisp_return_t blisp_device_get_boot_info(struct blisp_device* device,
|
||||
struct blisp_boot_info* boot_info) {
|
||||
blisp_return_t ret;
|
||||
|
||||
ret = blisp_send_command(device, 0x10, NULL, 0, false);
|
||||
if (ret < 0)
|
||||
@ -228,7 +240,8 @@ int32_t blisp_device_get_boot_info(struct blisp_device* device,
|
||||
return ret;
|
||||
|
||||
memcpy(boot_info->boot_rom_version, &device->rx_buffer[0],
|
||||
4); // TODO: Endianess
|
||||
4); // TODO: Endianess; this may break on big endian machines
|
||||
|
||||
if (device->chip->type == BLISP_CHIP_BL70X) {
|
||||
memcpy(boot_info->chip_id, &device->rx_buffer[16], 8);
|
||||
}
|
||||
@ -237,9 +250,9 @@ int32_t blisp_device_get_boot_info(struct blisp_device* device,
|
||||
}
|
||||
|
||||
// TODO: Use struct instead of uint8_t*
|
||||
int32_t blisp_device_load_boot_header(struct blisp_device* device,
|
||||
uint8_t* boot_header) {
|
||||
int ret;
|
||||
blisp_return_t blisp_device_load_boot_header(struct blisp_device* device,
|
||||
uint8_t* boot_header) {
|
||||
blisp_return_t ret;
|
||||
ret = blisp_send_command(device, 0x11, boot_header, 176, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -250,10 +263,10 @@ int32_t blisp_device_load_boot_header(struct blisp_device* device,
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
int32_t blisp_device_load_segment_header(
|
||||
blisp_return_t blisp_device_load_segment_header(
|
||||
struct blisp_device* device,
|
||||
struct blisp_segment_header* segment_header) {
|
||||
int ret;
|
||||
blisp_return_t ret;
|
||||
ret = blisp_send_command(device, 0x17, segment_header, 16, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -264,10 +277,10 @@ int32_t blisp_device_load_segment_header(
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
int32_t blisp_device_load_segment_data(struct blisp_device* device,
|
||||
uint8_t* segment_data,
|
||||
uint32_t segment_data_length) {
|
||||
int ret;
|
||||
blisp_return_t blisp_device_load_segment_data(struct blisp_device* device,
|
||||
uint8_t* segment_data,
|
||||
uint32_t segment_data_length) {
|
||||
blisp_return_t ret;
|
||||
ret = blisp_send_command(device, 0x18, segment_data, segment_data_length,
|
||||
false);
|
||||
if (ret < 0)
|
||||
@ -279,8 +292,8 @@ int32_t blisp_device_load_segment_data(struct blisp_device* device,
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
int32_t blisp_device_check_image(struct blisp_device* device) {
|
||||
int ret;
|
||||
blisp_return_t blisp_device_check_image(struct blisp_device* device) {
|
||||
blisp_return_t ret;
|
||||
ret = blisp_send_command(device, 0x19, NULL, 0, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -291,11 +304,11 @@ int32_t blisp_device_check_image(struct blisp_device* device) {
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
int32_t blisp_device_write_memory(struct blisp_device* device,
|
||||
uint32_t address,
|
||||
uint32_t value,
|
||||
bool wait_for_res) {
|
||||
int ret;
|
||||
blisp_return_t blisp_device_write_memory(struct blisp_device* device,
|
||||
uint32_t address,
|
||||
uint32_t value,
|
||||
bool wait_for_res) {
|
||||
blisp_return_t ret;
|
||||
uint8_t payload[8];
|
||||
*(uint32_t*)(payload) = address;
|
||||
*(uint32_t*)(payload + 4) = value; // TODO: Endianness
|
||||
@ -311,8 +324,8 @@ int32_t blisp_device_write_memory(struct blisp_device* device,
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
int32_t blisp_device_run_image(struct blisp_device* device) {
|
||||
int ret;
|
||||
blisp_return_t blisp_device_run_image(struct blisp_device* device) {
|
||||
blisp_return_t ret;
|
||||
|
||||
if (device->chip->type == BLISP_CHIP_BL70X) { // ERRATA
|
||||
ret = blisp_device_write_memory(device, 0x4000F100, 0x4E424845, true);
|
||||
@ -339,14 +352,14 @@ int32_t blisp_device_run_image(struct blisp_device* device) {
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
int32_t blisp_device_flash_erase(struct blisp_device* device,
|
||||
uint32_t start_address,
|
||||
uint32_t end_address) {
|
||||
blisp_return_t blisp_device_flash_erase(struct blisp_device* device,
|
||||
uint32_t start_address,
|
||||
uint32_t end_address) {
|
||||
uint8_t payload[8];
|
||||
*(uint32_t*)(payload + 0) = start_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)
|
||||
return ret;
|
||||
do {
|
||||
@ -356,17 +369,18 @@ int32_t blisp_device_flash_erase(struct blisp_device* device,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t blisp_device_flash_write(struct blisp_device* device,
|
||||
uint32_t start_address,
|
||||
uint8_t* payload,
|
||||
uint32_t payload_size) {
|
||||
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: Don't use malloc + add check
|
||||
|
||||
uint8_t* buffer = malloc(4 + payload_size);
|
||||
*((uint32_t*)(buffer)) = start_address;
|
||||
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)
|
||||
goto exit1;
|
||||
ret = blisp_receive_response(device, false);
|
||||
@ -375,7 +389,7 @@ exit1:
|
||||
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);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -383,11 +397,11 @@ int32_t blisp_device_program_check(struct blisp_device* device) {
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
int32_t blisp_device_reset(struct blisp_device* device) {
|
||||
int ret = blisp_send_command(device, 0x21, NULL, 0, true);
|
||||
blisp_return_t blisp_device_reset(struct blisp_device* device) {
|
||||
blisp_return_t ret = blisp_send_command(device, 0x21, NULL, 0, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = blisp_receive_response(device, false);
|
||||
|
@ -6,12 +6,16 @@
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
static int64_t blisp_easy_transport_read(struct blisp_easy_transport* transport,
|
||||
void* buffer,
|
||||
uint32_t size) {
|
||||
static blisp_return_t blisp_easy_transport_read(
|
||||
struct blisp_easy_transport* transport,
|
||||
void* buffer,
|
||||
uint32_t size) {
|
||||
if (transport->type == 0) {
|
||||
// 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;
|
||||
return size;
|
||||
} 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) {
|
||||
return transport->data.memory.data_size;
|
||||
} else {
|
||||
// TODO: Implement
|
||||
printf("%s() Warning: calling non-implemented function\n", __func__);
|
||||
return BLISP_ERR_NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,17 +64,26 @@ int32_t blisp_easy_load_segment_data(
|
||||
struct blisp_easy_transport* segment_transport,
|
||||
blisp_easy_progress_callback progress_callback) {
|
||||
int32_t ret;
|
||||
#ifdef __APPLE__
|
||||
const uint16_t buffer_max_size = 252 * 16;
|
||||
#else
|
||||
const uint16_t buffer_max_size = 4092;
|
||||
#endif
|
||||
|
||||
uint32_t sent_data = 0;
|
||||
uint32_t buffer_size = 0;
|
||||
#ifdef _WIN32
|
||||
uint8_t buffer[4092];
|
||||
#else
|
||||
uint8_t buffer[buffer_max_size];
|
||||
#endif
|
||||
|
||||
blisp_easy_report_progress(progress_callback, 0, segment_size);
|
||||
|
||||
while (sent_data < segment_size) {
|
||||
buffer_size = segment_size - sent_data;
|
||||
if (buffer_size > 4092) {
|
||||
buffer_size = 4092;
|
||||
if (buffer_size > buffer_max_size) {
|
||||
buffer_size = buffer_max_size;
|
||||
}
|
||||
blisp_easy_transport_read(segment_transport, buffer,
|
||||
buffer_size); // TODO: Error Handling
|
||||
@ -80,7 +96,7 @@ int32_t blisp_easy_load_segment_data(
|
||||
sent_data += buffer_size;
|
||||
blisp_easy_report_progress(progress_callback, sent_data, segment_size);
|
||||
}
|
||||
return 0;
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
int32_t blisp_easy_load_ram_image(
|
||||
@ -131,10 +147,10 @@ int32_t blisp_easy_load_ram_image(
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
int32_t blisp_easy_load_ram_app(struct blisp_device* device,
|
||||
struct blisp_easy_transport* app_transport,
|
||||
blisp_easy_progress_callback progress_callback)
|
||||
{
|
||||
int32_t blisp_easy_load_ram_app(
|
||||
struct blisp_device* device,
|
||||
struct blisp_easy_transport* app_transport,
|
||||
blisp_easy_progress_callback progress_callback) {
|
||||
int32_t ret;
|
||||
// TODO: Rework
|
||||
// region boot header fill
|
||||
@ -281,7 +297,6 @@ int32_t blisp_easy_load_ram_app(struct blisp_device* device,
|
||||
boot_header.crc32 = 0xDEADBEEF;
|
||||
// endregion
|
||||
|
||||
|
||||
ret = blisp_device_load_boot_header(device, (uint8_t*)&boot_header);
|
||||
if (ret != BLISP_OK) {
|
||||
blisp_dlog("Failed to load boot header, ret: %d.", ret);
|
||||
@ -292,9 +307,9 @@ int32_t blisp_easy_load_ram_app(struct blisp_device* device,
|
||||
.dest_addr = device->chip->tcm_address,
|
||||
.length = blisp_easy_transport_size(app_transport),
|
||||
.reserved = 0,
|
||||
.crc32 = 0
|
||||
};
|
||||
segment_header.crc32 = crc32_calculate(&segment_header, 3 * sizeof(uint32_t)); // TODO: Make function
|
||||
.crc32 = 0};
|
||||
segment_header.crc32 = crc32_calculate(
|
||||
&segment_header, 3 * sizeof(uint32_t)); // TODO: Make function
|
||||
|
||||
ret = blisp_device_load_segment_header(device, &segment_header);
|
||||
if (ret != 0) {
|
||||
@ -302,14 +317,14 @@ int32_t blisp_easy_load_ram_app(struct blisp_device* device,
|
||||
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);
|
||||
if (ret != 0) {
|
||||
// TODO: Error printing
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
@ -319,23 +334,36 @@ int32_t blisp_easy_flash_write(struct blisp_device* device,
|
||||
uint32_t data_size,
|
||||
blisp_easy_progress_callback progress_callback) {
|
||||
int32_t ret;
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
const uint16_t buffer_max_size = 372 * 1;
|
||||
#else
|
||||
const uint16_t buffer_max_size = 2052;
|
||||
#endif
|
||||
|
||||
uint32_t sent_data = 0;
|
||||
uint32_t buffer_size = 0;
|
||||
uint8_t buffer[8184];
|
||||
#ifdef _WIN32
|
||||
uint8_t buffer[2052];
|
||||
#else
|
||||
uint8_t buffer[buffer_max_size];
|
||||
#endif
|
||||
blisp_easy_report_progress(progress_callback, 0, data_size);
|
||||
|
||||
while (sent_data < data_size) {
|
||||
buffer_size = data_size - sent_data;
|
||||
if (buffer_size > 2052) {
|
||||
buffer_size = 2052;
|
||||
if (buffer_size > buffer_max_size) {
|
||||
buffer_size = buffer_max_size;
|
||||
}
|
||||
blisp_easy_transport_read(data_transport, buffer,
|
||||
buffer_size); // TODO: Error Handling
|
||||
ret = blisp_easy_transport_read(data_transport, buffer, buffer_size);
|
||||
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,
|
||||
buffer_size);
|
||||
if (ret < BLISP_OK) {
|
||||
// TODO: Error logigng: fprintf(stderr, "Failed to write firmware! (ret:
|
||||
// %d)\n", ret);
|
||||
fprintf(stderr, "Failed to write firmware! (ret:%d)\n ", ret);
|
||||
return ret;
|
||||
}
|
||||
sent_data += buffer_size;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../../data/bl60x_eflash_loader.h"
|
||||
#include "blisp.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../../data/bl70x_eflash_loader.h"
|
||||
#include "blisp.h"
|
||||
|
9
shell.nix
Normal file
9
shell.nix
Normal 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
|
@ -1,17 +1,32 @@
|
||||
add_subdirectory(${CMAKE_SOURCE_DIR}/vendor/argtable3 ${CMAKE_CURRENT_BINARY_DIR}/argtable3)
|
||||
set(ARGTABLE3_ENABLE_TESTS OFF CACHE BOOL "Enable unit tests")
|
||||
set(ARGTABLE3_ENABLE_EXAMPLES OFF CACHE BOOL "Enable examples")
|
||||
#set(ARGTABLE3_REPLACE_GETOPT OFF CACHE BOOL "Replace getopt in the system C library")
|
||||
|
||||
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
|
||||
"${CMAKE_SOURCE_DIR}/include"
|
||||
add_subdirectory(src/file_parsers)
|
||||
|
||||
|
||||
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")
|
||||
endif()
|
||||
|
||||
target_include_directories(blisp PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/include")
|
||||
|
||||
target_link_libraries(blisp PRIVATE
|
||||
argtable3
|
||||
libblisp_static)
|
||||
argtable3::argtable3
|
||||
libblisp_static file_parsers)
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(blisp PRIVATE Setupapi.lib)
|
||||
elseif (APPLE)
|
||||
target_link_libraries(blisp PRIVATE "-framework IOKit" "-framework CoreFoundation")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
install(TARGETS blisp DESTINATION bin)
|
||||
|
@ -2,12 +2,20 @@
|
||||
#ifndef 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 {
|
||||
const char* name;
|
||||
int8_t (*args_init)();
|
||||
uint8_t (*args_parse_exec)(int argc, char** argv);
|
||||
blisp_return_t (*args_init)();
|
||||
blisp_return_t (*args_parse_exec)(int argc, char** argv);
|
||||
void (*args_print_syntax)();
|
||||
void (*args_free)();
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include <argtable3.h>
|
||||
#include <blisp_easy.h>
|
||||
#include "../cmd.h"
|
||||
#include "../common.h"
|
||||
#include <argtable3.h>
|
||||
|
||||
#define REG_EXTENDED 1
|
||||
#define REG_ICASE (REG_EXTENDED << 1)
|
||||
@ -9,21 +9,30 @@
|
||||
static struct arg_rex* cmd;
|
||||
static struct arg_file* single_download;
|
||||
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_lit* reset;
|
||||
static struct arg_end* end;
|
||||
static void* cmd_iot_argtable[7];
|
||||
static void cmd_iot_args_print_glossary();
|
||||
|
||||
void blisp_single_download()
|
||||
{
|
||||
blisp_return_t blisp_single_download() {
|
||||
struct blisp_device device;
|
||||
int32_t ret;
|
||||
blisp_return_t ret;
|
||||
|
||||
if (blisp_common_init_device(&device, port_name, chip_type) != 0) {
|
||||
return;
|
||||
if (access(single_download->filename[0], R_OK) != 0) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (blisp_common_prepare_flash(&device) != 0) {
|
||||
ret = blisp_common_init_device(&device, port_name, chip_type);
|
||||
if (ret != BLISP_OK) {
|
||||
return ret;
|
||||
}
|
||||
ret = blisp_common_prepare_flash(&device);
|
||||
if (ret != BLISP_OK) {
|
||||
// TODO: Error handling
|
||||
goto exit1;
|
||||
}
|
||||
@ -32,6 +41,7 @@ void blisp_single_download()
|
||||
if (data_file == NULL) {
|
||||
fprintf(stderr, "Failed to open data file \"%s\".\n",
|
||||
single_download->filename[0]);
|
||||
ret = BLISP_ERR_CANT_OPEN_FILE;
|
||||
goto exit1;
|
||||
}
|
||||
fseek(data_file, 0, SEEK_END);
|
||||
@ -39,9 +49,9 @@ void blisp_single_download()
|
||||
rewind(data_file);
|
||||
|
||||
printf("Erasing the area, this might take a while...\n");
|
||||
ret =
|
||||
blisp_device_flash_erase(&device, *single_download_location->ival,
|
||||
*single_download_location->ival + data_file_size + 1);
|
||||
ret = blisp_device_flash_erase(
|
||||
&device, *single_download_location->ival,
|
||||
*single_download_location->ival + data_file_size + 1);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to erase.\n");
|
||||
goto exit2;
|
||||
@ -51,8 +61,8 @@ void blisp_single_download()
|
||||
struct blisp_easy_transport data_transport =
|
||||
blisp_easy_transport_new_from_file(data_file);
|
||||
|
||||
ret = blisp_easy_flash_write(&device, &data_transport, *single_download_location->ival,
|
||||
data_file_size,
|
||||
ret = blisp_easy_flash_write(&device, &data_transport,
|
||||
*single_download_location->ival, data_file_size,
|
||||
blisp_common_progress_callback);
|
||||
if (ret < BLISP_OK) {
|
||||
fprintf(stderr, "Failed to write data to flash.\n");
|
||||
@ -67,21 +77,28 @@ void blisp_single_download()
|
||||
}
|
||||
printf("Program OK!\n");
|
||||
|
||||
if (reset->count > 0) { // TODO: could be common
|
||||
blisp_device_reset(&device);
|
||||
if (reset->count > 0) { // TODO: could be common
|
||||
printf("Resetting the chip.\n");
|
||||
ret = blisp_device_reset(&device);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to reset chip.\n");
|
||||
goto exit2;
|
||||
}
|
||||
}
|
||||
if (ret == BLISP_OK) {
|
||||
printf("Download complete!\n");
|
||||
}
|
||||
|
||||
printf("Download complete!\n");
|
||||
|
||||
exit2:
|
||||
if (data_file != NULL)
|
||||
fclose(data_file);
|
||||
exit1:
|
||||
blisp_device_close(&device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int8_t cmd_iot_args_init() {
|
||||
blisp_return_t cmd_iot_args_init() {
|
||||
cmd_iot_argtable[0] = cmd =
|
||||
arg_rex1(NULL, NULL, "iot", NULL, REG_ICASE, NULL);
|
||||
cmd_iot_argtable[1] = chip_type =
|
||||
@ -99,9 +116,9 @@ int8_t cmd_iot_args_init() {
|
||||
|
||||
if (arg_nullcheck(cmd_iot_argtable) != 0) {
|
||||
fprintf(stderr, "insufficient memory\n");
|
||||
return -1;
|
||||
return BLISP_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
return 0;
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
void cmd_iot_args_print_glossary() {
|
||||
@ -111,20 +128,19 @@ void cmd_iot_args_print_glossary() {
|
||||
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);
|
||||
if (errors == 0) {
|
||||
if (single_download->count == 1 && single_download_location->count == 1) {
|
||||
blisp_single_download();
|
||||
return 1;
|
||||
return blisp_single_download();
|
||||
} else {
|
||||
return 0;
|
||||
return BLISP_ERR_INVALID_COMMAND;
|
||||
}
|
||||
} else if (cmd->count == 1) {
|
||||
cmd_iot_args_print_glossary();
|
||||
return 1;
|
||||
return BLISP_OK;
|
||||
}
|
||||
return 0;
|
||||
return BLISP_ERR_INVALID_COMMAND;
|
||||
}
|
||||
|
||||
void cmd_iot_args_print_syntax() {
|
||||
@ -137,4 +153,4 @@ void cmd_iot_free() {
|
||||
}
|
||||
|
||||
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};
|
||||
|
@ -1,14 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <argtable3.h>
|
||||
#include <blisp.h>
|
||||
#include <blisp_easy.h>
|
||||
#include <blisp_struct.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../cmd.h"
|
||||
#include "../common.h"
|
||||
#include "../util.h"
|
||||
#include <argtable3.h>
|
||||
#include <blisp_easy.h>
|
||||
#include <blisp_struct.h>
|
||||
#include "parse_file.h"
|
||||
|
||||
#define REG_EXTENDED 1
|
||||
#define REG_ICASE (REG_EXTENDED << 1)
|
||||
@ -19,6 +20,7 @@ static struct arg_str *port_name, *chip_type;
|
||||
static struct arg_lit* reset;
|
||||
static struct arg_end* end;
|
||||
static void* cmd_write_argtable[6];
|
||||
static void cmd_write_args_print_glossary();
|
||||
|
||||
void fill_up_boot_header(struct bfl_boot_header* boot_header) {
|
||||
memcpy(boot_header->magiccode, "BFNP", 4);
|
||||
@ -164,12 +166,22 @@ void fill_up_boot_header(struct bfl_boot_header* boot_header) {
|
||||
boot_header->crc32 = 0xDEADBEEF;
|
||||
}
|
||||
|
||||
void blisp_flash_firmware() {
|
||||
blisp_return_t blisp_flash_firmware() {
|
||||
struct blisp_device device;
|
||||
int32_t ret;
|
||||
blisp_return_t ret;
|
||||
|
||||
if (blisp_common_init_device(&device, port_name, chip_type) != 0) {
|
||||
return;
|
||||
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 1;
|
||||
}
|
||||
|
||||
ret = blisp_common_init_device(&device, port_name, chip_type);
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (blisp_common_prepare_flash(&device) != 0) {
|
||||
@ -177,49 +189,66 @@ void blisp_flash_firmware() {
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
FILE* firmware_file = fopen(binary_to_write->filename[0], "rb");
|
||||
if (firmware_file == NULL) {
|
||||
fprintf(stderr, "Failed to open firmware file \"%s\".\n",
|
||||
binary_to_write->filename[0]);
|
||||
goto exit1;
|
||||
}
|
||||
fseek(firmware_file, 0, SEEK_END);
|
||||
int64_t firmware_file_size = ftell(firmware_file);
|
||||
rewind(firmware_file);
|
||||
parsed_firmware_file_t parsed_file;
|
||||
memset(&parsed_file, 0, sizeof(parsed_file));
|
||||
int parsed_result =
|
||||
parse_firmware_file(binary_to_write->filename[0], &parsed_file);
|
||||
|
||||
struct bfl_boot_header boot_header;
|
||||
fill_up_boot_header(&boot_header);
|
||||
// If we are injecting a bootloader section, make it, erase flash, and flash
|
||||
// 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;
|
||||
printf("Erasing flash, this might take a while...\n");
|
||||
ret =
|
||||
blisp_device_flash_erase(&device, firmware_base_address,
|
||||
firmware_base_address + firmware_file_size + 1);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to erase flash.\n");
|
||||
goto exit2;
|
||||
if (parsed_file.needs_boot_struct) {
|
||||
// Create a default boot header section in ram to be written out
|
||||
struct bfl_boot_header boot_header;
|
||||
fill_up_boot_header(&boot_header);
|
||||
printf("Erasing flash to flash boot header\n");
|
||||
ret = blisp_device_flash_erase(&device, 0x0000,
|
||||
sizeof(struct bfl_boot_header));
|
||||
|
||||
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 =
|
||||
blisp_device_flash_erase(&device, 0x0000, sizeof(struct bfl_boot_header));
|
||||
// Now that optional boot header is done, we clear out the flash for the new
|
||||
// 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) {
|
||||
fprintf(stderr, "Failed to erase flash.\n");
|
||||
fprintf(stderr,
|
||||
"Failed to erase flash. Tried to erase from 0x%08lu to 0x%08lu\n",
|
||||
parsed_file.payload_address,
|
||||
parsed_file.payload_address + parsed_file.payload_length + 1);
|
||||
goto exit2;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
printf("Flashing the firmware...\n");
|
||||
printf("Flashing the firmware %lu bytes @ 0x%08lu...\n",
|
||||
parsed_file.payload_length, parsed_file.payload_address);
|
||||
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, parsed_file.payload_address,
|
||||
parsed_file.payload_length, blisp_common_progress_callback);
|
||||
|
||||
ret = blisp_easy_flash_write(&device, &data_transport, firmware_base_address,
|
||||
firmware_file_size,
|
||||
blisp_common_progress_callback);
|
||||
if (ret < BLISP_OK) {
|
||||
fprintf(stderr, "Failed to write app to flash.\n");
|
||||
goto exit2;
|
||||
@ -242,13 +271,13 @@ void blisp_flash_firmware() {
|
||||
printf("Flash complete!\n");
|
||||
|
||||
exit2:
|
||||
if (firmware_file != NULL)
|
||||
fclose(firmware_file);
|
||||
if (parsed_file.payload != NULL)
|
||||
free(parsed_file.payload);
|
||||
exit1:
|
||||
blisp_device_close(&device);
|
||||
}
|
||||
|
||||
int8_t cmd_write_args_init() {
|
||||
blisp_return_t cmd_write_args_init() {
|
||||
cmd_write_argtable[0] = cmd =
|
||||
arg_rex1(NULL, NULL, "write", NULL, REG_ICASE, NULL);
|
||||
cmd_write_argtable[1] = chip_type =
|
||||
@ -264,9 +293,9 @@ int8_t cmd_write_args_init() {
|
||||
|
||||
if (arg_nullcheck(cmd_write_argtable) != 0) {
|
||||
fprintf(stderr, "insufficient memory\n");
|
||||
return -1;
|
||||
return BLISP_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
return 0;
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
void cmd_write_args_print_glossary() {
|
||||
@ -276,16 +305,16 @@ void cmd_write_args_print_glossary() {
|
||||
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);
|
||||
if (errors == 0) {
|
||||
blisp_flash_firmware(); // TODO: Error code?
|
||||
return 1;
|
||||
return blisp_flash_firmware(); // TODO: Error code?
|
||||
|
||||
} else if (cmd->count == 1) {
|
||||
cmd_write_args_print_glossary();
|
||||
return 1;
|
||||
return BLISP_OK;
|
||||
}
|
||||
return 0;
|
||||
return BLISP_ERR_INVALID_COMMAND;
|
||||
}
|
||||
|
||||
void cmd_write_args_print_syntax() {
|
||||
|
@ -3,23 +3,26 @@
|
||||
#include <argtable3.h>
|
||||
#include <blisp.h>
|
||||
#include <inttypes.h>
|
||||
#include <malloc.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "blisp_easy.h"
|
||||
#include "error_codes.h"
|
||||
#include "util.h"
|
||||
|
||||
void blisp_common_progress_callback(uint32_t current_value, uint32_t max_value) {
|
||||
printf("%" PRIu32 "b / %ldb (%.2f%%)\n", current_value, max_value,
|
||||
void blisp_common_progress_callback(uint32_t current_value,
|
||||
uint32_t max_value) {
|
||||
printf("%" PRIu32 "b / %u (%.2f%%)\n", current_value, max_value,
|
||||
(((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) {
|
||||
if (chip_type->count == 0) {
|
||||
fprintf(stderr, "Chip type is invalid.\n");
|
||||
return -1;
|
||||
return BLISP_ERR_INVALID_CHIP_TYPE;
|
||||
}
|
||||
|
||||
struct blisp_chip* chip = NULL;
|
||||
@ -30,44 +33,46 @@ int32_t blisp_common_init_device(struct blisp_device* device, struct arg_str* po
|
||||
chip = &blisp_chip_bl60x;
|
||||
} else {
|
||||
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);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to init device.\n");
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
ret = blisp_device_open(device,
|
||||
port_name->count == 1 ? port_name->sval[0] : NULL);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, ret == BLISP_ERR_DEVICE_NOT_FOUND ? "Device not found\n" : "Failed to open device.\n");
|
||||
return -1;
|
||||
fprintf(stderr, ret == BLISP_ERR_DEVICE_NOT_FOUND
|
||||
? "Device not found\n"
|
||||
: "Failed to open device.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares chip to access flash
|
||||
* this means performing handshake, and loading eflash_loader if needed.
|
||||
*/
|
||||
int32_t blisp_common_prepare_flash(struct blisp_device* device) {
|
||||
int32_t ret = 0;
|
||||
blisp_return_t blisp_common_prepare_flash(struct blisp_device* device) {
|
||||
blisp_return_t ret = 0;
|
||||
|
||||
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;
|
||||
return ret;
|
||||
}
|
||||
printf("Handshake successful!\nGetting chip info...\n");
|
||||
struct blisp_boot_info boot_info;
|
||||
ret = blisp_device_get_boot_info(device, &boot_info);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to get boot info.\n");
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
printf(
|
||||
@ -80,7 +85,7 @@ int32_t blisp_common_prepare_flash(struct blisp_device* device) {
|
||||
boot_info.chip_id[6], boot_info.chip_id[7]);
|
||||
|
||||
if (device->chip->load_eflash_loader == NULL) {
|
||||
return 0;
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
if (boot_info.boot_rom_version[0] == 255 &&
|
||||
@ -88,21 +93,24 @@ int32_t blisp_common_prepare_flash(struct blisp_device* device) {
|
||||
boot_info.boot_rom_version[2] == 255 &&
|
||||
boot_info.boot_rom_version[3] == 255) {
|
||||
printf("Device already in eflash_loader.\n");
|
||||
return 0;
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
uint8_t* eflash_loader_buffer = NULL;
|
||||
// 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 =
|
||||
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) {
|
||||
fprintf(stderr, "Failed to load eflash_loader, ret: %d\n", ret);
|
||||
ret = -1;
|
||||
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
@ -112,14 +120,12 @@ int32_t blisp_common_prepare_flash(struct blisp_device* device) {
|
||||
ret = blisp_device_check_image(device);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Failed to check image.\n");
|
||||
ret = -1;
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
ret = blisp_device_run_image(device);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to run image.\n");
|
||||
ret = -1;
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
@ -127,12 +133,12 @@ int32_t blisp_common_prepare_flash(struct blisp_device* device) {
|
||||
ret = blisp_device_handshake(device, true);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to handshake with device.\n");
|
||||
ret = -1;
|
||||
goto exit1;
|
||||
}
|
||||
printf("Handshake with eflash_loader successful.\n");
|
||||
exit1:
|
||||
if (eflash_loader_buffer != NULL)
|
||||
free(eflash_loader_buffer);
|
||||
|
||||
return ret;
|
||||
}
|
24
tools/blisp/src/file_parsers/CMakeLists.txt
Normal file
24
tools/blisp/src/file_parsers/CMakeLists.txt
Normal file
@ -0,0 +1,24 @@
|
||||
list(APPEND ADD_INCLUDE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/bin"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/dfu"
|
||||
"${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}/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}
|
||||
|
||||
)
|
15
tools/blisp/src/file_parsers/bin/bin_file.c
Normal file
15
tools/blisp/src/file_parsers/bin/bin_file.c
Normal file
@ -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;
|
||||
}
|
24
tools/blisp/src/file_parsers/bin/bin_file.h
Normal file
24
tools/blisp/src/file_parsers/bin/bin_file.h
Normal file
@ -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
|
53
tools/blisp/src/file_parsers/dfu/dfu_crc.c
Normal file
53
tools/blisp/src/file_parsers/dfu/dfu_crc.c
Normal file
@ -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);
|
||||
}
|
293
tools/blisp/src/file_parsers/dfu/dfu_file.c
Normal file
293
tools/blisp/src/file_parsers/dfu/dfu_file.c
Normal file
@ -0,0 +1,293 @@
|
||||
//
|
||||
// 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);
|
||||
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;
|
||||
}
|
27
tools/blisp/src/file_parsers/dfu/dfu_file.h
Normal file
27
tools/blisp/src/file_parsers/dfu/dfu_file.h
Normal file
@ -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
|
31
tools/blisp/src/file_parsers/dfu/tests/CMakeLists.txt
Normal file
31
tools/blisp/src/file_parsers/dfu/tests/CMakeLists.txt
Normal file
@ -0,0 +1,31 @@
|
||||
enable_language(CXX)
|
||||
|
||||
enable_testing()
|
||||
include(FetchContent)
|
||||
|
||||
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG release-1.11.0
|
||||
)
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
add_library(GTest::GTest INTERFACE IMPORTED)
|
||||
target_link_libraries(GTest::GTest INTERFACE gtest_main)
|
||||
|
||||
|
||||
add_executable(dfu_file_test test_dfu_file.cpp ../dfu_file.c ../dfu_crc.c)
|
||||
|
||||
target_link_libraries(dfu_file_test
|
||||
PRIVATE
|
||||
GTest::GTest
|
||||
)
|
||||
include_directories(dfu_file_test PRIVATE ../)
|
||||
add_test(dfu_file_test_gtests dfu_file_test)
|
||||
|
||||
configure_file(Config.h.in ${CMAKE_BINARY_DIR}/Config.h)
|
||||
include_directories(${CMAKE_BINARY_DIR})
|
||||
|
||||
set(TEST_APP_NAME dfu_file_tests)
|
||||
|
||||
#add_custom_command(TARGET ${TEST_APP_NAME} COMMAND ./${TEST_APP_NAME} POST_BUILD)
|
10
tools/blisp/src/file_parsers/dfu/tests/Config.h.in
Normal file
10
tools/blisp/src/file_parsers/dfu/tests/Config.h.in
Normal file
@ -0,0 +1,10 @@
|
||||
//
|
||||
// Created by ralim on 26/09/22.
|
||||
//
|
||||
|
||||
#ifndef BLISP_CONFIG_H_IN_H
|
||||
#define BLISP_CONFIG_H_IN_H
|
||||
|
||||
#define SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
|
||||
#endif // BLISP_CONFIG_H_IN_H
|
BIN
tools/blisp/src/file_parsers/dfu/tests/test.dfu
Normal file
BIN
tools/blisp/src/file_parsers/dfu/tests/test.dfu
Normal file
Binary file not shown.
17
tools/blisp/src/file_parsers/dfu/tests/test_dfu_file.cpp
Normal file
17
tools/blisp/src/file_parsers/dfu/tests/test_dfu_file.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by ralim on 26/09/22.
|
||||
//
|
||||
|
||||
#include "Config.h"
|
||||
#include "dfu_file.h"
|
||||
#include <gtest/gtest.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 "/test.dfu", &payload, &payload_size,
|
||||
&payload_address);
|
||||
ASSERT_EQ(res, 1);
|
||||
ASSERT_EQ(payload_size, 1337);
|
||||
ASSERT_EQ(payload_address, 0x11223344);
|
||||
}
|
48
tools/blisp/src/file_parsers/get_file_contents.c
Normal file
48
tools/blisp/src/file_parsers/get_file_contents.c
Normal file
@ -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;
|
||||
}
|
43
tools/blisp/src/file_parsers/parse_file.c
Normal file
43
tools/blisp/src/file_parsers/parse_file.c
Normal file
@ -0,0 +1,43 @@
|
||||
#include "parse_file.h"
|
||||
#include <string.h>
|
||||
#include "bin_file.h"
|
||||
#include "dfu_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);
|
||||
}
|
||||
// If we wanted to support hex files, here would be where
|
||||
|
||||
// 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
tools/blisp/src/file_parsers/parse_file.h
Normal file
29
tools/blisp/src/file_parsers/parse_file.h
Normal 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_
|
17
tools/blisp/src/file_parsers/parsed_firmware_file.h
Normal file
17
tools/blisp/src/file_parsers/parsed_firmware_file.h
Normal file
@ -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_
|
@ -14,7 +14,7 @@ static struct arg_lit* version;
|
||||
static struct arg_end* end;
|
||||
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[1] = version =
|
||||
arg_lit0(NULL, "version", "print version information and exit");
|
||||
@ -22,10 +22,10 @@ int8_t args_init() {
|
||||
|
||||
if (arg_nullcheck(argtable) != 0) {
|
||||
fprintf(stderr, "insufficient memory\n");
|
||||
return -1;
|
||||
return BLISP_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
void print_help() {
|
||||
@ -43,14 +43,14 @@ int8_t args_parse_exec(int argc, char** argv) {
|
||||
if (error == 0) {
|
||||
if (help->count) {
|
||||
print_help();
|
||||
return 1;
|
||||
return BLISP_OK;
|
||||
} else if (version->count) {
|
||||
printf("blisp 0.0.1\n");
|
||||
printf("blisp v0.0.4\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() {
|
||||
@ -58,27 +58,29 @@ void args_free() {
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int exit_code = 0;
|
||||
|
||||
if (args_init() != 0) {
|
||||
exit_code = -1;
|
||||
blisp_return_t ret = args_init();
|
||||
if (ret != 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < cmds_count; i++) {
|
||||
if (cmds[i]->args_init() != 0) {
|
||||
exit_code = -1;
|
||||
ret = cmds[i]->args_init();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (args_parse_exec(argc, argv)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
uint8_t command_found = false;
|
||||
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;
|
||||
break;
|
||||
}
|
||||
@ -93,5 +95,9 @@ exit:
|
||||
cmds[i]->args_free();
|
||||
}
|
||||
args_free();
|
||||
return exit_code;
|
||||
// Make error codes more intuitive, but converting to +ve mirror
|
||||
if (ret < 0) {
|
||||
ret = -ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
// These are not thread safe, but it doesn't place the responsibility
|
||||
// to free an allocated buffer on the caller.nn
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static void util_get_executable_path(char* buffer_out, uint32_t max_size) {
|
||||
assert(max_size >= PATH_MAX); // n.b. 1024 on MacOS. 4K on most Linux.
|
||||
|
||||
@ -33,6 +35,11 @@ ssize_t util_get_binary_folder(char* buffer, uint32_t buffer_size) {
|
||||
#elif defined(__APPLE__)
|
||||
util_get_executable_path(buffer, buffer_size);
|
||||
char* pos = strrchr(buffer, '/');
|
||||
#elif __FreeBSD__
|
||||
if (readlink("/proc/curproc/file", buffer, buffer_size) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
char* pos = strrchr(buffer, '/');
|
||||
#else
|
||||
if (GetModuleFileName(NULL, buffer, buffer_size) <= 0) {
|
||||
return -1;
|
||||
|
@ -4,9 +4,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#elif defined(_MSC_VER)
|
||||
#if defined(_MSC_VER)
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#include <windows.h>
|
||||
@ -14,10 +12,9 @@ typedef SSIZE_T ssize_t;
|
||||
#elif defined(__APPLE__)
|
||||
#include <sys/syslimits.h>
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/limits.h>
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
ssize_t util_get_binary_folder(char* buffer, uint32_t buffer_size);
|
||||
|
Loading…
x
Reference in New Issue
Block a user