Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.git
build
firmware/build
firmware/build-ble
docs/firmware/*.fwsc
node_modules
fm1-1.bin
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
build/
firmware/build/
firmware/openpocket.bin
firmware/build-ble/
firmware/openpocket-ble.bin
docs/firmware/*.fwsc
docs/firmware/manifest.json
*.o
Expand Down
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@
# Docker command lines; Windows calls it from the .bat files. See docs/BUILDING.md.
# make doctor check the prerequisites (Node, Docker, the image)
# make build firmware/openpocket.bin, the update loader and docs/firmware/*.fwsc + manifest.json
# make ble the advertise-only Bluetooth test image: firmware/openpocket-ble.bin, build/ble/*.fwsc (docs/BLE-TEST.md)
# make test the host tests (tests/run_tests.sh)
# make package build + build/SHA256SUMS of the outputs
# make clean remove every build output (needs no Docker)
# make shell a shell in the build container
# make image (re)build the container image
# make serve the installer and editor on http://localhost:8765/ (offline install)
# make serve-ble the same, with the Bluetooth test packages (build/ble) to install; builds them first if missing
# make render IN=guitar.wav [OUT=out.wav] [PRESET=1] a WAV through the engine
# make appimage [DUMP=fm1-1.bin] fm1-300.bin for the SD-card recovery
# `make NATIVE=1 build` skips Docker (toolchain installed with firmware/setup.sh).
.PHONY: doctor build test package clean shell image serve render appimage
doctor build test package clean shell image serve:
.PHONY: doctor build ble test package clean shell image serve serve-ble render appimage
doctor build ble test package clean shell image serve:
@node tools/op.mjs $@
serve-ble:
@node tools/op.mjs serve ble
render:
@node tools/op.mjs render "$(IN)" "$(OUT)" "$(PRESET)"
appimage:
Expand Down
2 changes: 2 additions & 0 deletions NOTICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ OpenPocket is GPL-3.0-only (`LICENSE`), except the parts below, which keep their
| `loader/` (update loader) | felucca-bsp `loader/`, changed for the Pocket X flash layout | MPL-2.0 |
| `docs/pxota.js`, `docs/pxpkg.js`, `tools/pxpkg.py`, `tools/mkloader.py`, `tools/lz4blk.py` | adapted from [Felucca](https://github.com/hugelton/Felucca)'s web installer and build tools (as used by CLIPPER and SLOOP) | GPL-3.0 |
| `firmware/sdk/` (I2S and DAC drivers as LLVM bitcode, SPL, cfg files) | JieLi AC79 SDK V1.2.0 (fw-AC79_AIoT_SDK) | Apache-2.0 (`LICENSES/Apache-2.0.txt`) |
| `third_party/jieli-ble/` (JieLi's Bluetooth LE controller, 33 objects of `btctrler.a` and 3 of `cpu.a`, as published LLVM bitcode, used only by the Bluetooth test image `make ble`) | JieLi AC79 SDK V1.2.0 (fw-AC79_AIoT_SDK, commit `0617f4c`), `cpu/wl82/liba/`; see `third_party/jieli-ble/README.md` | Apache-2.0 (`third_party/jieli-ble/LICENSE-JieLi-Apache-2.0`, `LICENSES/Apache-2.0.txt`) |
| `firmware/ble/ble_cfg.c` | values and names from the same SDK's `apps/common/config/log_config/lib_btctrler_config.c` | Apache-2.0 |
| `firmware/fonts.h` (bitmaps generated from Inter) | [Inter](https://rsms.me/inter/), Rasmus Andersson | SIL OFL 1.1 (`LICENSES/OFL-1.1-Inter.txt`) |

Sound models: the names refer to the gear that inspired each voicing (circuit analyses published by ElectroSmash,
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ replaces the files with this folder's.
| `tools/` | package builder, loader wrapper, font converter, flash image tools |
| `tests/` | host tests and the simulated pedal |
| `flash/` | SD-card recovery with fm1buddy (ESP32-S3) |
| `firmware/ble/`, `third_party/jieli-ble/` | the optional advertise-only Bluetooth test image (`make ble`, [docs/BLE-TEST.md](docs/BLE-TEST.md)) and JieLi's Bluetooth controller it links |

## Licence

Expand Down
175 changes: 175 additions & 0 deletions docs/BLE-TEST.md

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion docs/BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Apple silicon and other ARM machines Docker emulates it (Rosetta or QEMU); you c
| --- | --- |
| `make doctor` | check Node, Docker and the image, one line each (exit 1 when the build cannot work) |
| `make build` | `firmware/build.sh` in the container: `firmware/openpocket.bin`, the update loader, `docs/firmware/PocketX_9NN.fwsc`, `BlackBox_9NN.fwsc`, `manifest.json` |
| `make ble` | the advertise-only Bluetooth test image (`OP_BLE=1 firmware/build.sh`): `firmware/openpocket-ble.bin`, `build/ble/*.fwsc`. Own target, own output folders; [BLE-TEST.md](BLE-TEST.md) |
| `make serve-ble` | `make serve` with `build/ble/` as the installer's package folder, to flash the test image |
| `make package` | `build`, then `build/SHA256SUMS` |
| `make test` | `tests/run_tests.sh` (engine, preset store, screen, simulated pedal, installer, editor; the browser page tests also run when Playwright is installed) |
| `make clean` | remove every build output (on the host; needs neither Docker nor the image) |
Expand Down Expand Up @@ -57,7 +59,7 @@ old one.
The toolchain is JieLi's proprietary software. It is **not** in this repository and is not redistributed by it: the image
build downloads it from JieLi's own server (`jl-update.oss-cn-shenzhen.aliyuncs.com`, the file `https://pkgman.jieliapp.com/s/linux-toolchain`
redirects to). If you publish a container image, do not include the toolchain layer. The Apache-2.0 SDK parts in
`firmware/sdk/` are covered by `NOTICE.md`.
`firmware/sdk/` and `third_party/jieli-ble/` are covered by `NOTICE.md`.

## Reproducibility

Expand Down
13 changes: 10 additions & 3 deletions firmware/app.ld
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
/* Memory map of a standalone FM-1 app: code and constants run in place from XIP
* (app.bin offset 0 = 0x02000120); .data is copied to RAM by fm1_cstart, and so is .ram_text (code that runs
* while the flash is busy: the flash driver) into RAMTEXT, the guard's RAM code window.
* The ble build (OP_BLE=1) adds the JieLi controller's own sections: .*_code and .*_const (XIP), .*_data, .*_bss (RAM).
* Stacks sit above the RAM with 256-byte guard bands; NOINIT survives resets.
* 0x01C7FD50.. is reserved (boot info, mailbox, vector table). */
PROVIDE(op_guard_stack = 1); /* build.sh passes --defsym op_guard_stack=0 with OP_GUARD_STACK=0 */
MEMORY
{
XIP (rx) : ORIGIN = 0x02000120, LENGTH = 0x8DFBC
Expand All @@ -15,17 +17,22 @@ MEMORY
}
SECTIONS
{
.text : { KEEP(*(.text.crt0)) *(.text*) *(.rodata*) . = ALIGN(4); _etext = .; } > XIP
.text : { KEEP(*(.text.crt0)) *(.text*) *(.rodata*) *(.*_code) *(.*_const) . = ALIGN(4); _etext = .; } > XIP
.ram_text : { _rt_start = .; KEEP(*(.ram_text*))
. = ALIGN(4); _c1_start = .; KEEP(*(.c1_text*)) . = ALIGN(4); _c1_end = .; /* the second core's loop */
_rt_end = .; } > RAMTEXT AT > XIP
_rt_load = LOADADDR(.ram_text);
.data : { . = ALIGN(4); _data_start = .; *(.data*) *(.sdata*) . = ALIGN(4); _data_end = .; } > RAM AT > XIP
.data : { . = ALIGN(4); _data_start = .; *(.data*) *(.sdata*) *(.*_data) . = ALIGN(4); _data_end = .; } > RAM AT > XIP
_data_load = LOADADDR(.data);
.bss (NOLOAD) : { _bss_start = .; *(.bss*) *(.sbss*) *(COMMON) . = ALIGN(4); _bss_end = .; } > RAM
.bss (NOLOAD) : { _bss_start = .; _ble_stack_lo = .; *(.bss.ble_stack) _ble_stack_hi = .; *(.bss*) *(.sbss*) *(.*_bss) *(COMMON) . = ALIGN(4); _bss_end = .; } > RAM
.noinit (NOLOAD) : { *(.noinit*) } > NOINIT
.pool (NOLOAD) : { . = ALIGN(8); *(.pool*) } > POOL
_guard0 = 0x01C74000; _ustack_lo = 0x01C74100; _ustack_top = 0x01C7A000;
_guard1 = 0x01C7A000; _sstack_lo = 0x01C7A100; _sstack_top = 0x01C7C000;
/* The hardware stack guard (fm1_guard.h) faults any sp outside [_ustack_lo, _sstack_top]. The Bluetooth test image's task
* stacks (ble_os.c) are in RAM below that window, so it must be linked with op_guard_stack=0 (build.sh); with the guard on
* this link fails instead of the pedal crash-looping. Empty in the normal firmware. */
ASSERT(op_guard_stack == 0 || _ble_stack_lo == _ble_stack_hi || (_ble_stack_lo >= _ustack_lo && _ble_stack_hi <= _sstack_top),
"BLE task stacks lie outside the stack-guard window while the stack guard is enabled")
/DISCARD/ : { *(.comment) *(.note*) }
}
27 changes: 27 additions & 0 deletions firmware/ble/ble_adv.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-3.0-only OR MPL-2.0 */
/* The advertisement the Bluetooth test image sends, as the Bluetooth Core Specification wants it (Vol 3 Part C 11, Vol 6
* Part B 2.3, Vol 4 Part E 7.8.5-7.8.9). No hardware access: tests/test_ble_status.c checks it on the PC.
*
* PDU ADV_SCAN_IND: scannable, not connectable. Scan requests are answered; no connection is accepted.
* interval 0x00A0 x 0.625 ms = 100 ms (min = max). ADV_SCAN_IND needs at least 100 ms in Core 4.0 and 20 ms since 4.1.
* channels 37, 38, 39 (map 0x07). filter policy 0: scans from anybody.
* address the controller's public address slot (the library's own-address type is a build setting of its HCI layer,
* 0 = public, and cannot be changed from here). Left alone it is zero, which is not a valid device address;
* it is set to a fixed, non-zero, locally administered unicast address. Not an IEEE-assigned one: a test image.
* advertising data flags (LE general discoverable, BR/EDR not supported) + complete list of 128-bit service UUIDs
* (BLE-MIDI 03B80E5A-EDE8-4B33-A751-6CE34EC4C700, little endian): 21 of the 31 bytes
* scan response complete local name "OpenPocket-BLE-TEST": 21 bytes
* Transmit power is the library's own power table (no stored trims are read: docs/BLE-TEST.md). */
#pragma once
#include <stdint.h>

