Compare commits

...

10 Commits

Author SHA1 Message Date
hueso
2bc8143045 4 brightness levels instead of 16 2026-02-17 02:41:37 -03:00
Puck Meerburg
b66cab7029 main: sleep instead of busy-loop 2026-02-08 00:04:14 +00:00
Puck Meerburg
63ec27d6e2 ble: add bonding support 2026-02-07 23:28:25 +00:00
Puck Meerburg
5b0b659002 Add screen (event/stack) abstraction 2026-02-07 22:54:19 +00:00
Puck Meerburg
decd87a456 usb: fix CDC-ACM descriptors
I should probably turn these into actual structs.
2026-02-06 23:54:59 +00:00
Puck Meerburg
57558522d2 Add initial bootloader skipping 2026-02-06 19:40:25 +00:00
Puck Meerburg
634ebad7cd Fix build warnings 2026-02-06 18:13:46 +00:00
Puck Meerburg
4eb0c6cdd2 menu/main: wire up multi-button handling 2026-02-06 18:13:46 +00:00
Puck Meerburg
b5fb2372fb input: wire up third and fourth buttons 2026-02-06 18:13:46 +00:00
Puck Meerburg
54e09bc059 input: move battery ADC call to timer call 2026-02-06 18:13:46 +00:00
17 changed files with 591 additions and 178 deletions

View File

@@ -6,10 +6,12 @@ SRCS := \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_pwr.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_sys.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_timer0.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_timer1.c \
CH5xx_ble_firmware_library/StdPeriphDriver/CH58x_timer3.c \
CH5xx_ble_firmware_library/RVMSIS/core_riscv.c \
CH5xx_ble_firmware_library/Startup/startup_CH583.S \
$(wildcard src/*.c) \
$(wildcard src/*.S) \
$(wildcard src/*/*.c)
@@ -50,7 +52,7 @@ LDFLAGS = -march=rv32imac -mabi=ilp32 -msmall-data-limit=8 \
-lc -lm -lnosys \
./CH5xx_ble_firmware_library/StdPeriphDriver/libISP583.a \
./CH5xx_ble_firmware_library/BLE/LIBCH58xBLE.a \
-T CH5xx_ble_firmware_library/Ld/Link.ld -nostartfiles -Xlinker --gc-sections
-T link.ld -nostartfiles -Xlinker --gc-sections
all: build/$(PLATFORM).bin

186
link.ld Normal file
View File

@@ -0,0 +1,186 @@
ENTRY( _bldr_start )
MEMORY
{
BLDRFLASH (rx) : ORIGIN = 0x00000000, LENGTH = 4K
FLASH (rx) : ORIGIN = 0x00001000, LENGTH = 444K
RAM (xrw) : ORIGIN = 0x20003800, LENGTH = 32K
}
SECTIONS
{
.bldr_init :
{
. = ALIGN(4);
KEEP(*(SORT_NONE(.bldr_init)))
. = ALIGN(4);
} >BLDRFLASH AT>BLDRFLASH
.init :
{
_sinit = .;
. = ALIGN(4);
KEEP(*(SORT_NONE(.init)))
. = ALIGN(4);
_einit = .;
} >FLASH AT>FLASH
/* .vector :
{
*(.vector);
} >FLASH AT>FLASH */
.highcodelalign :
{
. = ALIGN(4);
PROVIDE(_highcode_lma = .);
} >FLASH AT>FLASH
.highcode :
{
. = ALIGN(4);
PROVIDE(_highcode_vma_start = .);
*(.vector);
KEEP(*(SORT_NONE(.vector_handler)))
*(.highcode);
*(.highcode.*);
. = ALIGN(4);
PROVIDE(_highcode_vma_end = .);
} >RAM AT>FLASH
.text :
{
. = ALIGN(4);
KEEP(*(SORT_NONE(.handle_reset)))
*(.text)
*(.text.*)
*(.rodata)
*(.rodata*)
*(.sdata2.*)
*(.glue_7)
*(.glue_7t)
*(.gnu.linkonce.t.*)
. = ALIGN(4);
} >FLASH AT>FLASH
.fini :
{
KEEP(*(SORT_NONE(.fini)))
. = ALIGN(4);
} >FLASH AT>FLASH
PROVIDE( _etext = . );
PROVIDE( _eitcm = . );
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH AT>FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH AT>FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH AT>FLASH
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >FLASH AT>FLASH
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >FLASH AT>FLASH
.dalign :
{
. = ORIGIN(RAM) + MAX(0x800 , SIZEOF(.highcode));
} >RAM AT>FLASH
.dlalign :
{
. = ALIGN(4);
PROVIDE(_data_lma = .);
} >FLASH AT>FLASH
.data :
{
. = ALIGN(4);
PROVIDE(_data_vma = .);
*(.gnu.linkonce.r.*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
. = ALIGN(4);
PROVIDE( _edata = .);
} >RAM AT>FLASH
.bss :
{
. = ALIGN(4);
PROVIDE( _sbss = .);
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss*)
*(.gnu.linkonce.b.*)
*(COMMON*)
. = ALIGN(4);
PROVIDE( _ebss = .);
} >RAM AT>FLASH
PROVIDE( _end = _ebss);
PROVIDE( end = . );
.stack ORIGIN(RAM)+LENGTH(RAM) :
{
. = ALIGN(4);
PROVIDE(_eusrstack = . );
} >RAM
}

