mirror of
https://github.com/pine64/blisp.git
synced 2026-09-19 23:21:29 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
738626e67e |
+56
-2
@@ -1,4 +1,58 @@
|
||||
---
|
||||
BasedOnStyle: Chromium
|
||||
Language: Cpp
|
||||
BasedOnStyle: GNU
|
||||
IndentWidth: 4
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterFunction: false
|
||||
AfterCaseLabel: false
|
||||
AfterEnum: false
|
||||
AfterControlStatement: Never
|
||||
AfterStruct : false
|
||||
AfterUnion : false
|
||||
AfterExternBlock : false
|
||||
BeforeElse : false
|
||||
BeforeWhile : false
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: Left
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
AllowShortEnumsOnASingleLine: False
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine : false
|
||||
AlwaysBreakAfterReturnType: AllDefinitions
|
||||
AlignTrailingComments : true
|
||||
AlignConsecutiveMacros: AcrossEmptyLines
|
||||
KeepEmptyLinesAtTheStartOfBlocks : false
|
||||
PointerAlignment : Left
|
||||
QualifierAlignment : Left
|
||||
ReferenceAlignment : Left
|
||||
RemoveBracesLLVM : false
|
||||
SpaceAfterCStyleCast : false
|
||||
SpaceAfterLogicalNot : false
|
||||
SpaceAfterTemplateKeyword : false
|
||||
SpaceAroundPointerQualifiers : Before
|
||||
SpaceBeforeAssignmentOperators : true
|
||||
SpaceBeforeCaseColon : false
|
||||
SpaceBeforeCpp11BracedList : false
|
||||
SpaceBeforeParens : ControlStatements
|
||||
SpaceBeforeParensOptions :
|
||||
AfterControlStatements : true
|
||||
AfterFunctionDeclarationName : false
|
||||
AfterFunctionDefinitionName : false
|
||||
AfterOverloadedOperator : false
|
||||
SpaceBeforeRangeBasedForLoopColon : false
|
||||
SpaceBeforeSquareBrackets : false
|
||||
SpaceInEmptyBlock : false
|
||||
SpaceInEmptyParentheses : false
|
||||
SpacesInCStyleCastParentheses : false
|
||||
SpacesInConditionalStatement : false
|
||||
SpacesInContainerLiterals : false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets : false
|
||||
UseTab : Never
|
||||
|
||||
...
|
||||
BitFieldColonSpacing: None
|
||||
BreakBeforeBinaryOperators: All
|
||||
@@ -1,157 +0,0 @@
|
||||
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@v3
|
||||
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@v3
|
||||
with:
|
||||
name: blips-windows-x86_64.zip
|
||||
path: |
|
||||
build/tools/blisp/Release/blisp.exe
|
||||
if-no-files-found: error
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
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@v3
|
||||
with:
|
||||
name: blips-apple-universal.zip
|
||||
path: |
|
||||
build/tools/blisp/blisp
|
||||
if-no-files-found: error
|
||||
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
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@v3
|
||||
with:
|
||||
name: blips-linux-x86_64.zip
|
||||
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@v3
|
||||
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@v3
|
||||
with:
|
||||
name: blisp-linux-${{ matrix.arch }}.zip
|
||||
path: |
|
||||
artifacts/blisp-*
|
||||
if-no-files-found: error
|
||||
+1
-4
@@ -74,7 +74,4 @@ fabric.properties
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
build/
|
||||
|
||||
.DS_Store
|
||||
.idea/caches/build_file_checksums.ser
|
||||
+32
-74
@@ -1,18 +1,15 @@
|
||||
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)
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
project(blisp C)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
set(CMAKE_C_STANDARD 23)
|
||||
|
||||
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
|
||||
lib/chip/blisp_chip_bl60x.c
|
||||
lib/chip/blisp_chip_bl70x.c lib/blisp_easy.c)
|
||||
lib/chip/blisp_chip_bl70x.c
|
||||
lib/chip/blisp_chip_bl808.c)
|
||||
|
||||
target_include_directories(libblisp_obj PRIVATE ${CMAKE_SOURCE_DIR}/include/)
|
||||
|
||||
@@ -21,89 +18,50 @@ 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 "${BLISP_PUBLIC_HEADERS}"
|
||||
VERSION 0.0.4
|
||||
PUBLIC_HEADER "include/blisp.h"
|
||||
VERSION 1.0
|
||||
SOVERSION 1
|
||||
LIBRARY_OUTPUT_DIRECTORY "shared"
|
||||
OUTPUT_NAME "blisp")
|
||||
|
||||
set_target_properties(libblisp_static PROPERTIES
|
||||
PUBLIC_HEADER "${BLISP_PUBLIC_HEADERS}"
|
||||
VERSION 0.0.4
|
||||
PUBLIC_HEADER "include/blisp.h"
|
||||
VERSION 1.0
|
||||
SOVERSION 1
|
||||
ARCHIVE_OUTPUT_DIRECTORY "static"
|
||||
OUTPUT_NAME "blisp")
|
||||
|
||||
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
|
||||
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)
|
||||
endif()
|
||||
target_include_directories(libblisp_obj PRIVATE ${CMAKE_SOURCE_DIR}/vendor/libserialport)
|
||||
|
||||
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()
|
||||
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
|
||||
"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_obj PRIVATE "-framework IOKit" "-framework CoreFoundation")
|
||||
target_compile_definitions(libblisp_obj PRIVATE LIBSERIALPORT_ATBUILD "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()
|
||||
|
||||
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)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Marek Kraus <gamelaster@outlook.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,51 +1,18 @@
|
||||
[](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)
|
||||
# Bouffalo Labs ISP tool & library
|
||||
|
||||
<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.
|
||||
Tool and library for flashing their RISC-V MCUs.
|
||||
|
||||
**NOTE:** Library API and `blisp` tool cli arguments are not stable yet.
|
||||
<br>
|
||||
|
||||
## Supported MCUs
|
||||
- [x] `bl60x` - BL602 / BL604 / TG7100C / LF686 / LF688
|
||||
- [x] `bl70x` - BL702 / BL704 / BL706
|
||||
<br>
|
||||
# Supported MCUs
|
||||
|
||||
## Supported Devices
|
||||
| System | <img width="15" src="https://cdn.simpleicons.org/Windows11/5791ac" /> 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
|
||||
- [X] `bl60x` - BL602 / BL604
|
||||
- [X] `bl70x` - BL702 / BL704 / BL706
|
||||
- [ ] `bl606p` - BL606P
|
||||
- [ ] `bl61x` - BL616 / BL618
|
||||
- [ ] `bl808` - BL808
|
||||
|
||||
Download the newest release of [Blisp updater here](https://github.com/pine64/blisp/releases/).
|
||||
|
||||
Check out the [wiki page](https://github.com/pine64/blisp/wiki/Update-Pinecil-V2) for install instructions.
|
||||
<br><br>
|
||||
|
||||
## Building from code
|
||||
|
||||
### Clone repository
|
||||
|
||||
If you have not cloned this repository locally; clone the git repository locally by running
|
||||
|
||||
```bash
|
||||
git clone --recursive https://github.com/pine64/blisp.git
|
||||
cd blisp
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
If vendor/argtable3 and vendor/libserialport/ are empty, this last step has
|
||||
failed and should be investigated.
|
||||
|
||||
### Build the library and command line utility
|
||||
# Building
|
||||
|
||||
For building `blisp` command line tool, use following commands:
|
||||
|
||||
@@ -55,59 +22,22 @@ cmake -DBLISP_BUILD_CLI=ON ..
|
||||
cmake --build .
|
||||
```
|
||||
|
||||
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 .
|
||||
```
|
||||
# Usage
|
||||
|
||||
#### 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:
|
||||
For BL70X, BL61X, BL808 and BL606P, connected via USB, you can use following command, which will auto-detect serial port:
|
||||
|
||||
```bash
|
||||
.\blisp.exe write --chip=bl70x --reset .\name_of_firmware.bin
|
||||
or
|
||||
.\blisp.exe write -c bl70x --reset .\name_of_firmware.bin
|
||||
blisp --chip bl70x --reset name_of_firmware.bin
|
||||
```
|
||||
|
||||
For BL60X, you need to specify also the serial port path:
|
||||
|
||||
```bash
|
||||
blisp write --chip bl60x --reset -p /dev/ttyUSB0 name_of_firmware.bin
|
||||
blisp --chip bl60x --reset -p /dev/ttyUSB0 name_of_firmware.bin
|
||||
```
|
||||
|
||||
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
|
||||
# To Do
|
||||
|
||||
```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
|
||||
```
|
||||
- [ ] Another code style
|
||||
- [ ] Finalize API
|
||||
- [ ] SDIO and JTAG support
|
||||
@@ -1,49 +0,0 @@
|
||||
{
|
||||
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 ];
|
||||
};
|
||||
})
|
||||
@@ -1,79 +0,0 @@
|
||||
# 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()
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
(import (
|
||||
let
|
||||
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
|
||||
in
|
||||
fetchTarball {
|
||||
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||
}
|
||||
) { src = ./.; }).defaultNix
|
||||
Generated
-27
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
description = "A very basic flake";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{ self, nixpkgs, ... }@inputs:
|
||||
let
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
];
|
||||
forEachSystem = nixpkgs.lib.genAttrs systems;
|
||||
in
|
||||
{
|
||||
packages = forEachSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
with pkgs;
|
||||
{
|
||||
blisp = callPackage ./blisp.nix { inherit self; };
|
||||
default = self.packages.${system}.blisp;
|
||||
}
|
||||
);
|
||||
|
||||
devShells = forEachSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
with pkgs;
|
||||
{
|
||||
default = mkShell {
|
||||
name = "blisp-dev";
|
||||
nativeBuildInputs = [ self.packages.${system}.default ];
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB |
+22
-36
@@ -1,62 +1,48 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef _LIBBLISP_H
|
||||
#define _LIBBLISP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "blisp_chip.h"
|
||||
#include "error_codes.h"
|
||||
|
||||
struct blisp_segment_header {
|
||||
uint32_t dest_addr;
|
||||
uint32_t length;
|
||||
uint32_t reserved;
|
||||
uint32_t crc32;
|
||||
uint32_t dest_addr;
|
||||
uint32_t length;
|
||||
uint32_t reserved;
|
||||
uint32_t crc32;
|
||||
};
|
||||
|
||||
struct blisp_device {
|
||||
struct blisp_chip* chip;
|
||||
void* serial_port;
|
||||
bool is_usb;
|
||||
uint32_t current_baud_rate;
|
||||
uint8_t rx_buffer[5000]; // TODO:
|
||||
uint8_t tx_buffer[5000];
|
||||
uint16_t error_code;
|
||||
struct blisp_chip* chip;
|
||||
void* serial_port;
|
||||
bool is_usb;
|
||||
uint32_t current_baud_rate;
|
||||
uint8_t rx_buffer[5000]; // TODO:
|
||||
uint8_t tx_buffer[5000];
|
||||
uint16_t error_code;
|
||||
};
|
||||
|
||||
struct blisp_boot_info {
|
||||
uint8_t boot_rom_version[4];
|
||||
uint8_t chip_id[8]; // TODO: BL60X only 6 bytes
|
||||
uint8_t boot_rom_version[4];
|
||||
uint8_t chip_id[8]; // TODO: BL60X only 6 bytes
|
||||
};
|
||||
|
||||
// TODO: Refactor variable names, so all will follow same semantic, like
|
||||
// image_run, image_check etc.
|
||||
// TODO: Refactor variable names, so all will follow same semantic, like image_run, image_check etc.
|
||||
|
||||
int32_t blisp_device_init(struct blisp_device* device, struct blisp_chip* chip);
|
||||
int32_t blisp_device_open(struct blisp_device* device, const char* port_name);
|
||||
int32_t blisp_device_handshake(struct blisp_device* device, bool in_ef_loader);
|
||||
int32_t blisp_device_get_boot_info(struct blisp_device* device,
|
||||
struct blisp_boot_info* boot_info);
|
||||
int32_t blisp_device_load_boot_header(struct blisp_device* device,
|
||||
uint8_t* boot_header);
|
||||
int32_t blisp_device_load_segment_header(
|
||||
struct blisp_device* device,
|
||||
struct blisp_segment_header* segment_header);
|
||||
int32_t blisp_device_load_segment_data(struct blisp_device* device,
|
||||
uint8_t* segment_data,
|
||||
uint32_t segment_data_length);
|
||||
int32_t blisp_device_get_boot_info(struct blisp_device* device, struct blisp_boot_info* boot_info);
|
||||
int32_t blisp_device_load_boot_header(struct blisp_device* device, uint8_t* boot_header);
|
||||
int32_t blisp_device_load_segment_header(struct blisp_device* device, struct blisp_segment_header* segment_header);
|
||||
int32_t blisp_device_load_segment_data(struct blisp_device* device, uint8_t* segment_data, uint32_t segment_data_length);
|
||||
int32_t blisp_device_write_memory(struct blisp_device* device,
|
||||
uint32_t address,
|
||||
uint32_t value,
|
||||
uint32_t address, uint32_t value,
|
||||
bool wait_for_res);
|
||||
int32_t blisp_device_check_image(struct blisp_device* device);
|
||||
int32_t blisp_device_run_image(struct blisp_device* device);
|
||||
int32_t blisp_device_flash_erase(struct blisp_device* device,
|
||||
uint32_t start_address,
|
||||
uint32_t end_address);
|
||||
int32_t blisp_device_flash_write(struct blisp_device* device,
|
||||
uint32_t start_address,
|
||||
uint8_t* payload,
|
||||
uint32_t payload_size);
|
||||
int32_t blisp_device_flash_erase(struct blisp_device* device, uint32_t start_address, uint32_t end_address);
|
||||
int32_t blisp_device_flash_write(struct blisp_device* device, uint32_t start_address, uint8_t* payload, uint32_t payload_size);
|
||||
int32_t blisp_device_program_check(struct blisp_device* device);
|
||||
int32_t blisp_device_reset(struct blisp_device* device);
|
||||
void blisp_device_close(struct blisp_device* device);
|
||||
|
||||
+10
-16
@@ -1,31 +1,25 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef _BLISP_CHIP_H
|
||||
#define _BLISP_CHIP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
enum blisp_chip_type {
|
||||
BLISP_CHIP_BL60X,
|
||||
BLISP_CHIP_BL70X,
|
||||
BLISP_CHIP_BL606P,
|
||||
BLISP_CHIP_BL808,
|
||||
BLISP_CHIP_BL61X,
|
||||
BLISP_CHIP_BL60X,
|
||||
BLISP_CHIP_BL70X,
|
||||
BLISP_CHIP_BL808
|
||||
};
|
||||
|
||||
struct blisp_chip { // TODO: Move elsewhere?
|
||||
enum blisp_chip_type type;
|
||||
const char* type_str;
|
||||
bool usb_isp_available;
|
||||
float handshake_byte_multiplier;
|
||||
const char* default_xtal; // TODO: Make this selectable
|
||||
int64_t (*load_eflash_loader)(uint8_t clk_type, uint8_t** firmware_buf_ptr);
|
||||
uint32_t tcm_address;
|
||||
struct blisp_chip { // TODO: Move elsewhere?
|
||||
enum blisp_chip_type type;
|
||||
const char* type_str;
|
||||
bool usb_isp_available;
|
||||
float handshake_byte_multiplier;
|
||||
const char* default_eflash_loader_xtal; // TODO: Make this selectable
|
||||
};
|
||||
|
||||
extern struct blisp_chip blisp_chip_bl60x;
|
||||
extern struct blisp_chip blisp_chip_bl70x;
|
||||
extern struct blisp_chip blisp_chip_bl808;
|
||||
extern struct blisp_chip blisp_chip_bl61x;
|
||||
|
||||
#endif
|
||||
@@ -1,54 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef BLISP_BLISP_EASY_H
|
||||
#define BLISP_BLISP_EASY_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "blisp.h"
|
||||
|
||||
struct blisp_easy_transport {
|
||||
uint8_t type; // 0 - memory, 1 - FILE file_handle
|
||||
union {
|
||||
FILE* file_handle;
|
||||
struct {
|
||||
void* data_location;
|
||||
uint32_t data_size;
|
||||
uint32_t current_position;
|
||||
} memory;
|
||||
} data;
|
||||
};
|
||||
|
||||
enum blisp_easy_error {
|
||||
BLISP_EASY_ERR_TRANSPORT_ERROR = -100,
|
||||
BLISP_EASY_ERR_CHECK_IMAGE_FAILED = -101
|
||||
};
|
||||
|
||||
typedef void (*blisp_easy_progress_callback)(uint32_t current_value,
|
||||
uint32_t max_value);
|
||||
|
||||
struct blisp_easy_transport blisp_easy_transport_new_from_file(FILE* file);
|
||||
struct blisp_easy_transport blisp_easy_transport_new_from_memory(
|
||||
void* data_location,
|
||||
uint32_t data_size);
|
||||
|
||||
int32_t blisp_easy_load_segment_data(
|
||||
struct blisp_device* device,
|
||||
uint32_t segment_size,
|
||||
struct blisp_easy_transport* segment_transport,
|
||||
blisp_easy_progress_callback progress_callback);
|
||||
|
||||
int32_t blisp_easy_load_ram_image(
|
||||
struct blisp_device* device,
|
||||
struct blisp_easy_transport* image_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 blisp_easy_flash_write(struct blisp_device* device,
|
||||
struct blisp_easy_transport* data_transport,
|
||||
uint32_t flash_location,
|
||||
uint32_t data_size,
|
||||
blisp_easy_progress_callback progress_callback);
|
||||
|
||||
#endif // BLISP_BLISP_EASY_H
|
||||
+135
-134
@@ -6,166 +6,167 @@
|
||||
#ifndef _LIBBLISP_STRUCT_H
|
||||
#define _LIBBLISP_STRUCT_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct {
|
||||
uint8_t ioMode; /*!< Serail flash interface mode,bit0-3:IF mode,bit4:unwrap */
|
||||
uint8_t cReadSupport; /*!< Support continuous read mode,bit0:continuous read
|
||||
mode support,bit1:read mode cfg */
|
||||
uint8_t clkDelay; /*!< SPI clock delay,bit0-3:delay,bit4-6:pad delay */
|
||||
uint8_t clkInvert; /*!< SPI clock phase invert,bit0:clck invert,bit1:rx
|
||||
invert,bit2-4:pad delay,bit5-7:pad delay */
|
||||
uint8_t resetEnCmd; /*!< Flash enable reset command */
|
||||
uint8_t resetCmd; /*!< Flash reset command */
|
||||
uint8_t resetCreadCmd; /*!< Flash reset continuous read command */
|
||||
uint8_t resetCreadCmdSize; /*!< Flash reset continuous read command size */
|
||||
uint8_t jedecIdCmd; /*!< JEDEC ID command */
|
||||
uint8_t jedecIdCmdDmyClk; /*!< JEDEC ID command dummy clock */
|
||||
uint8_t qpiJedecIdCmd; /*!< QPI JEDEC ID comamnd */
|
||||
uint8_t qpiJedecIdCmdDmyClk; /*!< QPI JEDEC ID command dummy clock */
|
||||
uint8_t sectorSize; /*!< *1024bytes */
|
||||
uint8_t mid; /*!< Manufacturer ID */
|
||||
uint16_t pageSize; /*!< Page size */
|
||||
uint8_t chipEraseCmd; /*!< Chip erase cmd */
|
||||
uint8_t sectorEraseCmd; /*!< Sector erase command */
|
||||
uint8_t blk32EraseCmd; /*!< Block 32K erase command,some Micron not support */
|
||||
uint8_t blk64EraseCmd; /*!< Block 64K erase command */
|
||||
uint8_t writeEnableCmd; /*!< Need before every erase or program */
|
||||
uint8_t pageProgramCmd; /*!< Page program cmd */
|
||||
uint8_t qpageProgramCmd; /*!< QIO page program cmd */
|
||||
uint8_t qppAddrMode; /*!< QIO page program address mode */
|
||||
uint8_t fastReadCmd; /*!< Fast read command */
|
||||
uint8_t frDmyClk; /*!< Fast read command dummy clock */
|
||||
uint8_t qpiFastReadCmd; /*!< QPI fast read command */
|
||||
uint8_t qpiFrDmyClk; /*!< QPI fast read command dummy clock */
|
||||
uint8_t fastReadDoCmd; /*!< Fast read dual output command */
|
||||
uint8_t frDoDmyClk; /*!< Fast read dual output command dummy clock */
|
||||
uint8_t fastReadDioCmd; /*!< Fast read dual io comamnd */
|
||||
uint8_t frDioDmyClk; /*!< Fast read dual io command dummy clock */
|
||||
uint8_t fastReadQoCmd; /*!< Fast read quad output comamnd */
|
||||
uint8_t frQoDmyClk; /*!< Fast read quad output comamnd dummy clock */
|
||||
uint8_t fastReadQioCmd; /*!< Fast read quad io comamnd */
|
||||
uint8_t frQioDmyClk; /*!< Fast read quad io comamnd dummy clock */
|
||||
uint8_t qpiFastReadQioCmd; /*!< QPI fast read quad io comamnd */
|
||||
uint8_t qpiFrQioDmyClk; /*!< QPI fast read QIO dummy clock */
|
||||
uint8_t qpiPageProgramCmd; /*!< QPI program command */
|
||||
uint8_t writeVregEnableCmd; /*!< Enable write reg */
|
||||
uint8_t wrEnableIndex; /*!< Write enable register index */
|
||||
uint8_t qeIndex; /*!< Quad mode enable register index */
|
||||
uint8_t busyIndex; /*!< Busy status register index */
|
||||
uint8_t wrEnableBit; /*!< Write enable bit pos */
|
||||
uint8_t qeBit; /*!< Quad enable bit pos */
|
||||
uint8_t busyBit; /*!< Busy status bit pos */
|
||||
uint8_t wrEnableWriteRegLen; /*!< Register length of write enable */
|
||||
uint8_t wrEnableReadRegLen; /*!< Register length of write enable status */
|
||||
uint8_t qeWriteRegLen; /*!< Register length of contain quad enable */
|
||||
uint8_t qeReadRegLen; /*!< Register length of contain quad enable status */
|
||||
uint8_t releasePowerDown; /*!< Release power down command */
|
||||
uint8_t busyReadRegLen; /*!< Register length of contain busy status */
|
||||
uint8_t readRegCmd[4]; /*!< Read register command buffer */
|
||||
uint8_t writeRegCmd[4]; /*!< Write register command buffer */
|
||||
uint8_t enterQpi; /*!< Enter qpi command */
|
||||
uint8_t exitQpi; /*!< Exit qpi command */
|
||||
uint8_t cReadMode; /*!< Config data for continuous read mode */
|
||||
uint8_t cRExit; /*!< Config data for exit continuous read mode */
|
||||
uint8_t burstWrapCmd; /*!< Enable burst wrap command */
|
||||
uint8_t burstWrapCmdDmyClk; /*!< Enable burst wrap command dummy clock */
|
||||
uint8_t burstWrapDataMode; /*!< Data and address mode for this command */
|
||||
uint8_t burstWrapData; /*!< Data to enable burst wrap */
|
||||
uint8_t deBurstWrapCmd; /*!< Disable burst wrap command */
|
||||
uint8_t deBurstWrapCmdDmyClk; /*!< Disable burst wrap command dummy clock */
|
||||
uint8_t deBurstWrapDataMode; /*!< Data and address mode for this command */
|
||||
uint8_t deBurstWrapData; /*!< Data to disable burst wrap */
|
||||
uint16_t timeEsector; /*!< 4K erase time */
|
||||
uint16_t timeE32k; /*!< 32K erase time */
|
||||
uint16_t timeE64k; /*!< 64K erase time */
|
||||
uint16_t timePagePgm; /*!< Page program time */
|
||||
uint16_t timeCe; /*!< Chip erase time in ms */
|
||||
uint8_t pdDelay; /*!< Release power down command delay time for wake up */
|
||||
uint8_t qeData; /*!< QE set data */
|
||||
uint8_t ioMode; /*!< Serail flash interface mode,bit0-3:IF mode,bit4:unwrap */
|
||||
uint8_t cReadSupport; /*!< Support continuous read mode,bit0:continuous read mode support,bit1:read mode cfg */
|
||||
uint8_t clkDelay; /*!< SPI clock delay,bit0-3:delay,bit4-6:pad delay */
|
||||
uint8_t clkInvert; /*!< SPI clock phase invert,bit0:clck invert,bit1:rx invert,bit2-4:pad delay,bit5-7:pad delay */
|
||||
uint8_t resetEnCmd; /*!< Flash enable reset command */
|
||||
uint8_t resetCmd; /*!< Flash reset command */
|
||||
uint8_t resetCreadCmd; /*!< Flash reset continuous read command */
|
||||
uint8_t resetCreadCmdSize; /*!< Flash reset continuous read command size */
|
||||
uint8_t jedecIdCmd; /*!< JEDEC ID command */
|
||||
uint8_t jedecIdCmdDmyClk; /*!< JEDEC ID command dummy clock */
|
||||
uint8_t qpiJedecIdCmd; /*!< QPI JEDEC ID comamnd */
|
||||
uint8_t qpiJedecIdCmdDmyClk; /*!< QPI JEDEC ID command dummy clock */
|
||||
uint8_t sectorSize; /*!< *1024bytes */
|
||||
uint8_t mid; /*!< Manufacturer ID */
|
||||
uint16_t pageSize; /*!< Page size */
|
||||
uint8_t chipEraseCmd; /*!< Chip erase cmd */
|
||||
uint8_t sectorEraseCmd; /*!< Sector erase command */
|
||||
uint8_t blk32EraseCmd; /*!< Block 32K erase command,some Micron not support */
|
||||
uint8_t blk64EraseCmd; /*!< Block 64K erase command */
|
||||
uint8_t writeEnableCmd; /*!< Need before every erase or program */
|
||||
uint8_t pageProgramCmd; /*!< Page program cmd */
|
||||
uint8_t qpageProgramCmd; /*!< QIO page program cmd */
|
||||
uint8_t qppAddrMode; /*!< QIO page program address mode */
|
||||
uint8_t fastReadCmd; /*!< Fast read command */
|
||||
uint8_t frDmyClk; /*!< Fast read command dummy clock */
|
||||
uint8_t qpiFastReadCmd; /*!< QPI fast read command */
|
||||
uint8_t qpiFrDmyClk; /*!< QPI fast read command dummy clock */
|
||||
uint8_t fastReadDoCmd; /*!< Fast read dual output command */
|
||||
uint8_t frDoDmyClk; /*!< Fast read dual output command dummy clock */
|
||||
uint8_t fastReadDioCmd; /*!< Fast read dual io comamnd */
|
||||
uint8_t frDioDmyClk; /*!< Fast read dual io command dummy clock */
|
||||
uint8_t fastReadQoCmd; /*!< Fast read quad output comamnd */
|
||||
uint8_t frQoDmyClk; /*!< Fast read quad output comamnd dummy clock */
|
||||
uint8_t fastReadQioCmd; /*!< Fast read quad io comamnd */
|
||||
uint8_t frQioDmyClk; /*!< Fast read quad io comamnd dummy clock */
|
||||
uint8_t qpiFastReadQioCmd; /*!< QPI fast read quad io comamnd */
|
||||
uint8_t qpiFrQioDmyClk; /*!< QPI fast read QIO dummy clock */
|
||||
uint8_t qpiPageProgramCmd; /*!< QPI program command */
|
||||
uint8_t writeVregEnableCmd; /*!< Enable write reg */
|
||||
uint8_t wrEnableIndex; /*!< Write enable register index */
|
||||
uint8_t qeIndex; /*!< Quad mode enable register index */
|
||||
uint8_t busyIndex; /*!< Busy status register index */
|
||||
uint8_t wrEnableBit; /*!< Write enable bit pos */
|
||||
uint8_t qeBit; /*!< Quad enable bit pos */
|
||||
uint8_t busyBit; /*!< Busy status bit pos */
|
||||
uint8_t wrEnableWriteRegLen; /*!< Register length of write enable */
|
||||
uint8_t wrEnableReadRegLen; /*!< Register length of write enable status */
|
||||
uint8_t qeWriteRegLen; /*!< Register length of contain quad enable */
|
||||
uint8_t qeReadRegLen; /*!< Register length of contain quad enable status */
|
||||
uint8_t releasePowerDown; /*!< Release power down command */
|
||||
uint8_t busyReadRegLen; /*!< Register length of contain busy status */
|
||||
uint8_t readRegCmd[4]; /*!< Read register command buffer */
|
||||
uint8_t writeRegCmd[4]; /*!< Write register command buffer */
|
||||
uint8_t enterQpi; /*!< Enter qpi command */
|
||||
uint8_t exitQpi; /*!< Exit qpi command */
|
||||
uint8_t cReadMode; /*!< Config data for continuous read mode */
|
||||
uint8_t cRExit; /*!< Config data for exit continuous read mode */
|
||||
uint8_t burstWrapCmd; /*!< Enable burst wrap command */
|
||||
uint8_t burstWrapCmdDmyClk; /*!< Enable burst wrap command dummy clock */
|
||||
uint8_t burstWrapDataMode; /*!< Data and address mode for this command */
|
||||
uint8_t burstWrapData; /*!< Data to enable burst wrap */
|
||||
uint8_t deBurstWrapCmd; /*!< Disable burst wrap command */
|
||||
uint8_t deBurstWrapCmdDmyClk; /*!< Disable burst wrap command dummy clock */
|
||||
uint8_t deBurstWrapDataMode; /*!< Data and address mode for this command */
|
||||
uint8_t deBurstWrapData; /*!< Data to disable burst wrap */
|
||||
uint16_t timeEsector; /*!< 4K erase time */
|
||||
uint16_t timeE32k; /*!< 32K erase time */
|
||||
uint16_t timeE64k; /*!< 64K erase time */
|
||||
uint16_t timePagePgm; /*!< Page program time */
|
||||
uint16_t timeCe; /*!< Chip erase time in ms */
|
||||
uint8_t pdDelay; /*!< Release power down command delay time for wake up */
|
||||
uint8_t qeData; /*!< QE set data */
|
||||
} SPI_Flash_Cfg_Type;
|
||||
|
||||
#define BFLB_BOOTROM_HASH_SIZE 256 / 8
|
||||
|
||||
struct boot_flash_cfg_t {
|
||||
char magiccode[4]; /*'FCFG'*/
|
||||
SPI_Flash_Cfg_Type cfg;
|
||||
uint32_t crc32;
|
||||
struct boot_flash_cfg_t
|
||||
{
|
||||
char magiccode[4]; /*'FCFG'*/
|
||||
SPI_Flash_Cfg_Type cfg;
|
||||
uint32_t crc32;
|
||||
};
|
||||
|
||||
struct sys_clk_cfg_t {
|
||||
uint8_t xtal_type;
|
||||
uint8_t pll_clk;
|
||||
uint8_t hclk_div;
|
||||
uint8_t bclk_div;
|
||||
struct sys_clk_cfg_t
|
||||
{
|
||||
uint8_t xtal_type;
|
||||
uint8_t pll_clk;
|
||||
uint8_t hclk_div;
|
||||
uint8_t bclk_div;
|
||||
|
||||
uint8_t flash_clk_type;
|
||||
uint8_t flash_clk_div;
|
||||
uint8_t rsvd[2];
|
||||
uint8_t flash_clk_type;
|
||||
uint8_t flash_clk_div;
|
||||
uint8_t rsvd[2];
|
||||
};
|
||||
|
||||
struct boot_clk_cfg_t {
|
||||
char magiccode[4]; /*'PCFG'*/
|
||||
struct sys_clk_cfg_t cfg;
|
||||
uint32_t crc32;
|
||||
struct boot_clk_cfg_t
|
||||
{
|
||||
char magiccode[4]; /*'PCFG'*/
|
||||
struct sys_clk_cfg_t cfg;
|
||||
uint32_t crc32;
|
||||
};
|
||||
|
||||
struct bfl_boot_header {
|
||||
char magiccode[4]; /*'BFXP'*/
|
||||
uint32_t revison;
|
||||
struct boot_flash_cfg_t flashCfg;
|
||||
struct boot_clk_cfg_t clkCfg;
|
||||
union {
|
||||
struct {
|
||||
uint32_t sign : 2; /* [1: 0] for sign*/
|
||||
uint32_t encrypt_type : 2; /* [3: 2] for encrypt */
|
||||
uint32_t key_sel : 2; /* [5: 4] for key sel in boot interface*/
|
||||
uint32_t rsvd6_7 : 2; /* [7: 6] for encrypt*/
|
||||
uint32_t no_segment : 1; /* [8] no segment info */
|
||||
uint32_t cache_enable : 1; /* [9] for cache */
|
||||
uint32_t
|
||||
notload_in_bootrom : 1; /* [10] not load this img in bootrom */
|
||||
uint32_t aes_region_lock : 1; /* [11] aes region lock */
|
||||
uint32_t cache_way_disable : 4; /* [15: 12] cache way disable info*/
|
||||
uint32_t crc_ignore : 1; /* [16] ignore crc */
|
||||
uint32_t hash_ignore : 1; /* [17] hash crc */
|
||||
uint32_t halt_ap : 1; /* [18] halt ap */
|
||||
uint32_t rsvd19_31 : 13; /* [31:19] rsvd */
|
||||
} bval;
|
||||
uint32_t wval;
|
||||
} bootcfg;
|
||||
struct bfl_boot_header
|
||||
{
|
||||
char magiccode[4]; /*'BFXP'*/
|
||||
uint32_t revison;
|
||||
struct boot_flash_cfg_t flashCfg;
|
||||
struct boot_clk_cfg_t clkCfg;
|
||||
union {
|
||||
struct {
|
||||
uint32_t sign : 2; /* [1: 0] for sign*/
|
||||
uint32_t encrypt_type : 2; /* [3: 2] for encrypt */
|
||||
uint32_t key_sel : 2; /* [5: 4] for key sel in boot interface*/
|
||||
uint32_t rsvd6_7 : 2; /* [7: 6] for encrypt*/
|
||||
uint32_t no_segment : 1; /* [8] no segment info */
|
||||
uint32_t cache_enable : 1; /* [9] for cache */
|
||||
uint32_t notload_in_bootrom : 1; /* [10] not load this img in bootrom */
|
||||
uint32_t aes_region_lock : 1; /* [11] aes region lock */
|
||||
uint32_t cache_way_disable : 4; /* [15: 12] cache way disable info*/
|
||||
uint32_t crc_ignore : 1; /* [16] ignore crc */
|
||||
uint32_t hash_ignore : 1; /* [17] hash crc */
|
||||
uint32_t halt_ap : 1; /* [18] halt ap */
|
||||
uint32_t rsvd19_31 : 13; /* [31:19] rsvd */
|
||||
} bval;
|
||||
uint32_t wval;
|
||||
}bootcfg ;
|
||||
|
||||
union {
|
||||
uint32_t segment_cnt;
|
||||
uint32_t img_length;
|
||||
} segment_info;
|
||||
union {
|
||||
uint32_t segment_cnt;
|
||||
uint32_t img_length;
|
||||
}segment_info;
|
||||
|
||||
uint32_t bootentry; /* entry point of the image*/
|
||||
uint32_t bootentry; /* entry point of the image*/
|
||||
|
||||
uint32_t flashoffset;
|
||||
uint32_t flashoffset;
|
||||
|
||||
uint8_t hash[BFLB_BOOTROM_HASH_SIZE]; /*hash of the image*/
|
||||
uint8_t hash[BFLB_BOOTROM_HASH_SIZE]; /*hash of the image*/
|
||||
|
||||
uint32_t rsv1;
|
||||
uint32_t rsv2;
|
||||
uint32_t crc32;
|
||||
uint32_t rsv1;
|
||||
uint32_t rsv2;
|
||||
uint32_t crc32;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct bfl_boot_header) == 176,
|
||||
"Bootheader have wrong size");
|
||||
static_assert(sizeof(struct bfl_boot_header) == 176, "Bootheader have wrong size");
|
||||
|
||||
struct blflash_segment_header {
|
||||
uint32_t destaddr;
|
||||
uint32_t len;
|
||||
uint32_t rsvd;
|
||||
uint32_t crc32;
|
||||
struct blflash_segment_header
|
||||
{
|
||||
uint32_t destaddr;
|
||||
uint32_t len;
|
||||
uint32_t rsvd;
|
||||
uint32_t crc32;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct blflash_segment_header) == 16,
|
||||
"Segment header have wrong size");
|
||||
static_assert(sizeof(struct blflash_segment_header) == 16, "Segment header have wrong size");
|
||||
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
+6
-83
@@ -1,98 +1,21 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef _BLISP_UTIL_H
|
||||
#define _BLISP_UTIL_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
static void blisp_dlog(const char* format, ...)
|
||||
{
|
||||
fflush(stdout);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
|
||||
static void sleep_ms(int milliseconds) {
|
||||
static void sleep_ms(int milliseconds){
|
||||
#ifdef WIN32
|
||||
Sleep(milliseconds);
|
||||
Sleep(milliseconds);
|
||||
#else
|
||||
struct timespec ts;
|
||||
ts.tv_sec = milliseconds / 1000;
|
||||
ts.tv_nsec = (milliseconds % 1000) * 1000000;
|
||||
nanosleep(&ts, NULL);
|
||||
struct timespec ts;
|
||||
ts.tv_sec = milliseconds / 1000;
|
||||
ts.tv_nsec = (milliseconds % 1000) * 1000000;
|
||||
nanosleep(&ts, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* * Generated on Mon Jan 9 19:56:36 2023
|
||||
* by pycrc vunknown, https://pycrc.org
|
||||
* using the configuration:
|
||||
* - Width = 32
|
||||
* - Poly = 0x04c11db7
|
||||
* - XorIn = 0xffffffff
|
||||
* - ReflectIn = True
|
||||
* - XorOut = 0xffffffff
|
||||
* - ReflectOut = True
|
||||
* - Algorithm = table-driven
|
||||
*/
|
||||
|
||||
static const uint32_t crc_table[256] = {
|
||||
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
|
||||
};
|
||||
|
||||
static uint32_t crc32_calculate(const void *data, size_t data_len)
|
||||
{
|
||||
uint32_t crc = 0xffffffff;
|
||||
const unsigned char *d = (const unsigned char *)data;
|
||||
unsigned int tbl_idx;
|
||||
|
||||
while (data_len--) {
|
||||
tbl_idx = (crc ^ *d) & 0xff;
|
||||
crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff;
|
||||
d++;
|
||||
}
|
||||
return (crc & 0xffffffff) ^ 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,30 +0,0 @@
|
||||
#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
|
||||
+287
-357
@@ -1,417 +1,347 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <blisp.h>
|
||||
#include <blisp_util.h>
|
||||
#include <libserialport.h>
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/serial.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#include <blisp_util.h>
|
||||
|
||||
#define DEBUG
|
||||
|
||||
static void drain(struct sp_port* port) {
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
sp_drain(port);
|
||||
#endif
|
||||
int32_t blisp_device_init(struct blisp_device* device, struct blisp_chip* chip)
|
||||
{
|
||||
device->chip = chip;
|
||||
device->is_usb = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
blisp_return_t blisp_device_init(struct blisp_device* device,
|
||||
struct blisp_chip* chip) {
|
||||
device->chip = chip;
|
||||
device->is_usb = false;
|
||||
return BLISP_OK;
|
||||
}
|
||||
int32_t blisp_device_open(struct blisp_device* device, const char* port_name)
|
||||
{
|
||||
int ret;
|
||||
struct sp_port* serial_port = NULL;
|
||||
|
||||
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) {
|
||||
ret = sp_get_port_by_name(port_name, &serial_port);
|
||||
if (ret != SP_OK) {
|
||||
blisp_dlog("Couldn't open device, err: %d", ret);
|
||||
return BLISP_ERR_CANT_OPEN_DEVICE;
|
||||
}
|
||||
} else {
|
||||
if (!device->chip->usb_isp_available) {
|
||||
return BLISP_ERR_NO_AUTO_FIND_AVAILABLE;
|
||||
}
|
||||
struct sp_port** port_list;
|
||||
ret = sp_list_ports(&port_list);
|
||||
if (ret != SP_OK) {
|
||||
blisp_dlog("Couldn't list ports, err: %d", ret);
|
||||
return BLISP_ERR_DEVICE_NOT_FOUND;
|
||||
}
|
||||
for (int i = 0; port_list[i] != NULL; i++) {
|
||||
struct sp_port* port = port_list[i];
|
||||
|
||||
int vid, pid;
|
||||
sp_get_port_usb_vid_pid(port, &vid, &pid);
|
||||
if (vid == 0xFFFF && pid == 0xFFFF) {
|
||||
ret = sp_get_port_by_name(sp_get_port_name(port), &serial_port);
|
||||
if (port_name != NULL) {
|
||||
ret = sp_get_port_by_name(port_name, &serial_port);
|
||||
if (ret != SP_OK) {
|
||||
blisp_dlog("Couldn't open device, err: %d", ret);
|
||||
return BLISP_ERR_CANT_OPEN_DEVICE;
|
||||
return -1; // TODO: Improve error codes
|
||||
}
|
||||
} else {
|
||||
if (!device->chip->usb_isp_available) {
|
||||
return -2; // Can't auto-find device due it doesn't have native USB
|
||||
}
|
||||
struct sp_port **port_list;
|
||||
ret = sp_list_ports(&port_list);
|
||||
if (ret != SP_OK) {
|
||||
return -1; // TODO: Improve error codes
|
||||
}
|
||||
for (int i = 0; port_list[i] != NULL; i++) {
|
||||
struct sp_port *port = port_list[i];
|
||||
|
||||
int vid, pid;
|
||||
sp_get_port_usb_vid_pid(port, &vid, &pid);
|
||||
if (vid == 0xFFFF && pid == 0xFFFF) {
|
||||
ret = sp_get_port_by_name(sp_get_port_name(port), &serial_port);
|
||||
if (ret != SP_OK) {
|
||||
return -1; // TODO: Improve error codes
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
sp_free_port_list(port_list);
|
||||
if (serial_port == NULL) {
|
||||
return -3; // Device not found
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
sp_free_port_list(port_list);
|
||||
if (serial_port == NULL) {
|
||||
return BLISP_ERR_DEVICE_NOT_FOUND;
|
||||
|
||||
ret = sp_open(serial_port, SP_MODE_READ_WRITE);
|
||||
if (ret != SP_OK) { // TODO: Handle not found
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
sp_set_bits(serial_port, 8);
|
||||
sp_set_parity(serial_port, SP_PARITY_NONE);
|
||||
sp_set_stopbits(serial_port, 1);
|
||||
sp_set_flowcontrol(serial_port, SP_FLOWCONTROL_NONE);
|
||||
|
||||
ret = sp_open(serial_port, SP_MODE_READ_WRITE);
|
||||
if (ret != SP_OK) {
|
||||
blisp_dlog("SP open failed: %d", ret);
|
||||
return BLISP_ERR_CANT_OPEN_DEVICE;
|
||||
}
|
||||
// TODO: Handle errors in following functions, although, none of them *should*
|
||||
// fail
|
||||
sp_set_bits(serial_port, 8);
|
||||
sp_set_parity(serial_port, SP_PARITY_NONE);
|
||||
sp_set_stopbits(serial_port, 1);
|
||||
sp_set_flowcontrol(serial_port, SP_FLOWCONTROL_NONE);
|
||||
uint32_t 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;
|
||||
// }
|
||||
sp_set_baudrate(serial_port, device->current_baud_rate);
|
||||
device->serial_port = serial_port;
|
||||
|
||||
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 = 460800;
|
||||
// }
|
||||
|
||||
#if 0
|
||||
int fd;
|
||||
sp_get_port_handle(serial_port, &fd);
|
||||
struct serial_struct serial;
|
||||
ioctl(fd, TIOCGSERIAL, &serial);
|
||||
// serial.flags &= ~(ASYNC_LOW_LATENCY);
|
||||
serial.flags |= ASYNC_LOW_LATENCY;
|
||||
ioctl(fd, TIOCSSERIAL, &serial);
|
||||
#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_API_ERROR;
|
||||
}
|
||||
device->serial_port = serial_port;
|
||||
|
||||
return BLISP_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
int32_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;
|
||||
|
||||
device->tx_buffer[0] = command;
|
||||
device->tx_buffer[1] = 0;
|
||||
device->tx_buffer[2] = payload_size & 0xFF;
|
||||
device->tx_buffer[3] = (payload_size >> 8) & 0xFF;
|
||||
if (add_checksum) {
|
||||
uint32_t checksum = 0;
|
||||
checksum += device->tx_buffer[2] + device->tx_buffer[3];
|
||||
for (uint16_t i = 0; i < payload_size; i++) {
|
||||
checksum += *(uint8_t*)((uint8_t*)payload + i);
|
||||
device->tx_buffer[0] = command;
|
||||
device->tx_buffer[1] = 0;
|
||||
device->tx_buffer[2] = payload_size & 0xFF;
|
||||
device->tx_buffer[3] = (payload_size >> 8) & 0xFF;
|
||||
if (add_checksum) {
|
||||
uint32_t checksum = 0;
|
||||
checksum += device->tx_buffer[2] + device->tx_buffer[3];
|
||||
for (uint16_t i = 0; i < payload_size; i++) {
|
||||
checksum += *(uint8_t*)((uint8_t*)payload + i);
|
||||
}
|
||||
device->tx_buffer[1] = checksum & 0xFF;
|
||||
}
|
||||
device->tx_buffer[1] = checksum & 0xFF;
|
||||
}
|
||||
if (payload_size != 0) {
|
||||
memcpy(&device->tx_buffer[4], payload, payload_size);
|
||||
}
|
||||
ret =
|
||||
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_API_ERROR;
|
||||
}
|
||||
drain(serial_port);
|
||||
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
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_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,
|
||||
100); // TODO: Check if really we received the data.
|
||||
uint16_t data_length =
|
||||
(device->rx_buffer[3] << 8) | (device->rx_buffer[2]);
|
||||
sp_blocking_read(serial_port, &device->rx_buffer[0], data_length, 100);
|
||||
return data_length;
|
||||
if (payload_size != 0) {
|
||||
memcpy(&device->tx_buffer[4], payload, payload_size);
|
||||
}
|
||||
ret = sp_blocking_write(serial_port, device->tx_buffer, 4 + payload_size, 1000);
|
||||
if (ret != (4 + payload_size)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
} else if (device->rx_buffer[0] == 'P' && device->rx_buffer[1] == 'D') {
|
||||
return BLISP_ERR_PENDING; // TODO: This might be rather positive return
|
||||
// number?
|
||||
} else if (device->rx_buffer[0] == 'F' && device->rx_buffer[1] == 'L') {
|
||||
sp_blocking_read(serial_port, &device->rx_buffer[2], 2, 100);
|
||||
device->error_code = (device->rx_buffer[3] << 8) | (device->rx_buffer[2]);
|
||||
blisp_dlog("Chip returned error: %d", device->error_code);
|
||||
return BLISP_ERR_CHIP_ERR;
|
||||
}
|
||||
blisp_dlog("Failed to receive any response (err: %d, %d - %d)", ret,
|
||||
device->rx_buffer[0], device->rx_buffer[1]);
|
||||
return BLISP_ERR_NO_RESPONSE;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (!in_ef_loader && !device->is_usb) {
|
||||
sp_set_rts(serial_port, SP_RTS_ON);
|
||||
sp_set_dtr(serial_port, SP_DTR_ON);
|
||||
sleep_ms(50);
|
||||
sp_set_dtr(serial_port, SP_DTR_OFF);
|
||||
sleep_ms(100);
|
||||
sp_set_rts(serial_port, SP_RTS_OFF);
|
||||
sleep_ms(50); // Wait a bit so BootROM can init
|
||||
}
|
||||
|
||||
uint32_t bytes_count = device->chip->handshake_byte_multiplier *
|
||||
(float)device->current_baud_rate / 10.0f;
|
||||
if (bytes_count > 600)
|
||||
bytes_count = 600;
|
||||
memset(handshake_buffer, 'U', bytes_count);
|
||||
|
||||
for (uint8_t i = 0; i < 5; i++) {
|
||||
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_API_ERROR;
|
||||
int32_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, 500);
|
||||
if (ret < 2) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Failed to receive response. (ret = %d)\n", ret);
|
||||
#endif
|
||||
return -1; // TODO: Terrible
|
||||
} 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, 100); // TODO: Check if really we received the data.
|
||||
uint16_t data_length = (device->rx_buffer[3] << 8) | (device->rx_buffer[2]);
|
||||
sp_blocking_read(serial_port, &device->rx_buffer[0], data_length, 100);
|
||||
return data_length;
|
||||
}
|
||||
return 0;
|
||||
} else if (device->rx_buffer[0] == 'P' && device->rx_buffer[1] == 'D') {
|
||||
return -3; // TODO: Terrible
|
||||
} else if (device->rx_buffer[0] == 'F' && device->rx_buffer[1] == 'L') {
|
||||
sp_blocking_read(serial_port, &device->rx_buffer[2], 2, 100);
|
||||
device->error_code = (device->rx_buffer[3] << 8) | (device->rx_buffer[2]);
|
||||
return -4; // Failed
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Receive response failed... (err: %d, %d - %d)\n", ret, device->rx_buffer[0], device->rx_buffer[1]);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_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;
|
||||
|
||||
if (!in_ef_loader && !device->is_usb) {
|
||||
sp_drain(serial_port); // Wait for write to send all data
|
||||
sp_flush(serial_port, SP_BUF_INPUT); // Flush garbage out of RX
|
||||
sp_set_rts(serial_port, SP_RTS_ON);
|
||||
sp_set_dtr(serial_port, SP_DTR_ON);
|
||||
sleep_ms(50);
|
||||
sp_set_dtr(serial_port, SP_DTR_OFF);
|
||||
sleep_ms(100);
|
||||
sp_set_rts(serial_port, SP_RTS_OFF);
|
||||
}
|
||||
|
||||
ret = sp_blocking_read(serial_port, device->rx_buffer, 2, 50);
|
||||
if (ret >= 2) {
|
||||
if (device->rx_buffer[0] == 'O' && device->rx_buffer[1] == 'K') {
|
||||
return BLISP_OK;
|
||||
}
|
||||
uint32_t bytes_count = device->chip->handshake_byte_multiplier * (float)device->current_baud_rate / 10.0f;
|
||||
if (bytes_count > 600) bytes_count = 600;
|
||||
memset(handshake_buffer, 'U', bytes_count);
|
||||
|
||||
// sp_flush(serial_port, SP_BUF_BOTH);
|
||||
|
||||
for (uint8_t i = 0; i < 5; i++) {
|
||||
if (!in_ef_loader) {
|
||||
if (device->is_usb) {
|
||||
sp_blocking_write(serial_port, "BOUFFALOLAB5555RESET\0\0", 22,
|
||||
100); // TODO: Error handling
|
||||
}
|
||||
}
|
||||
ret = sp_blocking_write(serial_port, handshake_buffer, bytes_count,
|
||||
500);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (device->chip->type == BLISP_CHIP_BL808) {
|
||||
sleep_ms(300);
|
||||
const uint8_t second_handshake[] = { 0x50, 0x00, 0x08, 0x00, 0x38, 0xF0, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18 };
|
||||
sp_blocking_write(serial_port, second_handshake, sizeof(second_handshake), 300); // TODO: Error handling
|
||||
}
|
||||
ret = sp_blocking_read(serial_port, device->rx_buffer, 20, 50);
|
||||
if (ret >= 2) {
|
||||
for (uint8_t j = 0; j < (ret - 1); j++) {
|
||||
if (device->rx_buffer[j] == 'O' && device->rx_buffer[j + 1] == 'K') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
blisp_dlog("Received no response from chip.");
|
||||
return BLISP_ERR_NO_RESPONSE;
|
||||
return -4; // didn't received response
|
||||
}
|
||||
|
||||
blisp_return_t blisp_device_get_boot_info(struct blisp_device* device,
|
||||
struct blisp_boot_info* boot_info) {
|
||||
blisp_return_t ret;
|
||||
int32_t blisp_device_get_boot_info(struct blisp_device* device, struct blisp_boot_info* boot_info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = blisp_send_command(device, 0x10, NULL, 0, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = blisp_send_command(device, 0x10, NULL, 0, false);
|
||||
if (ret < 0) return ret;
|
||||
|
||||
ret = blisp_receive_response(device, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = blisp_receive_response(device, true);
|
||||
if (ret < 0) return ret;
|
||||
|
||||
memcpy(boot_info->boot_rom_version, &device->rx_buffer[0],
|
||||
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);
|
||||
}
|
||||
// TODO: BL60X
|
||||
return BLISP_OK;
|
||||
memcpy(boot_info->boot_rom_version, &device->rx_buffer[0], 4); // TODO: Endianess
|
||||
if (device->chip->type == BLISP_CHIP_BL70X || device->chip->type == BLISP_CHIP_BL808) { // TODO: This is only 70X related
|
||||
memcpy(boot_info->chip_id, &device->rx_buffer[16], 8);
|
||||
}
|
||||
// TODO: BL60X, BL808
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: Use struct instead of uint8_t*
|
||||
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;
|
||||
ret = blisp_receive_response(device, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
blisp_return_t blisp_device_load_segment_header(
|
||||
struct blisp_device* device,
|
||||
struct blisp_segment_header* segment_header) {
|
||||
blisp_return_t ret;
|
||||
ret = blisp_send_command(device, 0x17, segment_header, 16, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = blisp_receive_response(device, true); // TODO: Handle response
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
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)
|
||||
return ret;
|
||||
ret = blisp_receive_response(device, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
ret = blisp_receive_response(device, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
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
|
||||
ret = blisp_send_command(device, 0x50, payload, 8, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (wait_for_res) {
|
||||
int32_t blisp_device_load_boot_header(struct blisp_device* device, uint8_t* boot_header)
|
||||
{
|
||||
int ret;
|
||||
ret = blisp_send_command(device, 0x11, boot_header, 176, false);
|
||||
if (ret < 0) return ret;
|
||||
ret = blisp_receive_response(device, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0) return ret;
|
||||
|
||||
return BLISP_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
blisp_return_t blisp_device_run_image(struct blisp_device* device) {
|
||||
blisp_return_t ret;
|
||||
int32_t blisp_device_load_segment_header(struct blisp_device* device, struct blisp_segment_header* segment_header)
|
||||
{
|
||||
int ret;
|
||||
ret = blisp_send_command(device, 0x17, segment_header, 16, false);
|
||||
if (ret < 0) return ret;
|
||||
ret = blisp_receive_response(device, true); // TODO: Handle response
|
||||
if (ret < 0) return ret;
|
||||
|
||||
if (device->chip->type == BLISP_CHIP_BL70X) { // ERRATA
|
||||
ret = blisp_device_write_memory(device, 0x4000F100, 0x4E424845, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = blisp_device_write_memory(device, 0x4000F104, 0x22010000, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
// ret = blisp_device_write_memory(device, 0x40000018, 0x00000000);
|
||||
// if (ret < 0) return ret;
|
||||
ret = blisp_device_write_memory(device, 0x40000018, 0x00000002, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
ret = blisp_send_command(device, 0x1A, NULL, 0, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = blisp_receive_response(device, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return BLISP_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
blisp_return_t ret = blisp_send_command(device, 0x30, payload, 8, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
do {
|
||||
int32_t blisp_device_load_segment_data(struct blisp_device* device, uint8_t* segment_data, uint32_t segment_data_length)
|
||||
{
|
||||
int ret;
|
||||
ret = blisp_send_command(device, 0x18, segment_data, segment_data_length, false);
|
||||
if (ret < 0) return ret;
|
||||
ret = blisp_receive_response(device, false);
|
||||
} while (ret == BLISP_ERR_PENDING);
|
||||
if (ret < 0) return ret;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
int32_t blisp_device_check_image(struct blisp_device* device)
|
||||
{
|
||||
int ret;
|
||||
ret = blisp_send_command(device, 0x19, NULL, 0, false);
|
||||
if (ret < 0) return ret;
|
||||
ret = blisp_receive_response(device, false);
|
||||
if (ret < 0) return ret;
|
||||
|
||||
uint8_t* buffer = malloc(4 + payload_size);
|
||||
*((uint32_t*)(buffer)) = start_address;
|
||||
memcpy(buffer + 4, payload, payload_size);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
blisp_device_write_memory(struct blisp_device* device, uint32_t address,
|
||||
uint32_t value, bool wait_for_res) {
|
||||
int ret;
|
||||
uint8_t payload[8];
|
||||
*(uint32_t*)(payload) = address;
|
||||
*(uint32_t*)(payload + 4) = value; // TODO: Endianness
|
||||
ret = blisp_send_command(device, 0x50, payload, 8, true);
|
||||
if (ret < 0) return ret;
|
||||
if (wait_for_res) {
|
||||
ret = blisp_receive_response(device, false);
|
||||
if (ret < 0) return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t blisp_device_run_image(struct blisp_device* device)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (device->chip->type == BLISP_CHIP_BL70X) { // ERRATA
|
||||
ret = blisp_device_write_memory(device, 0x4000F100, 0x4E424845, true);
|
||||
if (ret < 0) return ret;
|
||||
ret = blisp_device_write_memory(device, 0x4000F104, 0x22010000, true);
|
||||
if (ret < 0) return ret;
|
||||
// ret = blisp_device_write_memory(device, 0x40000018, 0x00000000);
|
||||
// if (ret < 0) return ret;
|
||||
ret = blisp_device_write_memory(device, 0x40000018, 0x00000002, false);
|
||||
if (ret < 0) return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = blisp_send_command(device, 0x1A, NULL, 0, false);
|
||||
if (ret < 0) return ret;
|
||||
ret = blisp_receive_response(device, false);
|
||||
if (ret < 0) return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_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);
|
||||
if (ret < 0) return ret;
|
||||
do {
|
||||
ret = blisp_receive_response(device, false);
|
||||
} while (ret == -3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_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?)
|
||||
|
||||
uint8_t* buffer = malloc(4 + payload_size); // TODO: Don't use malloc + add check
|
||||
*((uint32_t*)(buffer)) = start_address;
|
||||
memcpy(buffer + 4, payload, payload_size);
|
||||
int ret = blisp_send_command(device, 0x31, buffer, payload_size + 4, true);
|
||||
if (ret < 0) goto exit1;
|
||||
ret = blisp_receive_response(device, false);
|
||||
exit1:
|
||||
free(buffer);
|
||||
return ret;
|
||||
free(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
ret = blisp_receive_response(device, false);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
int32_t blisp_device_program_check(struct blisp_device* device)
|
||||
{
|
||||
int ret = blisp_send_command(device, 0x3A, NULL, 0, true);
|
||||
if (ret < 0) return ret;
|
||||
ret = blisp_receive_response(device, false);
|
||||
if (ret < 0) return ret;
|
||||
|
||||
return BLISP_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
int32_t blisp_device_reset(struct blisp_device* device)
|
||||
{
|
||||
int ret = blisp_send_command(device, 0x21, NULL, 0, true);
|
||||
if (ret < 0) return ret;
|
||||
ret = blisp_receive_response(device, false);
|
||||
if (ret < 0) return ret;
|
||||
|
||||
return BLISP_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void blisp_device_close(struct blisp_device* device) {
|
||||
struct sp_port* serial_port = device->serial_port;
|
||||
sp_close(serial_port);
|
||||
void blisp_device_close(struct blisp_device* device)
|
||||
{
|
||||
struct sp_port* serial_port = device->serial_port;
|
||||
sp_close(serial_port);
|
||||
}
|
||||
@@ -1,373 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "blisp_easy.h"
|
||||
#include "blisp_struct.h"
|
||||
#include "blisp_util.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
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);
|
||||
transport->data.memory.current_position += size;
|
||||
return size;
|
||||
} else {
|
||||
return fread(buffer, size, 1, transport->data.file_handle);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void blisp_easy_report_progress(blisp_easy_progress_callback callback,
|
||||
uint32_t current_value,
|
||||
uint32_t max_value) {
|
||||
if (callback != NULL) {
|
||||
callback(current_value, max_value);
|
||||
}
|
||||
}
|
||||
|
||||
struct blisp_easy_transport blisp_easy_transport_new_from_file(FILE* file) {
|
||||
struct blisp_easy_transport transport = {.type = 1, .data.file_handle = file};
|
||||
return transport;
|
||||
}
|
||||
|
||||
struct blisp_easy_transport blisp_easy_transport_new_from_memory(
|
||||
void* data_location,
|
||||
uint32_t data_size) {
|
||||
struct blisp_easy_transport transport = {
|
||||
.type = 0,
|
||||
.data.memory.data_location = data_location,
|
||||
.data.memory.data_size = data_size,
|
||||
.data.memory.current_position = 0};
|
||||
return transport;
|
||||
}
|
||||
|
||||
int32_t blisp_easy_load_segment_data(
|
||||
struct blisp_device* device,
|
||||
uint32_t segment_size,
|
||||
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 > buffer_max_size) {
|
||||
buffer_size = buffer_max_size;
|
||||
}
|
||||
blisp_easy_transport_read(segment_transport, buffer,
|
||||
buffer_size); // TODO: Error Handling
|
||||
ret = blisp_device_load_segment_data(device, buffer, buffer_size);
|
||||
if (ret < BLISP_OK) {
|
||||
// TODO: Error logging fprintf(stderr, "Failed to load segment data. (ret
|
||||
// %d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
sent_data += buffer_size;
|
||||
blisp_easy_report_progress(progress_callback, sent_data, segment_size);
|
||||
}
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
int32_t blisp_easy_load_ram_image(
|
||||
struct blisp_device* device,
|
||||
struct blisp_easy_transport* image_transport,
|
||||
blisp_easy_progress_callback progress_callback) {
|
||||
int32_t ret;
|
||||
|
||||
struct bfl_boot_header image_boot_header;
|
||||
// TODO: Error handling
|
||||
blisp_easy_transport_read(image_transport, &image_boot_header, 176);
|
||||
|
||||
ret = blisp_device_load_boot_header(device, (uint8_t*)&image_boot_header);
|
||||
if (ret != BLISP_OK) {
|
||||
// TODO: Error printing: fprintf(stderr, "Failed to load boot header.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
{
|
||||
for (uint8_t seg_index = 0;
|
||||
seg_index < image_boot_header.segment_info.segment_cnt; seg_index++) {
|
||||
struct blisp_segment_header segment_header = {0};
|
||||
blisp_easy_transport_read(image_transport, &segment_header,
|
||||
16); // TODO: Error handling
|
||||
|
||||
ret = blisp_device_load_segment_header(device, &segment_header);
|
||||
if (ret != 0) {
|
||||
// TODO: Error printing: fprintf(stderr, "Failed to load segment
|
||||
// header.");
|
||||
return ret;
|
||||
}
|
||||
// TODO: Info printing: printf("Flashing %d. segment\n", seg_index + 1);
|
||||
|
||||
ret = blisp_easy_load_segment_data(device, segment_header.length,
|
||||
image_transport, progress_callback);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = blisp_device_check_image(device);
|
||||
if (ret != BLISP_OK) {
|
||||
// TODO: Error printing: fprintf(stderr, "Failed to check image.\n");
|
||||
return BLISP_EASY_ERR_CHECK_IMAGE_FAILED;
|
||||
}
|
||||
|
||||
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 ret;
|
||||
// TODO: Rework
|
||||
// region boot header fill
|
||||
struct bfl_boot_header boot_header;
|
||||
memcpy(boot_header.magiccode, "BFNP", 4);
|
||||
memcpy(boot_header.flashCfg.magiccode, "FCFG", 4);
|
||||
boot_header.revison = 0x01;
|
||||
boot_header.flashCfg.cfg.ioMode = 0x04;
|
||||
boot_header.flashCfg.cfg.cReadSupport = 0x01;
|
||||
boot_header.flashCfg.cfg.clkDelay = 0x01;
|
||||
boot_header.flashCfg.cfg.clkInvert = 0x01;
|
||||
boot_header.flashCfg.cfg.resetEnCmd = 0x66;
|
||||
boot_header.flashCfg.cfg.resetCmd = 0x99;
|
||||
boot_header.flashCfg.cfg.resetCreadCmd = 0xFF;
|
||||
boot_header.flashCfg.cfg.resetCreadCmdSize = 0x03;
|
||||
boot_header.flashCfg.cfg.jedecIdCmd = 0x9F;
|
||||
boot_header.flashCfg.cfg.jedecIdCmdDmyClk = 0x00;
|
||||
boot_header.flashCfg.cfg.qpiJedecIdCmd = 0x9F;
|
||||
boot_header.flashCfg.cfg.qpiJedecIdCmdDmyClk = 0x00;
|
||||
boot_header.flashCfg.cfg.sectorSize = 0x04;
|
||||
boot_header.flashCfg.cfg.mid = 0xEF;
|
||||
boot_header.flashCfg.cfg.pageSize = 0x100;
|
||||
boot_header.flashCfg.cfg.chipEraseCmd = 0xC7;
|
||||
boot_header.flashCfg.cfg.sectorEraseCmd = 0x20;
|
||||
boot_header.flashCfg.cfg.blk32EraseCmd = 0x52;
|
||||
boot_header.flashCfg.cfg.blk64EraseCmd = 0xD8;
|
||||
boot_header.flashCfg.cfg.writeEnableCmd = 0x06;
|
||||
boot_header.flashCfg.cfg.pageProgramCmd = 0x02;
|
||||
boot_header.flashCfg.cfg.qpageProgramCmd = 0x32;
|
||||
boot_header.flashCfg.cfg.qppAddrMode = 0x00;
|
||||
boot_header.flashCfg.cfg.fastReadCmd = 0x0B;
|
||||
boot_header.flashCfg.cfg.frDmyClk = 0x01;
|
||||
boot_header.flashCfg.cfg.qpiFastReadCmd = 0x0B;
|
||||
boot_header.flashCfg.cfg.qpiFrDmyClk = 0x01;
|
||||
boot_header.flashCfg.cfg.fastReadDoCmd = 0x3B;
|
||||
boot_header.flashCfg.cfg.frDoDmyClk = 0x01;
|
||||
boot_header.flashCfg.cfg.fastReadDioCmd = 0xBB;
|
||||
boot_header.flashCfg.cfg.frDioDmyClk = 0x00;
|
||||
boot_header.flashCfg.cfg.fastReadQoCmd = 0x6B;
|
||||
boot_header.flashCfg.cfg.frQoDmyClk = 0x01;
|
||||
boot_header.flashCfg.cfg.fastReadQioCmd = 0xEB;
|
||||
boot_header.flashCfg.cfg.frQioDmyClk = 0x02;
|
||||
boot_header.flashCfg.cfg.qpiFastReadQioCmd = 0xEB;
|
||||
boot_header.flashCfg.cfg.qpiFrQioDmyClk = 0x02;
|
||||
boot_header.flashCfg.cfg.qpiPageProgramCmd = 0x02;
|
||||
boot_header.flashCfg.cfg.writeVregEnableCmd = 0x50;
|
||||
boot_header.flashCfg.cfg.wrEnableIndex = 0x00;
|
||||
boot_header.flashCfg.cfg.qeIndex = 0x01;
|
||||
boot_header.flashCfg.cfg.busyIndex = 0x00;
|
||||
boot_header.flashCfg.cfg.wrEnableBit = 0x01;
|
||||
boot_header.flashCfg.cfg.qeBit = 0x01;
|
||||
boot_header.flashCfg.cfg.busyBit = 0x00;
|
||||
boot_header.flashCfg.cfg.wrEnableWriteRegLen = 0x02;
|
||||
boot_header.flashCfg.cfg.wrEnableReadRegLen = 0x01;
|
||||
boot_header.flashCfg.cfg.qeWriteRegLen = 0x01;
|
||||
boot_header.flashCfg.cfg.qeReadRegLen = 0x01;
|
||||
boot_header.flashCfg.cfg.releasePowerDown = 0xAB;
|
||||
boot_header.flashCfg.cfg.busyReadRegLen = 0x01;
|
||||
boot_header.flashCfg.cfg.readRegCmd[0] = 0x05;
|
||||
boot_header.flashCfg.cfg.readRegCmd[1] = 0x35;
|
||||
boot_header.flashCfg.cfg.readRegCmd[2] = 0x00;
|
||||
boot_header.flashCfg.cfg.readRegCmd[3] = 0x00;
|
||||
boot_header.flashCfg.cfg.writeRegCmd[0] = 0x01;
|
||||
boot_header.flashCfg.cfg.writeRegCmd[1] = 0x31;
|
||||
boot_header.flashCfg.cfg.writeRegCmd[2] = 0x00;
|
||||
boot_header.flashCfg.cfg.writeRegCmd[3] = 0x00;
|
||||
boot_header.flashCfg.cfg.enterQpi = 0x38;
|
||||
boot_header.flashCfg.cfg.exitQpi = 0xFF;
|
||||
boot_header.flashCfg.cfg.cReadMode = 0x20;
|
||||
boot_header.flashCfg.cfg.cRExit = 0xFF;
|
||||
boot_header.flashCfg.cfg.burstWrapCmd = 0x77;
|
||||
boot_header.flashCfg.cfg.burstWrapCmdDmyClk = 0x03;
|
||||
boot_header.flashCfg.cfg.burstWrapDataMode = 0x02;
|
||||
boot_header.flashCfg.cfg.burstWrapData = 0x40;
|
||||
boot_header.flashCfg.cfg.deBurstWrapCmd = 0x77;
|
||||
boot_header.flashCfg.cfg.deBurstWrapCmdDmyClk = 0x03;
|
||||
boot_header.flashCfg.cfg.deBurstWrapDataMode = 0x02;
|
||||
boot_header.flashCfg.cfg.deBurstWrapData = 0xF0;
|
||||
boot_header.flashCfg.cfg.timeEsector = 0x12C;
|
||||
boot_header.flashCfg.cfg.timeE32k = 0x4B0;
|
||||
boot_header.flashCfg.cfg.timeE64k = 0x4B0;
|
||||
boot_header.flashCfg.cfg.timePagePgm = 0x05;
|
||||
boot_header.flashCfg.cfg.timeCe = 0xD40;
|
||||
boot_header.flashCfg.cfg.pdDelay = 0x03;
|
||||
boot_header.flashCfg.cfg.qeData = 0x00;
|
||||
boot_header.flashCfg.crc32 = 0xC4BDD748;
|
||||
boot_header.clkCfg.cfg.xtal_type = 0x04;
|
||||
boot_header.clkCfg.cfg.pll_clk = 0x04;
|
||||
boot_header.clkCfg.cfg.hclk_div = 0x00;
|
||||
boot_header.clkCfg.cfg.bclk_div = 0x01;
|
||||
boot_header.clkCfg.cfg.flash_clk_type = 0x02;
|
||||
boot_header.clkCfg.cfg.flash_clk_div = 0x00;
|
||||
boot_header.clkCfg.crc32 = 0x824E14BB;
|
||||
boot_header.bootcfg.bval.sign = 0x00;
|
||||
boot_header.bootcfg.bval.encrypt_type = 0x00;
|
||||
boot_header.bootcfg.bval.key_sel = 0x00;
|
||||
boot_header.bootcfg.bval.rsvd6_7 = 0x00;
|
||||
boot_header.bootcfg.bval.no_segment = 0x01;
|
||||
boot_header.bootcfg.bval.cache_enable = 0x01;
|
||||
boot_header.bootcfg.bval.notload_in_bootrom = 0x00;
|
||||
boot_header.bootcfg.bval.aes_region_lock = 0x00;
|
||||
boot_header.bootcfg.bval.cache_way_disable = 0x00;
|
||||
boot_header.bootcfg.bval.crc_ignore = 0x01;
|
||||
boot_header.bootcfg.bval.hash_ignore = 0x01;
|
||||
boot_header.bootcfg.bval.halt_ap = 0x00;
|
||||
boot_header.bootcfg.bval.rsvd19_31 = 0x00;
|
||||
boot_header.segment_info.segment_cnt = 0x01;
|
||||
boot_header.bootentry = 0x00;
|
||||
boot_header.flashoffset = device->chip->tcm_address;
|
||||
boot_header.hash[0x00] = 0xEF;
|
||||
boot_header.hash[0x01] = 0xBE;
|
||||
boot_header.hash[0x02] = 0xAD;
|
||||
boot_header.hash[0x03] = 0xDE;
|
||||
boot_header.hash[0x04] = 0x00;
|
||||
boot_header.hash[0x05] = 0x00;
|
||||
boot_header.hash[0x06] = 0x00;
|
||||
boot_header.hash[0x07] = 0x00;
|
||||
boot_header.hash[0x08] = 0x00;
|
||||
boot_header.hash[0x09] = 0x00;
|
||||
boot_header.hash[0x0a] = 0x00;
|
||||
boot_header.hash[0x0b] = 0x00;
|
||||
boot_header.hash[0x0c] = 0x00;
|
||||
boot_header.hash[0x0d] = 0x00;
|
||||
boot_header.hash[0x0e] = 0x00;
|
||||
boot_header.hash[0x0f] = 0x00;
|
||||
boot_header.hash[0x10] = 0x00;
|
||||
boot_header.hash[0x11] = 0x00;
|
||||
boot_header.hash[0x12] = 0x00;
|
||||
boot_header.hash[0x13] = 0x00;
|
||||
boot_header.hash[0x14] = 0x00;
|
||||
boot_header.hash[0x15] = 0x00;
|
||||
boot_header.hash[0x16] = 0x00;
|
||||
boot_header.hash[0x17] = 0x00;
|
||||
boot_header.hash[0x18] = 0x00;
|
||||
boot_header.hash[0x19] = 0x00;
|
||||
boot_header.hash[0x1a] = 0x00;
|
||||
boot_header.hash[0x1b] = 0x00;
|
||||
boot_header.hash[0x1c] = 0x00;
|
||||
boot_header.hash[0x1d] = 0x00;
|
||||
boot_header.hash[0x1e] = 0x00;
|
||||
boot_header.hash[0x1f] = 0x00;
|
||||
boot_header.rsv1 = 0x00;
|
||||
boot_header.rsv2 = 0x00;
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct blisp_segment_header segment_header = {
|
||||
.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
|
||||
|
||||
ret = blisp_device_load_segment_header(device, &segment_header);
|
||||
if (ret != 0) {
|
||||
blisp_dlog("Failed to load segment header, ret: %d.", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int32_t blisp_easy_flash_write(struct blisp_device* device,
|
||||
struct blisp_easy_transport* data_transport,
|
||||
uint32_t flash_location,
|
||||
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;
|
||||
#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 > buffer_max_size) {
|
||||
buffer_size = buffer_max_size;
|
||||
}
|
||||
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) {
|
||||
fprintf(stderr, "Failed to write firmware! (ret:%d)\n ", ret);
|
||||
return ret;
|
||||
}
|
||||
sent_data += buffer_size;
|
||||
blisp_easy_report_progress(progress_callback, sent_data, data_size);
|
||||
}
|
||||
return BLISP_OK;
|
||||
}
|
||||
@@ -1,24 +1,9 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../../data/bl60x_eflash_loader.h"
|
||||
#include "blisp.h"
|
||||
|
||||
int64_t blisp_chip_bl60x_get_eflash_loader(uint8_t clk_type, uint8_t** firmware_buf_ptr)
|
||||
{
|
||||
uint8_t* firmware_buf = malloc(sizeof(bl60x_eflash_loader_bin));
|
||||
memcpy(firmware_buf, bl60x_eflash_loader_bin, sizeof(bl60x_eflash_loader_bin));
|
||||
*(firmware_buf + 0xE0) = 4; // TODO: 40 MHz clock
|
||||
*firmware_buf_ptr = firmware_buf;
|
||||
return sizeof(bl60x_eflash_loader_bin);
|
||||
}
|
||||
|
||||
struct blisp_chip blisp_chip_bl60x = {
|
||||
.type = BLISP_CHIP_BL60X,
|
||||
.type_str = "bl60x",
|
||||
.usb_isp_available = false,
|
||||
.default_xtal = "40m",
|
||||
.default_eflash_loader_xtal = "40m",
|
||||
.handshake_byte_multiplier = 0.006f,
|
||||
.load_eflash_loader = blisp_chip_bl60x_get_eflash_loader,
|
||||
.tcm_address = 0x22010000
|
||||
};
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "blisp.h"
|
||||
|
||||
struct blisp_chip blisp_chip_bl61x = {
|
||||
.type = BLISP_CHIP_BL61X,
|
||||
.type_str = "bl808",
|
||||
.usb_isp_available = true,
|
||||
.default_xtal = "-", // ?
|
||||
.handshake_byte_multiplier = 0.003f,
|
||||
.get_eflash_loader = NULL
|
||||
};
|
||||
@@ -1,25 +1,9 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../../data/bl70x_eflash_loader.h"
|
||||
#include "blisp.h"
|
||||
|
||||
int64_t blisp_chip_bl70x_get_eflash_loader(uint8_t clk_type, uint8_t** firmware_buf_ptr)
|
||||
{
|
||||
uint8_t* firmware_buf = malloc(sizeof(bl70x_eflash_loader_bin));
|
||||
memcpy(firmware_buf, bl70x_eflash_loader_bin, sizeof(bl70x_eflash_loader_bin));
|
||||
*(firmware_buf + 0xE0) = 1; // TODO: 32 MHz clock
|
||||
*firmware_buf_ptr = firmware_buf;
|
||||
return sizeof(bl70x_eflash_loader_bin);
|
||||
}
|
||||
|
||||
struct blisp_chip blisp_chip_bl70x = {
|
||||
.type = BLISP_CHIP_BL70X,
|
||||
.type_str = "bl70x",
|
||||
.usb_isp_available = true,
|
||||
.default_xtal = "32m",
|
||||
.default_eflash_loader_xtal = "32m",
|
||||
.handshake_byte_multiplier = 0.003f,
|
||||
.load_eflash_loader = blisp_chip_bl70x_get_eflash_loader,
|
||||
.tcm_address = 0x22010000
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "blisp.h"
|
||||
|
||||
struct blisp_chip blisp_chip_bl808 = {
|
||||
.type = BLISP_CHIP_BL808,
|
||||
.type_str = "bl808",
|
||||
.usb_isp_available = true, // TODO: Only for BL808D :-(
|
||||
.default_xtal = "-", // ?
|
||||
.handshake_byte_multiplier = 0.003f,
|
||||
.get_eflash_loader = NULL
|
||||
.usb_isp_available = true,
|
||||
.handshake_byte_multiplier = 0.006f,
|
||||
};
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
(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,32 +1,15 @@
|
||||
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_subdirectory(${CMAKE_SOURCE_DIR}/vendor/argtable3 ${CMAKE_CURRENT_BINARY_DIR}/argtable3)
|
||||
|
||||
add_executable(blisp src/main.c src/cmd/write.c src/util.c src/common.c src/cmd/iot.c)
|
||||
|
||||
add_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()
|
||||
add_executable(blisp src/main.c src/cmd/write.c)
|
||||
|
||||
target_include_directories(blisp PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}/include")
|
||||
"${CMAKE_SOURCE_DIR}/include"
|
||||
"${CMAKE_SOURCE_DIR}/vendor/argtable3/src")
|
||||
|
||||
target_link_libraries(blisp PRIVATE
|
||||
argtable3::argtable3
|
||||
libblisp_static file_parsers)
|
||||
argtable3
|
||||
libblisp_static)
|
||||
|
||||
if (WIN32)
|
||||
if(WIN32)
|
||||
target_link_libraries(blisp PRIVATE Setupapi.lib)
|
||||
elseif (APPLE)
|
||||
target_link_libraries(blisp PRIVATE "-framework IOKit" "-framework CoreFoundation")
|
||||
endif ()
|
||||
|
||||
install(TARGETS blisp DESTINATION bin)
|
||||
endif()
|
||||
+7
-17
@@ -1,26 +1,16 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef BLISP_CMD_H
|
||||
#define BLISP_CMD_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;
|
||||
blisp_return_t (*args_init)();
|
||||
blisp_return_t (*args_parse_exec)(int argc, char** argv);
|
||||
void (*args_print_syntax)();
|
||||
void (*args_free)();
|
||||
const char* name;
|
||||
int8_t (*args_init)();
|
||||
uint8_t (*args_parse_exec)(int argc, char** argv);
|
||||
void (*args_print_syntax)();
|
||||
void (*args_free)();
|
||||
};
|
||||
|
||||
extern struct cmd cmd_write;
|
||||
extern struct cmd cmd_iot;
|
||||
|
||||
#endif // BLISP_CMD_H
|
||||
#endif // BLISP_CMD_H
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
#include <argtable3.h>
|
||||
#include <blisp_easy.h>
|
||||
#include "../cmd.h"
|
||||
#include "../common.h"
|
||||
|
||||
#define REG_EXTENDED 1
|
||||
#define REG_ICASE (REG_EXTENDED << 1)
|
||||
|
||||
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_lit* reset;
|
||||
static struct arg_end* end;
|
||||
static void* cmd_iot_argtable[7];
|
||||
static void cmd_iot_args_print_glossary();
|
||||
|
||||
blisp_return_t blisp_single_download() {
|
||||
struct blisp_device device;
|
||||
blisp_return_t ret;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
FILE* data_file = fopen(single_download->filename[0], "rb");
|
||||
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);
|
||||
int64_t data_file_size = ftell(data_file);
|
||||
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);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to erase.\n");
|
||||
goto exit2;
|
||||
}
|
||||
|
||||
printf("Writing the data...\n");
|
||||
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,
|
||||
blisp_common_progress_callback);
|
||||
if (ret < BLISP_OK) {
|
||||
fprintf(stderr, "Failed to write data to flash.\n");
|
||||
goto exit2;
|
||||
}
|
||||
|
||||
printf("Checking program...\n");
|
||||
ret = blisp_device_program_check(&device);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to check program.\n");
|
||||
goto exit2;
|
||||
}
|
||||
printf("Program OK!\n");
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
exit2:
|
||||
if (data_file != NULL)
|
||||
fclose(data_file);
|
||||
exit1:
|
||||
blisp_device_close(&device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 =
|
||||
arg_str1("c", "chip", "<chip_type>", "Chip Type");
|
||||
cmd_iot_argtable[2] = port_name =
|
||||
arg_str0("p", "port", "<port_name>",
|
||||
"Name/Path to the Serial Port (empty for search)");
|
||||
cmd_iot_argtable[3] = reset =
|
||||
arg_lit0(NULL, "reset", "Reset chip after write");
|
||||
cmd_iot_argtable[4] = single_download =
|
||||
arg_file0("s", "single-down", "<file>", "Single download file");
|
||||
cmd_iot_argtable[5] = single_download_location =
|
||||
arg_int0("l", "single-down-loc", NULL, "Single download offset");
|
||||
cmd_iot_argtable[6] = end = arg_end(10);
|
||||
|
||||
if (arg_nullcheck(cmd_iot_argtable) != 0) {
|
||||
fprintf(stderr, "insufficient memory\n");
|
||||
return BLISP_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
void cmd_iot_args_print_glossary() {
|
||||
fputs("Usage: blisp", stdout);
|
||||
arg_print_syntax(stdout, cmd_iot_argtable, "\n");
|
||||
puts("Flashes firmware as Bouffalo's DevCube");
|
||||
arg_print_glossary(stdout, cmd_iot_argtable, " %-25s %s\n");
|
||||
}
|
||||
|
||||
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) {
|
||||
return blisp_single_download();
|
||||
} else {
|
||||
return BLISP_ERR_INVALID_COMMAND;
|
||||
}
|
||||
} else if (cmd->count == 1) {
|
||||
cmd_iot_args_print_glossary();
|
||||
return BLISP_OK;
|
||||
}
|
||||
return BLISP_ERR_INVALID_COMMAND;
|
||||
}
|
||||
|
||||
void cmd_iot_args_print_syntax() {
|
||||
arg_print_syntax(stdout, cmd_iot_argtable, "\n");
|
||||
}
|
||||
|
||||
void cmd_iot_free() {
|
||||
arg_freetable(cmd_iot_argtable,
|
||||
sizeof(cmd_iot_argtable) / sizeof(cmd_iot_argtable[0]));
|
||||
}
|
||||
|
||||
struct cmd cmd_iot = {"iot", cmd_iot_args_init, cmd_iot_parse_exec,
|
||||
cmd_iot_args_print_syntax, cmd_iot_free};
|
||||
+425
-283
@@ -1,330 +1,472 @@
|
||||
// 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 "parse_file.h"
|
||||
#include "argtable3.h"
|
||||
#include <blisp.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "blisp_struct.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#include <linux/limits.h>
|
||||
#elif defined(_MSC_VER)
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#include <windows.h>
|
||||
#define PATH_MAX MAX_PATH
|
||||
#endif
|
||||
|
||||
#define REG_EXTENDED 1
|
||||
#define REG_ICASE (REG_EXTENDED << 1)
|
||||
#define REG_ICASE (REG_EXTENDED << 1)
|
||||
|
||||
static struct arg_rex* cmd;
|
||||
static struct arg_file* binary_to_write;
|
||||
static struct arg_str *port_name, *chip_type;
|
||||
static struct arg_str* port_name, *chip_type;
|
||||
static struct arg_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);
|
||||
|
||||
boot_header->revison = 0x01;
|
||||
memcpy(boot_header->flashCfg.magiccode, "FCFG", 4);
|
||||
boot_header->flashCfg.cfg.ioMode = 0x11;
|
||||
boot_header->flashCfg.cfg.cReadSupport = 0x00;
|
||||
boot_header->flashCfg.cfg.clkDelay = 0x01;
|
||||
boot_header->flashCfg.cfg.clkInvert = 0x01;
|
||||
boot_header->flashCfg.cfg.resetEnCmd = 0x66;
|
||||
boot_header->flashCfg.cfg.resetCmd = 0x99;
|
||||
boot_header->flashCfg.cfg.resetCreadCmd = 0xFF;
|
||||
boot_header->flashCfg.cfg.resetCreadCmdSize = 0x03;
|
||||
boot_header->flashCfg.cfg.jedecIdCmd = 0x9F;
|
||||
boot_header->flashCfg.cfg.jedecIdCmdDmyClk = 0x00;
|
||||
boot_header->flashCfg.cfg.qpiJedecIdCmd = 0x9F;
|
||||
boot_header->flashCfg.cfg.qpiJedecIdCmdDmyClk = 0x00;
|
||||
boot_header->flashCfg.cfg.sectorSize = 0x04;
|
||||
boot_header->flashCfg.cfg.mid = 0xC2;
|
||||
boot_header->flashCfg.cfg.pageSize = 0x100;
|
||||
boot_header->flashCfg.cfg.chipEraseCmd = 0xC7;
|
||||
boot_header->flashCfg.cfg.sectorEraseCmd = 0x20;
|
||||
boot_header->flashCfg.cfg.blk32EraseCmd = 0x52;
|
||||
boot_header->flashCfg.cfg.blk64EraseCmd = 0xD8;
|
||||
boot_header->flashCfg.cfg.writeEnableCmd = 0x06;
|
||||
boot_header->flashCfg.cfg.pageProgramCmd = 0x02;
|
||||
boot_header->flashCfg.cfg.qpageProgramCmd = 0x32;
|
||||
boot_header->flashCfg.cfg.qppAddrMode = 0x00;
|
||||
boot_header->flashCfg.cfg.fastReadCmd = 0x0B;
|
||||
boot_header->flashCfg.cfg.frDmyClk = 0x01;
|
||||
boot_header->flashCfg.cfg.qpiFastReadCmd = 0x0B;
|
||||
boot_header->flashCfg.cfg.qpiFrDmyClk = 0x01;
|
||||
boot_header->flashCfg.cfg.fastReadDoCmd = 0x3B;
|
||||
boot_header->flashCfg.cfg.frDoDmyClk = 0x01;
|
||||
boot_header->flashCfg.cfg.fastReadDioCmd = 0xBB;
|
||||
boot_header->flashCfg.cfg.frDioDmyClk = 0x00;
|
||||
boot_header->flashCfg.cfg.fastReadQoCmd = 0x6B;
|
||||
boot_header->flashCfg.cfg.frQoDmyClk = 0x01;
|
||||
boot_header->flashCfg.cfg.fastReadQioCmd = 0xEB;
|
||||
boot_header->flashCfg.cfg.frQioDmyClk = 0x02;
|
||||
boot_header->flashCfg.cfg.qpiFastReadQioCmd = 0xEB;
|
||||
boot_header->flashCfg.cfg.qpiFrQioDmyClk = 0x02;
|
||||
boot_header->flashCfg.cfg.qpiPageProgramCmd = 0x02;
|
||||
boot_header->flashCfg.cfg.writeVregEnableCmd = 0x50;
|
||||
boot_header->flashCfg.cfg.wrEnableIndex = 0x00;
|
||||
boot_header->flashCfg.cfg.qeIndex = 0x01;
|
||||
boot_header->flashCfg.cfg.busyIndex = 0x00;
|
||||
boot_header->flashCfg.cfg.wrEnableBit = 0x01;
|
||||
boot_header->flashCfg.cfg.qeBit = 0x01;
|
||||
boot_header->flashCfg.cfg.busyBit = 0x00;
|
||||
boot_header->flashCfg.cfg.wrEnableWriteRegLen = 0x02;
|
||||
boot_header->flashCfg.cfg.wrEnableReadRegLen = 0x01;
|
||||
boot_header->flashCfg.cfg.qeWriteRegLen = 0x02;
|
||||
boot_header->flashCfg.cfg.qeReadRegLen = 0x01;
|
||||
boot_header->flashCfg.cfg.releasePowerDown = 0xAB;
|
||||
boot_header->flashCfg.cfg.busyReadRegLen = 0x01;
|
||||
boot_header->flashCfg.cfg.readRegCmd[0] = 0x05;
|
||||
boot_header->flashCfg.cfg.readRegCmd[1] = 0x00;
|
||||
boot_header->flashCfg.cfg.readRegCmd[2] = 0x00;
|
||||
boot_header->flashCfg.cfg.readRegCmd[3] = 0x00;
|
||||
boot_header->flashCfg.cfg.writeRegCmd[0] = 0x01;
|
||||
boot_header->flashCfg.cfg.writeRegCmd[1] = 0x00;
|
||||
boot_header->flashCfg.cfg.writeRegCmd[2] = 0x00;
|
||||
boot_header->flashCfg.cfg.writeRegCmd[3] = 0x00;
|
||||
boot_header->flashCfg.cfg.enterQpi = 0x38;
|
||||
boot_header->flashCfg.cfg.exitQpi = 0xFF;
|
||||
boot_header->flashCfg.cfg.cReadMode = 0x00;
|
||||
boot_header->flashCfg.cfg.cRExit = 0xFF;
|
||||
boot_header->flashCfg.cfg.burstWrapCmd = 0x77;
|
||||
boot_header->flashCfg.cfg.burstWrapCmdDmyClk = 0x03;
|
||||
boot_header->flashCfg.cfg.burstWrapDataMode = 0x02;
|
||||
boot_header->flashCfg.cfg.burstWrapData = 0x40;
|
||||
boot_header->flashCfg.cfg.deBurstWrapCmd = 0x77;
|
||||
boot_header->flashCfg.cfg.deBurstWrapCmdDmyClk = 0x03;
|
||||
boot_header->flashCfg.cfg.deBurstWrapDataMode = 0x02;
|
||||
boot_header->flashCfg.cfg.deBurstWrapData = 0xF0;
|
||||
boot_header->flashCfg.cfg.timeEsector = 0x12C;
|
||||
boot_header->flashCfg.cfg.timeE32k = 0x4B0;
|
||||
boot_header->flashCfg.cfg.timeE64k = 0x4B0;
|
||||
boot_header->flashCfg.cfg.timePagePgm = 0x05;
|
||||
boot_header->flashCfg.cfg.timeCe = 0xFFFF;
|
||||
boot_header->flashCfg.cfg.pdDelay = 0x14;
|
||||
boot_header->flashCfg.cfg.qeData = 0x00;
|
||||
boot_header->flashCfg.crc32 = 0xE43C762A;
|
||||
boot_header->clkCfg.cfg.xtal_type = 0x01;
|
||||
boot_header->clkCfg.cfg.pll_clk = 0x04;
|
||||
boot_header->clkCfg.cfg.hclk_div = 0x00;
|
||||
boot_header->clkCfg.cfg.bclk_div = 0x01;
|
||||
boot_header->clkCfg.cfg.flash_clk_type = 0x03;
|
||||
boot_header->clkCfg.cfg.flash_clk_div = 0x00;
|
||||
boot_header->clkCfg.crc32 = 0x72127DBA;
|
||||
boot_header->bootcfg.bval.sign = 0x00;
|
||||
boot_header->bootcfg.bval.encrypt_type = 0x00;
|
||||
boot_header->bootcfg.bval.key_sel = 0x00;
|
||||
boot_header->bootcfg.bval.rsvd6_7 = 0x00;
|
||||
boot_header->bootcfg.bval.no_segment = 0x01;
|
||||
boot_header->bootcfg.bval.cache_enable = 0x01;
|
||||
boot_header->bootcfg.bval.notload_in_bootrom = 0x00;
|
||||
boot_header->bootcfg.bval.aes_region_lock = 0x00;
|
||||
boot_header->bootcfg.bval.cache_way_disable = 0x00;
|
||||
boot_header->bootcfg.bval.crc_ignore = 0x01;
|
||||
boot_header->bootcfg.bval.hash_ignore = 0x01;
|
||||
boot_header->bootcfg.bval.halt_ap = 0x00;
|
||||
boot_header->bootcfg.bval.rsvd19_31 = 0x00;
|
||||
boot_header->segment_info.segment_cnt = 0xCDA8;
|
||||
boot_header->bootentry = 0x00;
|
||||
boot_header->flashoffset = 0x2000;
|
||||
boot_header->hash[0x00] = 0xEF;
|
||||
boot_header->hash[0x01] = 0xBE;
|
||||
boot_header->hash[0x02] = 0xAD;
|
||||
boot_header->hash[0x03] = 0xDE;
|
||||
boot_header->hash[0x04] = 0x00;
|
||||
boot_header->hash[0x05] = 0x00;
|
||||
boot_header->hash[0x06] = 0x00;
|
||||
boot_header->hash[0x07] = 0x00;
|
||||
boot_header->hash[0x08] = 0x00;
|
||||
boot_header->hash[0x09] = 0x00;
|
||||
boot_header->hash[0x0a] = 0x00;
|
||||
boot_header->hash[0x0b] = 0x00;
|
||||
boot_header->hash[0x0c] = 0x00;
|
||||
boot_header->hash[0x0d] = 0x00;
|
||||
boot_header->hash[0x0e] = 0x00;
|
||||
boot_header->hash[0x0f] = 0x00;
|
||||
boot_header->hash[0x10] = 0x00;
|
||||
boot_header->hash[0x11] = 0x00;
|
||||
boot_header->hash[0x12] = 0x00;
|
||||
boot_header->hash[0x13] = 0x00;
|
||||
boot_header->hash[0x14] = 0x00;
|
||||
boot_header->hash[0x15] = 0x00;
|
||||
boot_header->hash[0x16] = 0x00;
|
||||
boot_header->hash[0x17] = 0x00;
|
||||
boot_header->hash[0x18] = 0x00;
|
||||
boot_header->hash[0x19] = 0x00;
|
||||
boot_header->hash[0x1a] = 0x00;
|
||||
boot_header->hash[0x1b] = 0x00;
|
||||
boot_header->hash[0x1c] = 0x00;
|
||||
boot_header->hash[0x1d] = 0x00;
|
||||
boot_header->hash[0x1e] = 0x00;
|
||||
boot_header->hash[0x1f] = 0x00;
|
||||
boot_header->rsv1 = 0x1000;
|
||||
boot_header->rsv2 = 0x2000;
|
||||
boot_header->crc32 = 0xDEADBEEF;
|
||||
ssize_t
|
||||
get_binary_folder(char* buffer, uint32_t buffer_size) {
|
||||
#ifdef __linux__
|
||||
readlink("/proc/self/exe", buffer, buffer_size); // TODO: Error handling
|
||||
char* pos = strrchr(buffer, '/');
|
||||
#else
|
||||
GetModuleFileName(NULL, buffer, buffer_size);
|
||||
char* pos = strrchr(buffer, '\\');
|
||||
#endif
|
||||
pos[0] = '\0';
|
||||
return pos - buffer;
|
||||
}
|
||||
|
||||
blisp_return_t blisp_flash_firmware() {
|
||||
struct blisp_device device;
|
||||
blisp_return_t ret;
|
||||
void fill_up_boot_header(struct bfl_boot_header* boot_header)
|
||||
{
|
||||
memcpy(boot_header->magiccode, "BFNP", 4);;
|
||||
boot_header->revison = 0x01;
|
||||
memcpy(boot_header->flashCfg.magiccode, "FCFG", 4);
|
||||
boot_header->flashCfg.cfg.ioMode = 0x11;
|
||||
boot_header->flashCfg.cfg.cReadSupport = 0x00;
|
||||
boot_header->flashCfg.cfg.clkDelay = 0x01;
|
||||
boot_header->flashCfg.cfg.clkInvert = 0x01;
|
||||
boot_header->flashCfg.cfg.resetEnCmd = 0x66;
|
||||
boot_header->flashCfg.cfg.resetCmd = 0x99;
|
||||
boot_header->flashCfg.cfg.resetCreadCmd = 0xFF;
|
||||
boot_header->flashCfg.cfg.resetCreadCmdSize = 0x03;
|
||||
boot_header->flashCfg.cfg.jedecIdCmd = 0x9F;
|
||||
boot_header->flashCfg.cfg.jedecIdCmdDmyClk = 0x00;
|
||||
boot_header->flashCfg.cfg.qpiJedecIdCmd = 0x9F;
|
||||
boot_header->flashCfg.cfg.qpiJedecIdCmdDmyClk = 0x00;
|
||||
boot_header->flashCfg.cfg.sectorSize = 0x04;
|
||||
boot_header->flashCfg.cfg.mid = 0xC2;
|
||||
boot_header->flashCfg.cfg.pageSize = 0x100;
|
||||
boot_header->flashCfg.cfg.chipEraseCmd = 0xC7;
|
||||
boot_header->flashCfg.cfg.sectorEraseCmd = 0x20;
|
||||
boot_header->flashCfg.cfg.blk32EraseCmd = 0x52;
|
||||
boot_header->flashCfg.cfg.blk64EraseCmd = 0xD8;
|
||||
boot_header->flashCfg.cfg.writeEnableCmd = 0x06;
|
||||
boot_header->flashCfg.cfg.pageProgramCmd = 0x02;
|
||||
boot_header->flashCfg.cfg.qpageProgramCmd = 0x32;
|
||||
boot_header->flashCfg.cfg.qppAddrMode = 0x00;
|
||||
boot_header->flashCfg.cfg.fastReadCmd = 0x0B;
|
||||
boot_header->flashCfg.cfg.frDmyClk = 0x01;
|
||||
boot_header->flashCfg.cfg.qpiFastReadCmd = 0x0B;
|
||||
boot_header->flashCfg.cfg.qpiFrDmyClk = 0x01;
|
||||
boot_header->flashCfg.cfg.fastReadDoCmd = 0x3B;
|
||||
boot_header->flashCfg.cfg.frDoDmyClk = 0x01;
|
||||
boot_header->flashCfg.cfg.fastReadDioCmd = 0xBB;
|
||||
boot_header->flashCfg.cfg.frDioDmyClk = 0x00;
|
||||
boot_header->flashCfg.cfg.fastReadQoCmd = 0x6B;
|
||||
boot_header->flashCfg.cfg.frQoDmyClk = 0x01;
|
||||
boot_header->flashCfg.cfg.fastReadQioCmd = 0xEB;
|
||||
boot_header->flashCfg.cfg.frQioDmyClk = 0x02;
|
||||
boot_header->flashCfg.cfg.qpiFastReadQioCmd = 0xEB;
|
||||
boot_header->flashCfg.cfg.qpiFrQioDmyClk = 0x02;
|
||||
boot_header->flashCfg.cfg.qpiPageProgramCmd = 0x02;
|
||||
boot_header->flashCfg.cfg.writeVregEnableCmd = 0x50;
|
||||
boot_header->flashCfg.cfg.wrEnableIndex = 0x00;
|
||||
boot_header->flashCfg.cfg.qeIndex = 0x01;
|
||||
boot_header->flashCfg.cfg.busyIndex = 0x00;
|
||||
boot_header->flashCfg.cfg.wrEnableBit = 0x01;
|
||||
boot_header->flashCfg.cfg.qeBit = 0x01;
|
||||
boot_header->flashCfg.cfg.busyBit = 0x00;
|
||||
boot_header->flashCfg.cfg.wrEnableWriteRegLen = 0x02;
|
||||
boot_header->flashCfg.cfg.wrEnableReadRegLen = 0x01;
|
||||
boot_header->flashCfg.cfg.qeWriteRegLen = 0x02;
|
||||
boot_header->flashCfg.cfg.qeReadRegLen = 0x01;
|
||||
boot_header->flashCfg.cfg.releasePowerDown = 0xAB;
|
||||
boot_header->flashCfg.cfg.busyReadRegLen = 0x01;
|
||||
boot_header->flashCfg.cfg.readRegCmd[0] = 0x05;
|
||||
boot_header->flashCfg.cfg.readRegCmd[1] = 0x00;
|
||||
boot_header->flashCfg.cfg.readRegCmd[2] = 0x00;
|
||||
boot_header->flashCfg.cfg.readRegCmd[3] = 0x00;
|
||||
boot_header->flashCfg.cfg.writeRegCmd[0] = 0x01;
|
||||
boot_header->flashCfg.cfg.writeRegCmd[1] = 0x00;
|
||||
boot_header->flashCfg.cfg.writeRegCmd[2] = 0x00;
|
||||
boot_header->flashCfg.cfg.writeRegCmd[3] = 0x00;
|
||||
boot_header->flashCfg.cfg.enterQpi = 0x38;
|
||||
boot_header->flashCfg.cfg.exitQpi = 0xFF;
|
||||
boot_header->flashCfg.cfg.cReadMode = 0x00;
|
||||
boot_header->flashCfg.cfg.cRExit = 0xFF;
|
||||
boot_header->flashCfg.cfg.burstWrapCmd = 0x77;
|
||||
boot_header->flashCfg.cfg.burstWrapCmdDmyClk = 0x03;
|
||||
boot_header->flashCfg.cfg.burstWrapDataMode = 0x02;
|
||||
boot_header->flashCfg.cfg.burstWrapData = 0x40;
|
||||
boot_header->flashCfg.cfg.deBurstWrapCmd = 0x77;
|
||||
boot_header->flashCfg.cfg.deBurstWrapCmdDmyClk = 0x03;
|
||||
boot_header->flashCfg.cfg.deBurstWrapDataMode = 0x02;
|
||||
boot_header->flashCfg.cfg.deBurstWrapData = 0xF0;
|
||||
boot_header->flashCfg.cfg.timeEsector = 0x12C;
|
||||
boot_header->flashCfg.cfg.timeE32k = 0x4B0;
|
||||
boot_header->flashCfg.cfg.timeE64k = 0x4B0;
|
||||
boot_header->flashCfg.cfg.timePagePgm = 0x05;
|
||||
boot_header->flashCfg.cfg.timeCe = 0xFFFF;
|
||||
boot_header->flashCfg.cfg.pdDelay = 0x14;
|
||||
boot_header->flashCfg.cfg.qeData = 0x00;
|
||||
boot_header->flashCfg.crc32 = 0xE43C762A;
|
||||
boot_header->clkCfg.cfg.xtal_type = 0x01;
|
||||
boot_header->clkCfg.cfg.pll_clk = 0x04;
|
||||
boot_header->clkCfg.cfg.hclk_div = 0x00;
|
||||
boot_header->clkCfg.cfg.bclk_div = 0x01;
|
||||
boot_header->clkCfg.cfg.flash_clk_type = 0x03;
|
||||
boot_header->clkCfg.cfg.flash_clk_div = 0x00;
|
||||
boot_header->clkCfg.crc32 = 0x72127DBA;
|
||||
boot_header->bootcfg.bval.sign = 0x00;
|
||||
boot_header->bootcfg.bval.encrypt_type = 0x00;
|
||||
boot_header->bootcfg.bval.key_sel = 0x00;
|
||||
boot_header->bootcfg.bval.rsvd6_7 = 0x00;
|
||||
boot_header->bootcfg.bval.no_segment = 0x01;
|
||||
boot_header->bootcfg.bval.cache_enable = 0x01;
|
||||
boot_header->bootcfg.bval.notload_in_bootrom = 0x00;
|
||||
boot_header->bootcfg.bval.aes_region_lock = 0x00;
|
||||
boot_header->bootcfg.bval.cache_way_disable = 0x00;
|
||||
boot_header->bootcfg.bval.crc_ignore = 0x01;
|
||||
boot_header->bootcfg.bval.hash_ignore = 0x01;
|
||||
boot_header->bootcfg.bval.halt_ap = 0x00;
|
||||
boot_header->bootcfg.bval.rsvd19_31 = 0x00;
|
||||
boot_header->segment_info.segment_cnt = 0xCDA8;
|
||||
boot_header->bootentry = 0x00;
|
||||
boot_header->flashoffset = 0x2000;
|
||||
boot_header->hash[0x00] = 0xEF;
|
||||
boot_header->hash[0x01] = 0xBE;
|
||||
boot_header->hash[0x02] = 0xAD;
|
||||
boot_header->hash[0x03] = 0xDE;
|
||||
boot_header->hash[0x04] = 0x00;
|
||||
boot_header->hash[0x05] = 0x00;
|
||||
boot_header->hash[0x06] = 0x00;
|
||||
boot_header->hash[0x07] = 0x00;
|
||||
boot_header->hash[0x08] = 0x00;
|
||||
boot_header->hash[0x09] = 0x00;
|
||||
boot_header->hash[0x0a] = 0x00;
|
||||
boot_header->hash[0x0b] = 0x00;
|
||||
boot_header->hash[0x0c] = 0x00;
|
||||
boot_header->hash[0x0d] = 0x00;
|
||||
boot_header->hash[0x0e] = 0x00;
|
||||
boot_header->hash[0x0f] = 0x00;
|
||||
boot_header->hash[0x10] = 0x00;
|
||||
boot_header->hash[0x11] = 0x00;
|
||||
boot_header->hash[0x12] = 0x00;
|
||||
boot_header->hash[0x13] = 0x00;
|
||||
boot_header->hash[0x14] = 0x00;
|
||||
boot_header->hash[0x15] = 0x00;
|
||||
boot_header->hash[0x16] = 0x00;
|
||||
boot_header->hash[0x17] = 0x00;
|
||||
boot_header->hash[0x18] = 0x00;
|
||||
boot_header->hash[0x19] = 0x00;
|
||||
boot_header->hash[0x1a] = 0x00;
|
||||
boot_header->hash[0x1b] = 0x00;
|
||||
boot_header->hash[0x1c] = 0x00;
|
||||
boot_header->hash[0x1d] = 0x00;
|
||||
boot_header->hash[0x1e] = 0x00;
|
||||
boot_header->hash[0x1f] = 0x00;
|
||||
boot_header->rsv1 = 0x1000;
|
||||
boot_header->rsv2 = 0x2000;
|
||||
boot_header->crc32 = 0xDEADBEEF;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
void blisp_flash_firmware() {
|
||||
FILE* eflash_loader_file = NULL;
|
||||
|
||||
ret = blisp_common_init_device(&device, port_name, chip_type);
|
||||
if (chip_type->count == 0) {
|
||||
fprintf(stderr, "Chip type is invalid.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
struct blisp_chip* chip = NULL;
|
||||
|
||||
if (blisp_common_prepare_flash(&device) != 0) {
|
||||
// TODO: Error handling
|
||||
goto exit1;
|
||||
}
|
||||
if (strcmp(chip_type->sval[0], "bl70x") == 0) {
|
||||
chip = &blisp_chip_bl70x;
|
||||
} else if (strcmp(chip_type->sval[0], "bl60x") == 0) {
|
||||
chip = &blisp_chip_bl60x;
|
||||
} else if (strcmp(chip_type->sval[0], "bl808") == 0) {
|
||||
chip = &blisp_chip_bl808;
|
||||
} else {
|
||||
fprintf(stderr, "Chip type is invalid.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
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 blisp_device device;
|
||||
int32_t ret;
|
||||
ret = blisp_device_init(&device, chip);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Failed to init device.\n");
|
||||
return;
|
||||
}
|
||||
ret = blisp_device_open(&device, port_name->count == 1 ? port_name->sval[0] : NULL);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Failed to open device.\n");
|
||||
return;
|
||||
}
|
||||
printf("Sending a handshake...");
|
||||
ret = blisp_device_handshake(&device, false);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "\nFailed to handshake with device.\n");
|
||||
goto exit1;
|
||||
}
|
||||
printf(" OK\nGetting chip info...");
|
||||
struct blisp_boot_info boot_info;
|
||||
ret = blisp_device_get_boot_info(&device, &boot_info);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "\nFailed to get boot info.\n");
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
// 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__
|
||||
if (boot_info.boot_rom_version[0] == 255 &&
|
||||
boot_info.boot_rom_version[1] == 255 &&
|
||||
boot_info.boot_rom_version[2] == 255 &&
|
||||
boot_info.boot_rom_version[3] == 255) {
|
||||
printf(" OK\nDevice already in eflash_loader.\n");
|
||||
goto eflash_loader;
|
||||
}
|
||||
|
||||
printf(" BootROM version %d.%d.%d.%d, ChipID: %02X%02X%02X%02X%02X%02X%02X%02X\n",
|
||||
boot_info.boot_rom_version[0],
|
||||
boot_info.boot_rom_version[1],
|
||||
boot_info.boot_rom_version[2],
|
||||
boot_info.boot_rom_version[3],
|
||||
boot_info.chip_id[0],
|
||||
boot_info.chip_id[1],
|
||||
boot_info.chip_id[2],
|
||||
boot_info.chip_id[3],
|
||||
boot_info.chip_id[4],
|
||||
boot_info.chip_id[5],
|
||||
boot_info.chip_id[6],
|
||||
boot_info.chip_id[7]);
|
||||
|
||||
if (device.chip->type == BLISP_CHIP_BL808) {
|
||||
// Since eflash_loader is not needed in BL808, we can jump to flashing.
|
||||
goto eflash_loader; // TODO: Rework
|
||||
}
|
||||
|
||||
char exe_path[PATH_MAX];
|
||||
char eflash_loader_path[PATH_MAX];
|
||||
get_binary_folder(exe_path, PATH_MAX); // TODO: Error handling
|
||||
snprintf(eflash_loader_path, PATH_MAX, "%s/data/%s/eflash_loader_%s.bin", exe_path, device.chip->type_str, device.chip->default_eflash_loader_xtal);
|
||||
|
||||
eflash_loader_file = fopen(eflash_loader_path, "rb"); // TODO: Error handling
|
||||
uint8_t eflash_loader_header[176]; // TODO: Remap it to the boot header struct
|
||||
fread(eflash_loader_header, 176, 1, eflash_loader_file); // TODO: Error handling
|
||||
|
||||
printf("Loading eflash_loader...\n");
|
||||
ret = blisp_device_load_boot_header(&device, eflash_loader_header);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Failed to load boot header.\n");
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
{
|
||||
uint32_t sent_data = 0;
|
||||
uint32_t buffer_size = 0;
|
||||
uint8_t buffer[4092];
|
||||
|
||||
// TODO: Real checking of segments count
|
||||
for (uint8_t seg_index = 0; seg_index < 1; seg_index++) {
|
||||
struct blisp_segment_header segment_header = { 0 };
|
||||
fread(&segment_header, 16, 1,
|
||||
eflash_loader_file); // TODO: Error handling
|
||||
|
||||
ret = blisp_device_load_segment_header(&device, &segment_header);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Failed to load segment header.\n");
|
||||
goto exit1;
|
||||
}
|
||||
printf("Flashing %d. segment\n", seg_index + 1);
|
||||
printf("0b / %" PRIu32 "b (0.00%%)\n", segment_header.length);
|
||||
|
||||
while (sent_data < segment_header.length) {
|
||||
buffer_size = segment_header.length - sent_data;
|
||||
if (buffer_size > 4092) {
|
||||
buffer_size = 4092;
|
||||
}
|
||||
fread(buffer, buffer_size, 1, eflash_loader_file);
|
||||
ret = blisp_device_load_segment_data(
|
||||
&device, buffer, buffer_size); // TODO: Error handling
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Failed to load segment data. (ret %d)\n", ret);
|
||||
goto exit1;
|
||||
}
|
||||
sent_data += buffer_size;
|
||||
printf("%" PRIu32 "b / %" PRIu32 "b (%.2f%%)\n", sent_data,
|
||||
segment_header.length,
|
||||
(((float)sent_data / (float)segment_header.length)
|
||||
* 100.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = blisp_device_check_image(&device);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Failed to check image.\n");
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
ret = blisp_device_run_image(&device);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Failed to run image.\n");
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
printf("Sending a handshake...");
|
||||
ret = blisp_device_handshake(&device, true);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "\nFailed to handshake with device.\n");
|
||||
goto exit1;
|
||||
}
|
||||
printf(" OK\n");
|
||||
|
||||
eflash_loader:
|
||||
if (device.chip->type == BLISP_CHIP_BL808) {
|
||||
// Setting CLK configuration
|
||||
// Setting Flash Config
|
||||
// Setting Flash Parameter
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
const uint32_t firmware_base_address = 0x2000;
|
||||
printf("Erasing flash, this might take a while...");
|
||||
ret = blisp_device_flash_erase(&device, firmware_base_address,
|
||||
firmware_base_address + firmware_file_size
|
||||
+ 1);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "\nFailed 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;
|
||||
ret = blisp_device_flash_erase(&device, 0x0000, sizeof(struct bfl_boot_header));
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "\nFailed to erase flash.\n");
|
||||
goto exit2;
|
||||
}
|
||||
// Move the firmware to-be-flashed beyond the boot header area
|
||||
parsed_file.payload_address += 0x2000;
|
||||
}
|
||||
// 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);
|
||||
printf(" OK!\nFlashing boot header...");
|
||||
ret = blisp_device_flash_write(&device, 0x0000, (uint8_t*)&boot_header, sizeof(struct bfl_boot_header));
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "\nFailed to write boot header.\n");
|
||||
goto exit2;
|
||||
}
|
||||
printf(" OK!\nFlashing the firmware...\n");
|
||||
{
|
||||
uint32_t sent_data = 0;
|
||||
uint32_t buffer_size = 0;
|
||||
uint8_t buffer[8184];
|
||||
printf("0b / %ldb (0.00%%)\n", firmware_file_size);
|
||||
|
||||
if (ret != BLISP_OK) {
|
||||
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;
|
||||
}
|
||||
while (sent_data < firmware_file_size) {
|
||||
buffer_size = firmware_file_size - sent_data;
|
||||
if (buffer_size > 2052) {
|
||||
buffer_size = 2052;
|
||||
}
|
||||
fread(buffer, buffer_size, 1, firmware_file);
|
||||
ret = blisp_device_flash_write(&device, firmware_base_address + sent_data, buffer, buffer_size); // TODO: Error handling
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Failed to write firmware! (ret: %d)\n", ret);
|
||||
goto exit2;
|
||||
}
|
||||
sent_data += buffer_size;
|
||||
printf("%" PRIu32 "b / %ldb (%.2f%%)\n", sent_data, firmware_file_size,
|
||||
(((float)sent_data / (float)firmware_file_size) * 100.0f));
|
||||
}
|
||||
}
|
||||
|
||||
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_memory(parsed_file.payload,
|
||||
parsed_file.payload_length);
|
||||
printf("Checking program...");
|
||||
ret = blisp_device_program_check(&device);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "\nFailed to check program.\n");
|
||||
goto exit2;
|
||||
}
|
||||
printf("OK\n");
|
||||
|
||||
ret = blisp_easy_flash_write(
|
||||
&device, &data_transport, parsed_file.payload_address,
|
||||
parsed_file.payload_length, blisp_common_progress_callback);
|
||||
if (reset->count > 0) {
|
||||
blisp_device_reset(&device);
|
||||
printf("Resetting the chip.\n");
|
||||
// TODO: It seems that GPIO peripheral is not reset after resetting the chip
|
||||
}
|
||||
|
||||
if (ret < BLISP_OK) {
|
||||
fprintf(stderr, "Failed to write app to flash.\n");
|
||||
goto exit2;
|
||||
}
|
||||
|
||||
printf("Checking program...\n");
|
||||
ret = blisp_device_program_check(&device);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to check program.\n");
|
||||
goto exit2;
|
||||
}
|
||||
printf("Program OK!\n");
|
||||
|
||||
if (reset->count > 0) {
|
||||
blisp_device_reset(&device);
|
||||
printf("Resetting the chip.\n");
|
||||
// TODO: It seems that GPIO peripheral is not reset after resetting the chip
|
||||
}
|
||||
|
||||
printf("Flash complete!\n");
|
||||
printf("Flash complete!\n");
|
||||
|
||||
exit2:
|
||||
if (parsed_file.payload != NULL)
|
||||
free(parsed_file.payload);
|
||||
if (firmware_file != NULL) fclose(firmware_file);
|
||||
exit1:
|
||||
blisp_device_close(&device);
|
||||
if (eflash_loader_file != NULL) fclose(eflash_loader_file);
|
||||
blisp_device_close(&device);
|
||||
}
|
||||
|
||||
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 =
|
||||
arg_str1("c", "chip", "<chip_type>", "Chip Type");
|
||||
cmd_write_argtable[2] = port_name =
|
||||
arg_str0("p", "port", "<port_name>",
|
||||
"Name/Path to the Serial Port (empty for search)");
|
||||
cmd_write_argtable[3] = reset =
|
||||
arg_lit0(NULL, "reset", "Reset chip after write");
|
||||
cmd_write_argtable[4] = binary_to_write =
|
||||
arg_file1(NULL, NULL, "<input>", "Binary to write");
|
||||
cmd_write_argtable[5] = end = arg_end(10);
|
||||
int8_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 = arg_str1("c", "chip", "<chip_type>", "Chip Type (bl70x)");
|
||||
cmd_write_argtable[2] = port_name
|
||||
= arg_str0("p", "port", "<port_name>", "Name/Path to the Serial Port (empty for search)");
|
||||
cmd_write_argtable[3] = reset = arg_lit0(NULL, "reset", "Reset chip after write");
|
||||
cmd_write_argtable[4] = binary_to_write
|
||||
= arg_file1(NULL, NULL, "<input>", "Binary to write");
|
||||
cmd_write_argtable[5] = end = arg_end(10);
|
||||
|
||||
if (arg_nullcheck(cmd_write_argtable) != 0) {
|
||||
fprintf(stderr, "insufficient memory\n");
|
||||
return BLISP_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
return BLISP_OK;
|
||||
if (arg_nullcheck(cmd_write_argtable) != 0) {
|
||||
fprintf(stderr, "insufficient memory\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cmd_write_args_print_glossary() {
|
||||
fputs("Usage: blisp", stdout);
|
||||
arg_print_syntax(stdout, cmd_write_argtable, "\n");
|
||||
puts("Writes firmware to SPI Flash");
|
||||
arg_print_glossary(stdout, cmd_write_argtable, " %-25s %s\n");
|
||||
fputs("Usage: blisp", stdout);
|
||||
arg_print_syntax(stdout,cmd_write_argtable,"\n");
|
||||
puts("Writes firmware to SPI Flash");
|
||||
arg_print_glossary(stdout,cmd_write_argtable," %-25s %s\n");
|
||||
}
|
||||
|
||||
blisp_return_t cmd_write_parse_exec(int argc, char** argv) {
|
||||
int errors = arg_parse(argc, argv, cmd_write_argtable);
|
||||
if (errors == 0) {
|
||||
return blisp_flash_firmware(); // TODO: Error code?
|
||||
|
||||
} else if (cmd->count == 1) {
|
||||
cmd_write_args_print_glossary();
|
||||
return BLISP_OK;
|
||||
}
|
||||
return BLISP_ERR_INVALID_COMMAND;
|
||||
uint8_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;
|
||||
} else if (cmd->count == 1) {
|
||||
cmd_write_args_print_glossary();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cmd_write_args_print_syntax() {
|
||||
arg_print_syntax(stdout, cmd_write_argtable, "\n");
|
||||
arg_print_syntax(stdout,cmd_write_argtable,"\n");
|
||||
}
|
||||
|
||||
void cmd_write_free() {
|
||||
arg_freetable(cmd_write_argtable,
|
||||
sizeof(cmd_write_argtable) / sizeof(cmd_write_argtable[0]));
|
||||
void
|
||||
cmd_write_free() {
|
||||
arg_freetable(cmd_write_argtable,
|
||||
sizeof(cmd_write_argtable) / sizeof(cmd_write_argtable[0]));
|
||||
}
|
||||
|
||||
struct cmd cmd_write = {"write", cmd_write_args_init, cmd_write_parse_exec,
|
||||
cmd_write_args_print_syntax, cmd_write_free};
|
||||
struct cmd cmd_write
|
||||
= { "write", cmd_write_args_init, cmd_write_parse_exec, cmd_write_args_print_syntax, cmd_write_free };
|
||||
@@ -1,144 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "common.h"
|
||||
#include <argtable3.h>
|
||||
#include <blisp.h>
|
||||
#include <inttypes.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 / %u (%.2f%%)\n", current_value, max_value,
|
||||
(((float)current_value / (float)max_value) * 100.0f));
|
||||
}
|
||||
|
||||
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 BLISP_ERR_INVALID_CHIP_TYPE;
|
||||
}
|
||||
|
||||
struct blisp_chip* chip = NULL;
|
||||
|
||||
if (strcmp(chip_type->sval[0], "bl70x") == 0) {
|
||||
chip = &blisp_chip_bl70x;
|
||||
} else if (strcmp(chip_type->sval[0], "bl60x") == 0) {
|
||||
chip = &blisp_chip_bl60x;
|
||||
} else {
|
||||
fprintf(stderr, "Chip type is invalid.\n");
|
||||
return BLISP_ERR_INVALID_CHIP_TYPE;
|
||||
}
|
||||
|
||||
blisp_return_t ret;
|
||||
ret = blisp_device_init(device, chip);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to init device.\n");
|
||||
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 ret;
|
||||
}
|
||||
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares chip to access flash
|
||||
* this means performing handshake, and loading eflash_loader if needed.
|
||||
*/
|
||||
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 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 ret;
|
||||
}
|
||||
|
||||
printf(
|
||||
"BootROM version %d.%d.%d.%d, ChipID: "
|
||||
"%02X%02X%02X%02X%02X%02X%02X%02X\n",
|
||||
boot_info.boot_rom_version[0], boot_info.boot_rom_version[1],
|
||||
boot_info.boot_rom_version[2], boot_info.boot_rom_version[3],
|
||||
boot_info.chip_id[0], boot_info.chip_id[1], boot_info.chip_id[2],
|
||||
boot_info.chip_id[3], boot_info.chip_id[4], boot_info.chip_id[5],
|
||||
boot_info.chip_id[6], boot_info.chip_id[7]);
|
||||
|
||||
if (device->chip->load_eflash_loader == NULL) {
|
||||
return BLISP_OK;
|
||||
}
|
||||
|
||||
if (boot_info.boot_rom_version[0] == 255 &&
|
||||
boot_info.boot_rom_version[1] == 255 &&
|
||||
boot_info.boot_rom_version[2] == 255 &&
|
||||
boot_info.boot_rom_version[3] == 255) {
|
||||
printf("Device already in eflash_loader.\n");
|
||||
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);
|
||||
|
||||
struct blisp_easy_transport eflash_loader_transport =
|
||||
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);
|
||||
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to load eflash_loader, ret: %d\n", ret);
|
||||
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
free(eflash_loader_buffer);
|
||||
eflash_loader_buffer = NULL;
|
||||
|
||||
ret = blisp_device_check_image(device);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Failed to check image.\n");
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
ret = blisp_device_run_image(device);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to run image.\n");
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
printf("Sending a handshake...\n");
|
||||
ret = blisp_device_handshake(device, true);
|
||||
if (ret != BLISP_OK) {
|
||||
fprintf(stderr, "Failed to handshake with device.\n");
|
||||
goto exit1;
|
||||
}
|
||||
printf("Handshake with eflash_loader successful.\n");
|
||||
exit1:
|
||||
if (eflash_loader_buffer != NULL)
|
||||
free(eflash_loader_buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef BLISP_COMMON_H
|
||||
#define BLISP_COMMON_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <blisp.h>
|
||||
#include <argtable3.h>
|
||||
|
||||
int32_t blisp_common_prepare_flash(struct blisp_device* device);
|
||||
void blisp_common_progress_callback(uint32_t current_value, uint32_t max_value);
|
||||
int32_t blisp_common_init_device(struct blisp_device* device, struct arg_str* port_name, struct arg_str* chip_type);
|
||||
|
||||
#endif // BLISP_COMMON_H
|
||||
@@ -1,24 +0,0 @@
|
||||
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}
|
||||
|
||||
)
|
||||
@@ -1,15 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
@@ -1,53 +0,0 @@
|
||||
//
|
||||
// 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);
|
||||
}
|
||||
@@ -1,293 +0,0 @@
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
@@ -1,31 +0,0 @@
|
||||
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)
|
||||
@@ -1,10 +0,0 @@
|
||||
//
|
||||
// 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
|
||||
Binary file not shown.
@@ -1,17 +0,0 @@
|
||||
//
|
||||
// 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);
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#ifndef PARSE_FILE_H_
|
||||
#define PARSE_FILE_H_
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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_
|
||||
@@ -1,17 +0,0 @@
|
||||
#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_
|
||||
+63
-68
@@ -1,11 +1,12 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "argtable3.h"
|
||||
#include "cmd.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "argtable3.h"
|
||||
#include "cmd.h"
|
||||
|
||||
struct cmd* cmds[] = {&cmd_write, &cmd_iot};
|
||||
struct cmd* cmds[] = {
|
||||
&cmd_write
|
||||
};
|
||||
|
||||
static uint8_t cmds_count = sizeof(cmds) / sizeof(cmds[0]);
|
||||
|
||||
@@ -14,90 +15,84 @@ static struct arg_lit* version;
|
||||
static struct arg_end* end;
|
||||
static void* argtable[3];
|
||||
|
||||
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");
|
||||
argtable[2] = end = arg_end(20);
|
||||
int8_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");
|
||||
argtable[2] = end = arg_end(20);
|
||||
|
||||
if (arg_nullcheck(argtable) != 0) {
|
||||
fprintf(stderr, "insufficient memory\n");
|
||||
return BLISP_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (arg_nullcheck(argtable) != 0) {
|
||||
fprintf(stderr, "insufficient memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return BLISP_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_help() {
|
||||
puts("Usage:");
|
||||
for (uint8_t i = 0; i < cmds_count; i++) {
|
||||
puts("Usage:");
|
||||
for (uint8_t i = 0; i < cmds_count; i++) {
|
||||
fputs(" blisp", stdout);
|
||||
cmds[i]->args_print_syntax();
|
||||
}
|
||||
fputs(" blisp", stdout);
|
||||
cmds[i]->args_print_syntax();
|
||||
}
|
||||
fputs(" blisp", stdout);
|
||||
arg_print_syntax(stdout, argtable, "\n");
|
||||
arg_print_syntax(stdout, argtable,"\n");
|
||||
}
|
||||
|
||||
int8_t args_parse_exec(int argc, char** argv) {
|
||||
int error = arg_parse(argc, argv, argtable);
|
||||
if (error == 0) {
|
||||
if (help->count) {
|
||||
print_help();
|
||||
return BLISP_OK;
|
||||
} else if (version->count) {
|
||||
printf("blisp v0.0.4\n");
|
||||
printf("Copyright (C) 2023 Marek Kraus and PINE64 Community\n");
|
||||
return BLISP_OK;
|
||||
int error = arg_parse(argc, argv, argtable);
|
||||
if (error == 0) {
|
||||
if (help->count) {
|
||||
print_help();
|
||||
return 1;
|
||||
} else if (version->count) {
|
||||
printf("blisp 1.0.0\n");
|
||||
printf("Copyright (C) 2022 Marek Kraus and PINE64 Community\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return BLISP_ERR_INVALID_COMMAND;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void args_free() {
|
||||
arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
|
||||
arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
blisp_return_t ret = args_init();
|
||||
if (ret != 0) {
|
||||
goto exit;
|
||||
}
|
||||
int
|
||||
main(int argc, char** argv) {
|
||||
int exit_code = 0;
|
||||
|
||||
for (uint8_t i = 0; i < cmds_count; i++) {
|
||||
ret = cmds[i]->args_init();
|
||||
if (ret != BLISP_OK) {
|
||||
goto exit;
|
||||
if (args_init() != 0) {
|
||||
exit_code = -1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
// Try and parse as a help request
|
||||
{
|
||||
ret = args_parse_exec(argc, argv);
|
||||
if (ret == BLISP_OK) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t command_found = false;
|
||||
for (uint8_t i = 0; i < cmds_count; i++) {
|
||||
ret = cmds[i]->args_parse_exec(argc, argv);
|
||||
if (ret != BLISP_ERR_INVALID_COMMAND) {
|
||||
command_found = true;
|
||||
break;
|
||||
for (uint8_t i = 0; i < cmds_count; i++) {
|
||||
if (cmds[i]->args_init() != 0) {
|
||||
exit_code = -1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!command_found) {
|
||||
print_help();
|
||||
}
|
||||
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)) {
|
||||
command_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!command_found) {
|
||||
print_help();
|
||||
}
|
||||
|
||||
exit:
|
||||
for (uint8_t i = 0; i < cmds_count; i++) {
|
||||
cmds[i]->args_free();
|
||||
}
|
||||
args_free();
|
||||
// Make error codes more intuitive, but converting to +ve mirror
|
||||
if (ret < 0) {
|
||||
ret = -ret;
|
||||
}
|
||||
return ret;
|
||||
for (uint8_t i = 0; i < cmds_count; i++) {
|
||||
cmds[i]->args_free();
|
||||
}
|
||||
args_free();
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "util.h"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Ugh. This stuff is just so messy without C++17 or Qt...
|
||||
// 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.
|
||||
|
||||
char raw_path_name[PATH_MAX]; // $HOME/../../var/tmp/x
|
||||
char real_path_name[PATH_MAX]; // /var/tmp/x
|
||||
uint32_t raw_path_size = sizeof(raw_path_name);
|
||||
|
||||
if (!_NSGetExecutablePath(raw_path_name, &raw_path_size)) {
|
||||
realpath(raw_path_name, real_path_name);
|
||||
}
|
||||
// *real_path_name is appropriately sized and null terminated.
|
||||
strcpy(buffer_out, real_path_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
ssize_t util_get_binary_folder(char* buffer, uint32_t buffer_size) {
|
||||
#ifdef __linux__
|
||||
if (readlink("/proc/self/exe", buffer, buffer_size) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
char* pos = strrchr(buffer, '/');
|
||||
#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;
|
||||
}
|
||||
char* pos = strrchr(buffer, '\\');
|
||||
#endif
|
||||
pos[0] = '\0';
|
||||
return pos - buffer;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef BLISP_UTIL_H
|
||||
#define BLISP_UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#include <windows.h>
|
||||
#define PATH_MAX MAX_PATH
|
||||
#elif defined(__APPLE__)
|
||||
#include <sys/syslimits.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
ssize_t util_get_binary_folder(char* buffer, uint32_t buffer_size);
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user