enum { BLE_ADV_SCAN_IND = 2, BLE_ADV_INTERVAL = 0x00A0, BLE_ADV_CHMAP = 7, BLE_ADV_FILTER = 0 };

static uint8_t ble_adv_data[] = {
2, 0x01, 0x06, /* flags: LE general discoverable, no BR/EDR */
17, 0x07, /* complete list of 128-bit service UUIDs, little endian */
0x00, 0xC7, 0xC4, 0x4E, 0xE3, 0x6C, 0x51, 0xA7, 0x33, 0x4B, 0xE8, 0xED, 0x5A, 0x0E, 0xB8, 0x03,
};
static uint8_t ble_scan_rsp[] = { 20, 0x09, 'O','p','e','n','P','o','c','k','e','t','-','B','L','E','-','T','E','S','T' };
static uint8_t ble_adv_mac[6] = { 0x54, 0x4C, 0x42, 0x50, 0x4F, 0x02 }; /* 02:4F:50:42:4C:54, little endian: bit 1 of the first octet = locally administered, bit 0 = unicast */
static uint8_t ble_no_addr[6]; /* direct address: unused by ADV_SCAN_IND, but the library reads six bytes */
60 changes: 60 additions & 0 deletions firmware/ble/ble_cfg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* SPDX-License-Identifier: Apache-2.0 */
/* Controller configuration for the advertise-only image: the values the JieLi SDK's own
* apps/common/config/log_config/lib_btctrler_config.c (fw-AC79_AIoT_SDK V1.2.0, Apache-2.0, see
* third_party/jieli-ble/) gives a Bluetooth LE only build, reduced to LE advertising and one slave link. The names and
* types are the library's; the values for features we do not build are the SDK's defaults. */
#include <stdint.h>