56
src/badge_screen.c Normal file
View File

@@ -0,0 +1,56 @@
#include <stdint.h>
#include "screen.h"
#include "led.h"
#include "wang.h"
#include "menu.h"
static uint16_t badge_fb[44];
int image_index = 0;
int frame = 0;
int subframe = 99999;
int anim_render(uint16_t *fb, int index, int frame);
static void badge_event(struct screen_event event) {
if (event.type == SE_TICK) {
if (!flash_header_valid) {
screen_push(&menu_screen);
return;
}
subframe++;
if (subframe > 33 && flash_header_valid) {
screen_dirty = 1;
subframe = 0;
if (anim_render(badge_fb, image_index, frame++)) {
frame = 0;
}
}
} else if (event.type == SE_BUTTON_PRESS) {
if (event.data == 0) {
display_brightness = (display_brightness + 1) % 4;
} else if (event.data == 1) {
if (flash_header_valid) {
image_index++;
if (!flash_header.widths[image_index]) image_index = 0;
frame = 0;
subframe = 99999;
}
}
} else if (event.type == SE_BUTTON_HOLD) {
if (event.data == 0) {
display_brightness = (display_brightness + 3) % 4;
screen_push(&menu_screen);
}
}
}
static void badge_draw(struct row_buf *buf) {
display_make_buf_all(badge_fb, buf);
}
struct screen badge_screen = {
badge_draw,
badge_event,
};

5
src/bldr.S Normal file
View File

@@ -0,0 +1,5 @@
.section .bldr_init,"ax",@progbits
.global _bldr_start
.align 1
_bldr_start:
j handle_reset

151
src/ble.c
View File