#define BIT(n) (1u << (n))
enum { BT_MODULE_CLASSIC = BIT(0), BT_MODULE_LE = BIT(1) };
enum { BT_NORMAL = 0x01 };
enum { LE_MASTER = BIT(0), LE_SLAVE = BIT(1), LE_ADV = BIT(2), LE_SCAN = BIT(3), LE_INIT = BIT(4) };

const int config_btctler_modules = BT_MODULE_LE;
int config_btctler_mode = BT_NORMAL;
int config_btctler_hci_standard = 0;
const int config_bt_function = 0;
const int config_btctler_le_tws = 0;
const int CONFIG_BTCTLER_TWS_ENABLE = 0;
const int CONFIG_TWS_AFH_ENABLE = 0;
const int CONFIG_WIFI_DETECT_ENABLE = 0;
const int ESCO_FORWARD_ENABLE = 0;
const int CONFIG_LOW_LATENCY_ENABLE = 0;
const int CONFIG_ESCO_MUX_RX_BULK_ENABLE = 0;
const int CONFIG_BTCTLER_FAST_CONNECT_ENABLE = 0;
const int CONFIG_LMP_NAME_REQ_ENABLE = 1;
const int CONFIG_LMP_PASSKEY_ENABLE = 1;
const int CONFIG_LMP_MASTER_ESCO_ENABLE = 1;
const int CONFIG_INQUIRY_PAGE_OFFSET_ADJUST = 0;
const int config_force_bt_pwr_tab_using_normal_level = 0; /* 0: the power table of each mode (the stock trims) */
unsigned char config_btctler_bredr_master = 0;
const int config_btctler_dual_a2dp = 0;
const int config_btctler_role_switch_fail_disconnect = 1;
const int config_btctler_role_switch_fail_back_to_slave = 0;
const int config_bredr_afh_user = 0;
const uint8_t rx_fre_offset_adjust_enable = 1;
const int config_fix_fre_enable = 0;
const int ble_disable_wait_enable = 1;
const int config_delete_link_key = 1;
const int config_btstask_auto_exit_sniff = 1;
const int CONFIG_TEST_DUT_CODE = 0;
const int CONFIG_TEST_FCC_CODE = 0;
const int CONFIG_TEST_DUT_ONLY_BOX_CODE = 0;
const int CONFIG_BREDR_INQUIRY = 0;

const uint64_t config_btctler_le_features = 0; /* no encryption: no connections in this image */
const int config_btctler_le_roles = LE_ADV | LE_SLAVE;
const int config_btctler_le_afh_en = 0;
const int config_btctler_le_hw_ram_use_static = 1;
const int config_btctler_le_master_multilink = 0;
const int config_multilink_support_esco_enalbe = 0;
const int config_btctler_le_slave_multilink = 1;
const int config_btctler_le_hw_nums = 1;
const int config_btctler_le_rx_nums = 5 * 1;
const int config_btctler_le_acl_packet_length = 27;
const int config_btctler_le_acl_total_nums = 5 * 1;
const uint32_t config_vendor_le_bb = 0;
const int config_btctler_le_slave_conn_update_winden = 2500;
const int config_btctler_single_carrier_en = 0;
const int sniff_support_reset_anchor_point = 0;
const int config_bt_security_vulnerability = 0;
29 changes: 29 additions & 0 deletions firmware/ble/ble_ctx.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* SPDX-License-Identifier: MPL-2.0 */
/* Context switch for the cooperative scheduler in ble_os.c. A task is suspended by pushing the registers a C call must
* preserve (rets and r4-r15: every register a compiled function saves, the list its own prologue pushes) on its own stack and storing the stack
* pointer; it is resumed by loading that pointer and popping the same list. Push and pop are the same instruction pair
* the compiler emits, so the order in memory does not matter.
*
* void ble_ctx_swap(uint32_t **save, uint32_t *load) suspend here into *save, resume the context in load
* void ble_ctx_enter(uint32_t **save, uint32_t *top, void (*fn)(void))
* suspend here into *save, call fn on the stack at top
* (fn never returns)
*/
.section .text.ble_ctx,"ax",@progbits
.balign 4
.globl ble_ctx_swap
ble_ctx_swap:
[--sp] = {rets, r15-r4}
r2 = sp
[r0 + 0] = r2
sp = r1
{pc, r15-r4} = [sp++]