@@ -5,10 +5,70 @@
#include "CH58x_sys.h"
#include "CH58xBLE_LIB.h"
#include "led.h"
#include "screen.h"
#include "wang.h"
// Digits are from Spleen, under BSD-3-Clause.
const uint8_t digit_font[10 * 4] = {
0x1e,0x29,0x25,0x1e,
0x00,0x22,0x3f,0x20,
0x32,0x29,0x29,0x26,
0x12,0x21,0x25,0x1a,
0x0f,0x08,0x3e,0x08,
0x27,0x25,0x25,0x19,
0x1e,0x25,0x25,0x18,
0x03,0x31,0x09,0x07,
0x1a,0x25,0x25,0x1a,
0x06,0x29,0x29,0x1e
};
static const uint16_t magic = 0x201;
static const uint16_t magic2 = 0x1FE;
static uint32_t ble_pin = 0;
static void ble_popup_render(struct row_buf *buf) {
uint16_t fb[44] = {0};
int num = ble_pin;
fb[6] = magic2;
fb[7] = magic;
fb[37] = magic;
fb[38] = magic2;
for (int i = 5; i >= 0; i--) {
int x = 8 + (i * 5);
int digit = (num % 10);
for (int j = 0; j < 4; j++) {
fb[x + j] = magic | (((uint16_t) digit_font[digit * 4 + j]) << 2);
}
fb[x + 4] = magic;
num = num / 10;
}
display_make_buf_all(fb, buf);
}
static void ble_popup_event(struct screen_event event) {
if (event.type == SE_BUTTON_PRESS) {
screen_pop();
}
}
struct screen ble_screen = {
ble_popup_render,
ble_popup_event,
};
int ble_on = 0;
int ble_connected = 0;
// Whether the device is bonded or was previously bonded and recovered the keys successfully.
int ble_paired = 0;
void ble_toggle(void) {
uint8_t ble_mode = ble_on ? FALSE : TRUE;
GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(ble_mode), &ble_mode);
@@ -23,6 +83,27 @@ static void ble_calib_cb(void) {
Calibration_LSI(Level_128);
}
static void passcode_callback(uint8_t *device_addr, uint16_t handle, uint8_t uiInputs, uint8_t uiOutputs) {
ble_pin = tmos_rand() % 1000000;
screen_dirty = 1;
GAPBondMgr_PasscodeRsp(handle, SUCCESS, ble_pin);
}
static void pair_state_callback(uint16_t handle, uint8_t state, uint8_t status) {
if (state == GAPBOND_PAIRING_STATE_STARTED) {
screen_push(&ble_screen);
} else {
if (current_screen == &ble_screen) screen_pop();
}
if (status != SUCCESS) return;
if (state != GAPBOND_PAIRING_STATE_BONDED && state != GAPBOND_PAIRING_STATE_COMPLETE) return;
ble_paired = 1;
}
static uint8_t periph_task = INVALID_TASK_ID;
static uint16_t peripheral_task(uint8_t task_id, uint16_t events) {
@@ -41,7 +122,24 @@ static uint16_t peripheral_task(uint8_t task_id, uint16_t events) {
static void gap_onParamUpdate(uint16_t a, uint16_t b, uint16_t c, uint16_t d) {
}
static void gap_onStateChange(gapRole_States_t a, gapRoleEvent_t *b) {
static gapRole_States_t previous_state = GAPROLE_INIT;
static void gap_onStateChange(gapRole_States_t new_state, gapRoleEvent_t *event) {
if (previous_state == GAPROLE_CONNECTED && (new_state & GAPROLE_STATE_ADV_MASK) != GAPROLE_CONNECTED) {
ble_paired = 0;
ble_connected = 0;
}
if ((new_state & GAPROLE_STATE_ADV_MASK) == GAPROLE_ADVERTISING && event->gap.opcode == GAP_LINK_TERMINATED_EVENT) {
uint8_t ble_mode = TRUE;
GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(ble_mode), &ble_mode);
}
if (new_state == GAPROLE_CONNECTED) {
ble_connected = 1;
}
previous_state = new_state & GAPROLE_STATE_ADV_MASK;
}
uint8_t advertData[] = {
@@ -71,7 +169,7 @@ uint8_t scanRspData[31] = {
GAP_ADTYPE_LOCAL_NAME_COMPLETE,
'L', 'S', 'L', 'E', 'D', ' ', 'B', 'a', 'd', 'g', 'e', ' ', 'W', 'i', 't', 'c', 'h', 0,
0, 0, 0, 0,
0, 0,
};
static gapRolesBroadcasterCBs_t broadcast_handlers = {
@@ -85,30 +183,31 @@ static gapRolesCBs_t gap_handlers = {
};
static gapBondCBs_t bond_managers = {
0,
0,
passcode_callback,
pair_state_callback,
};
static const uint16_t service_uuid = 0xFEE0;
static const gattAttrType_t service = {2, (uint8_t *) &service_uuid};
static const uint8_t service_uuid[2] = {LO_UINT16(0xFEE0), HI_UINT16(0xFEE0)};
static const gattAttrType_t service = {2, service_uuid};
static const uint16_t rx_char_uuid = 0xFEE1;
static const uint8_t rx_char_uuid[2] = {LO_UINT16(0xFEE1), HI_UINT16(0xFEE1)};
static uint8_t rx_char_props = GATT_PROP_WRITE;
static uint8_t rx_char_val[16];
static gattAttribute_t attr_table[] = {
{{2, &primaryServiceUUID}, GATT_PERMIT_READ, 0, &service},
{{2, &characterUUID}, GATT_PERMIT_READ, 0, &rx_char_props},
{{2, &rx_char_uuid}, GATT_PERMIT_WRITE, 0, &rx_char_val},
{{2, primaryServiceUUID}, GATT_PERMIT_READ, 0, (uint8_t *)&service},
{{2, characterUUID}, GATT_PERMIT_READ, 0, &rx_char_props},
{{2, rx_char_uuid}, GATT_PERMIT_WRITE, 0, (uint8_t *)&rx_char_val},
};
uint16_t blefb[44] = {0};
static bStatus_t write_handler(uint16_t conn_handle, gattAttribute_t *pAttr, uint8_t *pValue, uint16_t len, uint16_t offset, uint8_t method) {
if (gattPermitAuthorWrite(pAttr->permissions)) return ATT_ERR_INSUFFICIENT_AUTHOR;
uint8_t bonded_count = 0;
GAPBondMgr_GetParameter(GAPBOND_BOND_COUNT, &bonded_count);
if (gattPermitAuthorWrite(pAttr->permissions) || (bonded_count && !ble_paired)) return ATT_ERR_INSUFFICIENT_AUTHOR;
uint16_t uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]);
if (uuid != rx_char_uuid) return ATT_ERR_ATTR_NOT_FOUND;
if (uuid != 0xFEE1) return ATT_ERR_ATTR_NOT_FOUND;
wang_rx(pValue, len);
@@ -121,6 +220,17 @@ static gattServiceCBs_t service_handlers = {
0,
};
uint32_t ble_read_flash(uint32_t addr, uint32_t num, uint32_t *buf) {
EEPROM_READ(addr, buf, num * 4);
return 0;
}
uint32_t ble_write_flash(uint32_t addr, uint32_t num, uint32_t *buf) {
EEPROM_ERASE(addr, num * 4);
EEPROM_WRITE(addr, buf, num * 4);
return 0;
}
void ble_init(void) {
bleConfig_t cfg = {0};
@@ -128,8 +238,11 @@ void ble_init(void) {
cfg.MEMAddr = (uint32_t) BLE_BUF;
cfg.MEMLen = (uint32_t) sizeof(BLE_BUF);
// not using the bonding information, as we do not support _bonding_.
// This should be changed. but. you know.
cfg.SNVAddr = (uint32_t) EEPROM_MAX_SIZE - 0x200;
cfg.SNVBlock = 256;
cfg.SNVNum = 1;
cfg.readFlashCB = ble_read_flash;
cfg.writeFlashCB = ble_write_flash;
// TODO: magic numbers
// amount of buffered packets
@@ -177,10 +290,10 @@ void ble_init(void) {
GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX, 200);
SET_PARAM(GAPBondMgr_SetParameter, GAPBOND_PERI_DEFAULT_PASSCODE, uint32_t, 0);
SET_PARAM(GAPBondMgr_SetParameter, GAPBOND_PERI_PAIRING_MODE, uint8_t, GAPBOND_PAIRING_MODE_NO_PAIRING);
SET_PARAM(GAPBondMgr_SetParameter, GAPBOND_PERI_MITM_PROTECTION, uint8_t, FALSE);
SET_PARAM(GAPBondMgr_SetParameter, GAPBOND_PERI_PAIRING_MODE, uint8_t, GAPBOND_PAIRING_MODE_WAIT_FOR_REQ);
SET_PARAM(GAPBondMgr_SetParameter, GAPBOND_PERI_MITM_PROTECTION, uint8_t, TRUE);
SET_PARAM(GAPBondMgr_SetParameter, GAPBOND_PERI_IO_CAPABILITIES, uint8_t, GAPBOND_IO_CAP_DISPLAY_ONLY);
SET_PARAM(GAPBondMgr_SetParameter, GAPBOND_PERI_BONDING_ENABLED, uint8_t, FALSE);
SET_PARAM(GAPBondMgr_SetParameter, GAPBOND_PERI_BONDING_ENABLED, uint8_t, TRUE);
GAPRole_BroadcasterSetCB(&broadcast_handlers);

View File

@@ -5,9 +5,13 @@
#include "CH58x_sys.h"
#include "CH58xBLE_LIB.h"
#include "platform.h"
volatile int button_count[2] = {15, 0};
volatile int button_pressed[2] = {1, 0};
uint16_t last_battery_value[24] = {0};
uint16_t last_battery_index = 0;
volatile int button_count[BUTTON_COUNT] = {15, 0};
volatile int button_pressed[BUTTON_COUNT] = {1, 0};
static void handle_button(int i, int state) {
if (state && button_count[i] < 16) button_count[i]++;
@@ -20,10 +24,21 @@ static void handle_button(int i, int state) {
__INTERRUPT
__HIGH_CODE
void TMR3_IRQHandler(void) {
TMR3_ClearITFlag(TMR0_3_IT_CYC_END);
handle_button(0, !!GPIOA_ReadPortPin(GPIO_Pin_1));
handle_button(1, !GPIOB_ReadPortPin(GPIO_Pin_22));
TMR3_ClearITFlag(TMR0_3_IT_CYC_END);
ADC_ChannelCfg(1);
last_battery_value[last_battery_index++] = ADC_ExcutSingleConver();
if (last_battery_index >= 24) last_battery_index = 0;
#if BUTTON_COUNT == 4
ADC_ChannelCfg(3);
uint16_t aux_button_value = ADC_ExcutSingleConver();
handle_button(3, (aux_button_value < 0xf00) && (aux_button_value > 0x400));
handle_button(2, aux_button_value < 0x100);
#endif
}
void button_init(void)
@@ -46,13 +61,17 @@ void button_init(void)
ADC_ChannelCfg(1);
GPIOA_ModeCfg(GPIO_Pin_0, GPIO_ModeIN_PU);
GPIOA_ModeCfg(GPIO_Pin_2, GPIO_ModeIN_PD);
#if BUTTON_COUNT == 4
GPIOA_ModeCfg(GPIO_Pin_13, GPIO_ModeIN_Floating);
#endif
}
int get_battery_percentage(void) {
uint32_t adc = 0;
for (int i = 0; i < 24; i++) {
adc += ADC_ExcutSingleConver();
adc += last_battery_value[i];
}
adc /= 24;

View File

@@ -1,7 +1,9 @@
#pragma once
#include "platform.h"
void button_init(void);
extern volatile int button_pressed[2];
extern volatile int button_pressed[BUTTON_COUNT];
int get_battery_percentage(void);
int is_charging(void);

View File

@@ -137,9 +137,6 @@ struct row_buf *display_screen = display_screens;
static struct row_buf *display_screen_render = display_screens + 22;
void display_flip(void) {
struct row_buf *new_render = display_screen == display_screens ? (display_screens + 22) : display_screens;
struct row_buf *old_render = display_screen;
__atomic_exchange(&display_screen, &display_screen_render, &display_screen_render, __ATOMIC_RELAXED);
}
@@ -163,7 +160,7 @@ void TMR0_IRQHandler(void)
}
}
if (cur_bness > display_brightness) {
if ( cur_bness+2 > 1 << 1 << display_brightness ) { // sorry I don't know how to make this nicer
display_commit(&blank);
} else {
display_commit(display_screen_render + cur_index);

View File

@@ -1,5 +1,7 @@
#pragma once
#include <stdint.h>
extern uint32_t pa_mask;
extern uint32_t pb_mask;

View File

@@ -6,13 +6,13 @@
#include "CH58xBLE_LIB.h"
#include "usb/core.h"
#include "led.h"
#include "button.h"
#include "input.h"
#include "menu.h"
#include "ble.h"
#include "cdc.h"
#include "wang.h"
int anim_render(uint16_t *fb, int index, int frame);
#include "platform.h"
#include "screen.h"
enum usb_control_resp bl_handler(enum usb_control_state state) {
if ((usb_control_request.bmRequestType & 0x7f) != 0x43) return USB_CONTROL_RESP_PASS;
@@ -25,63 +25,10 @@ enum usb_control_resp bl_handler(enum usb_control_state state) {
}
int btn1_was_pressed = 1;
int btn2_was_pressed = 0;
int btn1_hold = 0;
int btn2_hold = 0;
static int button_was_pressed[BUTTON_COUNT] = {0};
static int button_hold[BUTTON_COUNT] = {0};
int image_index = 0;
int frame = 0;
int subframe = 99999;
int main_handler(void) {
#define TIMER(btn0, btn1, v, count) if (button_pressed[0] != btn0 || button_pressed[1] != btn1) { v = 0; } else if (v < count) { v += 1; } else
static int menu_timer = 0;
TIMER(1, 0, menu_timer, 500) {
display_brightness = (display_brightness + 15) % 16;
menu_timer = 0;
menu_switch();
return 1;
}
if (button_pressed[0] && !btn1_was_pressed) {
display_brightness = (display_brightness + 1) % 16;
}
if (button_pressed[1] && !btn2_was_pressed) {
if (flash_header_valid) {
image_index++;
if (!flash_header.widths[image_index]) image_index = 0;
frame = 0;
subframe = 99999;
}
display_flip();
}
subframe++;
if (subframe > 33 && flash_header_valid) {
// approximately 30fps
subframe = 0;
uint16_t fb[44];
if (anim_render(fb, image_index, frame)) {
frame = 0;
} else {
frame++;
}
display_make_buf_all(fb, display_screen);
display_flip();
}
btn2_was_pressed = button_pressed[1];
btn1_was_pressed = button_pressed[0];
if (!flash_header_valid) return 1;
return 0;
}
extern struct screen badge_screen;
int main()
{
@@ -98,18 +45,25 @@ int main()
TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END);
PFIC_EnableIRQ(TMR0_IRQn);
TMR1_TimerInit((FREQ_SYS / 1000));
TMR1_ITCfg(ENABLE, TMR0_3_IT_CYC_END);
TMR3_TimerInit(FREQ_SYS / 200);
TMR3_ITCfg(ENABLE, TMR0_3_IT_CYC_END);
PFIC_EnableIRQ(TMR3_IRQn);
wang_init();
main_handler();
usb_register_handler(bl_handler);
usb_init();
ble_init();
screen_push(&badge_screen);
// set SEVONPEND
PFIC->SCTLR |= (1 << 4);
while (1) {
WWDG_SetCounter(0x7F);
static int btldr_timer = 0;
@@ -120,20 +74,51 @@ int main()
btldr_timer = 0;
}
static int cur_handler = 0;
if (cur_handler) {
cur_handler = menu_handler();
if (!cur_handler) {
btn2_was_pressed = button_pressed[1];
btn1_was_pressed = button_pressed[0];
subframe = 99999;
struct screen_event ev = {
SE_TICK,
0
};
current_screen->event_handler(ev);
for (int i = 0; i < BUTTON_COUNT; i++) {
int is_pressed = button_pressed[i];
if (button_was_pressed[i] && is_pressed) {
button_hold[i]++;
if (button_hold[i] == 500) {
ev.type = SE_BUTTON_HOLD;
ev.data = i;
current_screen->event_handler(ev);
} else if (button_hold[i] > 500) {
button_hold[i] = 501;
}
} else if (is_pressed && !button_was_pressed[i]) {
ev.type = SE_BUTTON_PRESS;
ev.data = i;
current_screen->event_handler(ev);
button_was_pressed[i] = 1;
button_hold[i] = 0;
} else if (!is_pressed && button_was_pressed[i]) {
ev.type = button_hold[i] >= 500 ? SE_BUTTON_RELEASE_HOLD : SE_BUTTON_RELEASE_SHORT;
ev.data = i;
current_screen->event_handler(ev);
button_was_pressed[i] = 0;
}
} else
cur_handler = main_handler();
}
if (screen_dirty) {
screen_dirty = 0;
current_screen->draw_handler(display_screen);
display_flip();
}
TMOS_SystemProcess();
cdc_tick();
hid_tick();
DelayMs(1);
while (!TMR1_GetITFlag(TMR0_3_IT_CYC_END)) {
__SEV();
__asm__ volatile("wfi");
}
TMR1_ClearITFlag(TMR0_3_IT_CYC_END);
}
}

View File

@@ -7,8 +7,9 @@
#include "usb/core.h"
#include "led.h"
#include "ble.h"
#include "button.h"
#include "input.h"
#include "wang.h"
#include "screen.h"
#include "img/menu.xbm"
@@ -38,7 +39,7 @@ static void boop()
LowPower_Shutdown(0);
}
static void render_xbm(unsigned char *bits, struct row_buf *b) {
static void render_xbm(uint8_t *bits, struct row_buf *b) {
uint16_t fb[45] = {0};
int index = 0;
for (int j = 0; j < 11; j++) {
@@ -53,13 +54,34 @@ static void render_xbm(unsigned char *bits, struct row_buf *b) {
display_make_buf_all(fb, b);
}
int menu_index = 0;
static int menu_index = 0;
static int btn0_pressed = 0;
static int btn1_pressed = 0;
void menu_render(void) {
char buffer[(48 * 11) / 8];
static int menu_ticks = 0;
static void menu_event(struct screen_event event) {
if (event.type == SE_TICK) {
if (menu_ticks++ > 125) {
screen_dirty = 1;
}
} else if (event.type == SE_BUTTON_PRESS) {
if (event.data == 0) {
menu_index = (menu_index + 1) % 3;
if (!flash_header_valid && !menu_index) menu_index = 1;
screen_dirty = 1;
} else if (event.data == 1) {
if (menu_index == 0) {
screen_pop();
return;
} else if (menu_index == 1) {
ble_toggle();
screen_dirty = 1;
} else if (menu_index == 2) {
boop();
}
}
}
}
static void menu_draw(struct row_buf *rb) {
uint8_t buffer[(48 * 11) / 8];
memcpy(buffer, menu_bits, sizeof(buffer));
int invert_index = 1 + menu_index * 13;
for (int i = invert_index; i < (invert_index + 9); i++) {
@@ -99,57 +121,11 @@ void menu_render(void) {
}
}
render_xbm(buffer, display_screen);
display_flip();
}
void menu_switch(void) {
btn0_pressed = button_pressed[0];
btn1_pressed = button_pressed[1];
menu_index = flash_header_valid ? 0 : 1;
menu_render();
}
int menu_handler(void) {
static int btldr_timer = 0;
static int render_ticks = 0;
render_ticks++;
if (button_pressed[1] && button_pressed[0]) {
btldr_timer++;
if (btldr_timer > 2000) asm volatile("j 0x00");
} else {
btldr_timer = 0;
}
if (button_pressed[0] && !btn0_pressed && !button_pressed[1]) {
menu_index = (menu_index + 1) % 3;
if (!flash_header_valid && !menu_index) menu_index = 1;
menu_render();
render_ticks = 0;
}
if (button_pressed[1] && !btn1_pressed && !button_pressed[0]) {
if (menu_index == 0) {
return 0;
} else if (menu_index == 1) {
ble_toggle();
menu_render();
render_ticks = 0;
} else if (menu_index == 2) {
boop();
}
}
if (render_ticks > 125) {
render_ticks = 0;
menu_render();
}
btn0_pressed = button_pressed[0];
btn1_pressed = button_pressed[1];
return 1;
render_xbm(buffer, rb);
menu_ticks = 0;
}
struct screen menu_screen = {
menu_draw,
menu_event,
};

View File

@@ -1,4 +1,5 @@
#pragma once
void menu_switch(void);
int menu_handler(void);
#include "screen.h"
extern struct screen menu_screen;

36
src/screen.c Normal file
View File

@@ -0,0 +1,36 @@
#include "screen.h"
static void blank_draw_handler(struct row_buf *buf) {
}
static void blank_event_handler(struct screen_event event) {
}
static struct screen blank_screen = {
blank_draw_handler,
blank_event_handler,
};
struct screen *current_screen = &blank_screen;
static struct screen *screen_stack[4] = {0};
static int screen_stack_idx = 0;
void screen_push(struct screen *screen) {
screen_stack[screen_stack_idx++] = current_screen;
current_screen = screen;
screen_dirty = 1;
}
void screen_replace(struct screen *screen) {
current_screen = screen;
}
void screen_pop() {
if (screen_stack_idx == 0) {
current_screen = &blank_screen;
} else {
current_screen = screen_stack[--screen_stack_idx];
}
}
int screen_dirty = 0;

31
src/screen.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#include "led.h"
enum screen_event_type {
SE_TICK = 0,
SE_BUTTON_PRESS = 1,
SE_BUTTON_RELEASE_SHORT = 2,
SE_BUTTON_HOLD = 3,
SE_BUTTON_RELEASE_HOLD = 4,
};
struct screen_event {
enum screen_event_type type;
uint8_t data;
};
typedef void (*screen_draw)(struct row_buf *);
typedef void (*screen_event)(struct screen_event);
struct screen {
screen_draw draw_handler;
screen_event event_handler;
};
void screen_push(struct screen *);
void screen_replace(struct screen *);
void screen_pop();
extern struct screen *current_screen;
extern int screen_dirty;

View File

@@ -135,13 +135,13 @@ void usb_init() {
R8_USB_DEV_AD = 0x00;
R8_USB_INT_FG = 0xFF;
R16_UEP0_DMA = ep04_buf;
R16_UEP1_DMA = epbuf + 0 * 128;
R16_UEP2_DMA = epbuf + 1 * 128;
R16_UEP3_DMA = epbuf + 2 * 128;
R16_UEP5_DMA = epbuf + 3 * 128;
R16_UEP6_DMA = epbuf + 4 * 128;
R16_UEP7_DMA = epbuf + 5 * 128;
R16_UEP0_DMA = (uint16_t) (uintptr_t) ep04_buf;
R16_UEP1_DMA = (uint16_t) (uintptr_t) (epbuf + 0 * 128);
R16_UEP2_DMA = (uint16_t) (uintptr_t) (epbuf + 1 * 128);
R16_UEP3_DMA = (uint16_t) (uintptr_t) (epbuf + 2 * 128);
R16_UEP5_DMA = (uint16_t) (uintptr_t) (epbuf + 3 * 128);
R16_UEP6_DMA = (uint16_t) (uintptr_t) (epbuf + 4 * 128);
R16_UEP7_DMA = (uint16_t) (uintptr_t) (epbuf + 5 * 128);
for (int i = 0; i < 8; i++) {
set_endpoint_state(i, USB_EP_STATE_NAK);
@@ -203,7 +203,7 @@ int16_t usb_recv(uint8_t endpoint, void *buffer, size_t buflen) {
recvlens[endpoint] = 0xFF;
memcpy(buffer, buf_for_ep(endpoint, 0), buflen);
memcpy(buffer, (uint8_t *)buf_for_ep(endpoint, 0), buflen);
return buflen;
}
@@ -216,7 +216,7 @@ int16_t usb_xmit(uint8_t endpoint, void *buffer, size_t buflen) {
if (buflen > 64) buflen = 64;
memcpy(buf_for_ep(endpoint, 1), buffer, buflen);
memcpy((uint8_t *)buf_for_ep(endpoint, 1), buffer, buflen);
*ep_t_len_regs[endpoint] = buflen;
set_endpoint_state(endpoint | 0x80, USB_EP_STATE_ACK);

View File

@@ -112,7 +112,7 @@ uint8_t config_descriptor[0x6b] = {
0x24, // bDescriptorType
0x01, // bDescriptorSubtype
0x00, // bmCapabilities
0x01, // bDataInterface
0x02, // bDataInterface
// ACM descripotor
0x04, // bLength
@@ -124,8 +124,8 @@ uint8_t config_descriptor[0x6b] = {
0x05, // bLength
0x24, // bDescriptorType
0x06, // bDescriptorSubtype
0x00, // bMasterInterface
0x01, // bSlaveInterface0
0x01, // bMasterInterface
0x02, // bSlaveInterface0
0x07, // bLength
0x05, // bDescriptorType
@@ -189,7 +189,7 @@ static enum usb_control_resp handle_hid_request(enum usb_control_state state) {
__HIGH_CODE
static enum usb_control_resp handle_main_request(enum usb_control_state state) {
if (usb_control_request.bmRequestType & 0x7F != 0x00) return USB_CONTROL_RESP_PASS;
if ((usb_control_request.bmRequestType & 0x7F) != 0x00) return USB_CONTROL_RESP_PASS;
switch (usb_control_request.bRequest) {
case 0: // GET_STATUS
@@ -291,7 +291,7 @@ void handle_ctrl_transfer(int is_in) {
// DMA.
if (control_transfer_len > 0) {
memcpy(ep04_buf, control_transfer_buf, control_transfer_len > 64 ? 64 : control_transfer_len);
memcpy((uint8_t *)ep04_buf, control_transfer_buf, control_transfer_len > 64 ? 64 : control_transfer_len);
R8_UEP0_T_LEN = control_transfer_len > 64 ? 64 : control_transfer_len;
set_endpoint_state(0x80, USB_EP_STATE_ACK);
} else {
@@ -306,7 +306,7 @@ void handle_ctrl_transfer(int is_in) {
}
control_transfer_len -= ack_bytes;
memcpy(control_transfer_buf, ep04_buf, ack_bytes);
memcpy(control_transfer_buf, (uint8_t *)ep04_buf, ack_bytes);
control_transfer_buf += ack_bytes;
if (control_transfer_len > 0) {
@@ -323,7 +323,7 @@ void handle_ctrl_transfer(int is_in) {
__HIGH_CODE
void handle_setup_request() {
// Copy the setup request from the EP0 buffer.
memcpy(&usb_control_request, ep04_buf, 8);
memcpy(&usb_control_request, (uint8_t *)ep04_buf, 8);
// We don't expect the previous request to be driven anymore.
// Reset the control transfer.
@@ -352,7 +352,7 @@ void handle_setup_request() {
if (ctrlreq_type() != USB_CONTROL_REQUEST_TYPE_OUT) {
int mlen = control_transfer_len;
if (mlen > 64) mlen = 64;
memcpy(ep04_buf, control_transfer_buf, mlen);
memcpy((uint8_t *)ep04_buf, control_transfer_buf, mlen);
R8_UEP0_T_LEN = mlen;
set_endpoint_state(0x80, USB_EP_STATE_ACK);
} else {

View File

@@ -1,5 +1,7 @@
#pragma once
#include "led.h"
struct wang_header {
// First 16-byte chunk
uint8_t magic[6]; // "wang\0\0"