.globl ble_ctx_enter
ble_ctx_enter:
[--sp] = {rets, r15-r4}
r3 = sp
[r0 + 0] = r3
sp = r1
call r2
goto .
29 changes: 29 additions & 0 deletions firmware/ble/ble_isr.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* SPDX-License-Identifier: MPL-2.0 */
/* The two baseband interrupts of the Bluetooth test image, counted. The library's own interrupt functions are complete
* interrupt entries (they save the registers and end in rti), so this cannot be a C function that calls them: it counts,
* restores the two registers it used and jumps to the library's function, which then runs as if it had been entered
* directly. The jump target is on the stack below the saved registers so that no register is left over. It uses add, load
* and store only (the compiler's own compares are fused with their branches), so the flags the library saves are those
* of the interrupted code.
*
* ble_isr_ev IRQ 45 counts ble_cnt_irq_ev, jumps to *ble_irq_target_ev
* ble_isr_rx IRQ 29 counts ble_cnt_irq_rx, jumps to *ble_irq_target_rx (ble_os.c request_irq sets them up) */
.macro BLE_ISR name, count, target
.section .text.\name,"ax",@progbits
.globl \name
\name:
sp += -4
[--sp] = {r1-r0}
r0 = \count
r1 = [r0+0]
r1 += 1
[r0+0] = r1
r0 = \target
r0 = [r0+0]
[sp+8] = r0
{r1-r0} = [sp++]
{pc} = [sp++]
.endm

BLE_ISR ble_isr_ev, ble_cnt_irq_ev, ble_irq_target_ev
BLE_ISR ble_isr_rx, ble_cnt_irq_rx, ble_irq_target_rx
27 changes: 27 additions & 0 deletions firmware/ble/ble_libc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-3.0-only OR MPL-2.0 */
/* The C library routines and diagnostics hooks the controller library calls and px_audio.h does not already supply
* (log_print, printf, config_asser, cpu_assert_debug, P33_SYSTEM_RESET, os_current_task_rom). Logging is switched off in
* the library by its log tags (ble_stubs.c), so the print functions here do nothing. */
#include <stdint.h>
#include <stddef.h>
#include "ble_os.h"

size_t strlen(const char *s) { const char *p = s; while (*p) p++; return (size_t)(p - s); }
int strcmp(const char *a, const char *b) { while (*a && *a == *b) { a++; b++; } return (uint8_t)*a - (uint8_t)*b; }
char *strcpy(char *d, const char *s) { char *r = d; while ((*d++ = *s++)) {} return r; }
char *strncpy(char *d, const char *s, size_t n) { size_t i = 0; for (; i < n && s[i]; i++) d[i] = s[i]; for (; i < n; i++) d[i] = 0; return d; }
void *memmove(void *d, const void *s, size_t n)
{
uint8_t *dp = d;
const uint8_t *sp = s;
if (dp < sp)
while (n--) *dp++ = *sp++;
else
for (dp += n, sp += n; n--;) *--dp = *--sp;
return d;
}

void printf_buf(const uint8_t *b, uint32_t n) { (void)b; (void)n; }
void put_buf(const uint8_t *b, uint32_t n) { (void)b; (void)n; }
int puts(const char *s) { (void)s; return 0; }
int putchar(int c) { return c; }
Loading
Loading