mirror of
https://codeberg.org/SiB64/turbo_weather.git
synced 2026-05-01 15:14:22 +02:00
Compare commits
2 commits
f0945b9227
...
65d615407c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65d615407c | ||
|
|
bd0238bb2d |
7 changed files with 136 additions and 128 deletions
|
|
@ -89,7 +89,7 @@ base85_encode:
|
|||
.global mul85
|
||||
mul85:
|
||||
# endif
|
||||
|
||||
;; TODO for SPACE: inline this
|
||||
_mul85:
|
||||
ldi r21, 85
|
||||
mul r25, r21
|
||||
|
|
|
|||
168
src/cmd.c
168
src/cmd.c
|
|
@ -11,14 +11,7 @@
|
|||
#include "pipe.h"
|
||||
|
||||
uint8_t cmd_buffer[16];
|
||||
uint8_t cmd_buffer_valid;
|
||||
|
||||
static __attribute__((noinline))
|
||||
const uint8_t *skip_space(const uint8_t *s) {
|
||||
if (*s == ' ')
|
||||
s++;
|
||||
return s;
|
||||
}
|
||||
uint8_t flash_buffer_valid;
|
||||
|
||||
uint8_t base85_str[6];
|
||||
#if 0
|
||||
|
|
@ -69,23 +62,11 @@ void base85_send_buffer(const uint8_t *buf)
|
|||
static inline
|
||||
const uint8_t *base85_fill_buffer(const uint8_t *s) {
|
||||
base85_error = 0;
|
||||
s = skip_space(s);
|
||||
for (int i=0; !base85_error && i<FB_SIZE; i+=4)
|
||||
s = base85_decode(s, (uint32_t *)(cmd_buffer + i));
|
||||
s = skip_space(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline
|
||||
void bch4369_feed_buffer(uint8_t flag)
|
||||
{
|
||||
if (flag=='0') {
|
||||
memset(bch_parity, 0, 16);
|
||||
}
|
||||
bch4369_str(cmd_buffer,16);
|
||||
}
|
||||
|
||||
|
||||
uint8_t * poke_addr;
|
||||
uint8_t peek_size;
|
||||
struct peak_poke {
|
||||
|
|
@ -132,95 +113,122 @@ uint8_t poke(struct peak_poke *p, uint8_t hp, uint8_t poke)
|
|||
return s && !poke;
|
||||
}
|
||||
|
||||
const uint8_t *cmd_flags;
|
||||
#if 0
|
||||
static __attribute__((noinline))
|
||||
uint8_t cmd_flag(uint8_t f)
|
||||
{
|
||||
if (*cmd_flags == f) {
|
||||
cmd_flags++;
|
||||
send_char(f);
|
||||
return f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static __attribute__((noinline, naked))
|
||||
uint8_t cmd_flag(uint8_t f)
|
||||
{
|
||||
// _send_char22 does not gobble r24.
|
||||
__asm__(
|
||||
""
|
||||
"lds r30, cmd_flags" "\n\t"
|
||||
"lds r31, cmd_flags+1" "\n\t"
|
||||
"ld r22, Z+" "\n\t"
|
||||
"cp r22, r24" "\n\t"
|
||||
"mov r24, r1" "\n\t"
|
||||
"brne 9f" "\n\t"
|
||||
"mov r24, r22" "\n\t"
|
||||
"sts cmd_flags, r30" "\n\t"
|
||||
"sts cmd_flags+1, r31" "\n\t"
|
||||
"rcall _send_char22" "\n"
|
||||
"9:" "\n\t"
|
||||
"ret" "\n"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
void parse_command(const uint8_t *s, uint8_t n)
|
||||
{
|
||||
// ^[A-Z][!-@]+( [!-u]{20}])?$
|
||||
// cmd flags base85
|
||||
|
||||
uint8_t r = 0;
|
||||
uint8_t cmd = *s++;
|
||||
if (*s =='`')
|
||||
if (cmd < 'A' || cmd > 'Z')
|
||||
return;
|
||||
uint8_t r = 0x08|cmd;
|
||||
send_char('`');
|
||||
send_char('#');
|
||||
send_char(cmd);
|
||||
uint8_t have_b = !(cmd & 0x20);
|
||||
cmd |= 0x20;
|
||||
if (cmd > 'z')
|
||||
goto error;
|
||||
if (have_b) {
|
||||
s = base85_fill_buffer(s);
|
||||
uint8_t bflg = *s - '0';
|
||||
uint8_t *bptr = cmd_buffer;
|
||||
if (bflg <= 5) {
|
||||
bptr = flash_buffer + 16*bflg;
|
||||
bflg = 1<<bflg;
|
||||
s++;
|
||||
}
|
||||
else
|
||||
bflg = 0;
|
||||
cmd_flags = s;
|
||||
while (*s > ' ' && *s < 'A')
|
||||
s++;
|
||||
uint8_t have_b = 0;
|
||||
if (*s==' ') {
|
||||
s = base85_fill_buffer(s+1);
|
||||
if (base85_error) {
|
||||
r = base85_error;
|
||||
goto error;
|
||||
}
|
||||
cmd_buffer_valid |= 0x80;
|
||||
have_b = 1;
|
||||
}
|
||||
s = skip_space(s);
|
||||
uint8_t flag = *s++;
|
||||
if (*s != '\n')
|
||||
goto error;
|
||||
switch(cmd) {
|
||||
case 'a':
|
||||
case 'A':
|
||||
r = adc_current;
|
||||
if (r >= N_ADC) {
|
||||
if (flag=='=') {
|
||||
memcpy(cmd_buffer, adc_readings, 16);
|
||||
cmd_buffer_valid |= 0x40;
|
||||
flag = *s++;
|
||||
}
|
||||
if (flag == '<') {
|
||||
if (cmd_flag('<'))
|
||||
base85_send_buffer((void*)adc_readings);
|
||||
flag = *s++;
|
||||
}
|
||||
if (flag == '+')
|
||||
if (cmd_flag('!'))
|
||||
start_adc();
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
r = cmd_buffer_valid;
|
||||
if (have_b) {
|
||||
flag -= '0';
|
||||
if (flag < 5 && flag==cmd_buffer_valid) {
|
||||
memcpy(flash_buffer+16*flag, cmd_buffer, 16);
|
||||
r = cmd_buffer_valid |= 1<<flag;
|
||||
flag = *++s;
|
||||
case 'B':
|
||||
if (have_b && bflg) {
|
||||
if (cmd_flag('|'))
|
||||
flash_buffer_valid |= bflg;
|
||||
memcpy(bptr, cmd_buffer, 16);
|
||||
}
|
||||
if (cmd_flag('%')) {
|
||||
if (cmd_flag('!'))
|
||||
memset(bch_parity, 0, 16);
|
||||
bch4369_str(bptr, 16);
|
||||
}
|
||||
if (flag == '%') {
|
||||
if (*s=='<')
|
||||
base85_send_buffer(bch_parity);
|
||||
if (cmd_flag('<')) {
|
||||
if (cmd_flag('|'))
|
||||
flash_buffer_valid &=~ bflg;
|
||||
base85_send_buffer(bptr);
|
||||
}
|
||||
r = flash_buffer_valid;
|
||||
break;
|
||||
case 'F':
|
||||
if (have_b)
|
||||
bch4369_feed_buffer(*++s);
|
||||
}
|
||||
else if (flag == '<') {
|
||||
flag = *s - '0';
|
||||
uint8_t *b;
|
||||
if (flag < 5)
|
||||
b = flash_buffer + 16*flag;
|
||||
else {
|
||||
b = cmd_buffer;
|
||||
}
|
||||
base85_send_buffer(b);
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
if (have_b) {
|
||||
r = flash_submit_command(cmd_buffer);
|
||||
cmd_buffer_valid &=~ 0x80;
|
||||
}
|
||||
else
|
||||
r = flash_poll(flag=='!');
|
||||
r = flash_poll(cmd_flag('!'));
|
||||
break;
|
||||
case 'p':
|
||||
if (have_b) {
|
||||
r = pipe_config(cmd_buffer, flag);
|
||||
cmd_buffer_valid &= ~0x80;
|
||||
}
|
||||
case 'P':
|
||||
if (have_b)
|
||||
r = pipe_config(cmd_buffer);
|
||||
else
|
||||
r = pipe_poll(flag=='!');
|
||||
r = pipe_poll(cmd_flag('!'));
|
||||
break;
|
||||
case 'm':
|
||||
if (poke((void*)cmd_buffer, have_b, have_b && flag=='!'))
|
||||
case 'M':
|
||||
if (poke((void*)cmd_buffer, have_b, have_b && cmd_flag('!')))
|
||||
base85_send_buffer(cmd_buffer);
|
||||
break;
|
||||
default:
|
||||
error:
|
||||
send_char('?');
|
||||
}
|
||||
send_hex_byte_eol(r);
|
||||
}
|
||||
|
||||
|
|
|
|||
13
src/flash.c
13
src/flash.c
|
|
@ -264,12 +264,6 @@ void bch_flash_init()
|
|||
uint8_t flash_poll(uint8_t rr)
|
||||
{
|
||||
uint8_t r = fs.status;
|
||||
if (spi_busy_p()) {
|
||||
if (rr)
|
||||
goto collision;
|
||||
fs.status = r | FS_Busy;
|
||||
return r;
|
||||
}
|
||||
if ((r & FS_Error) == FS_Error)
|
||||
return r;
|
||||
if (r & FS_StBsy) {
|
||||
|
|
@ -285,7 +279,6 @@ uint8_t flash_poll(uint8_t rr)
|
|||
if (!(r & FS_Busy))
|
||||
goto ready;
|
||||
if (rr) {
|
||||
collision:
|
||||
r |= FS_Error;
|
||||
fs.status = r;
|
||||
return r;
|
||||
|
|
@ -311,11 +304,12 @@ uint8_t flash_poll(uint8_t rr)
|
|||
}
|
||||
|
||||
ready:
|
||||
r &= ~(FS_Busy | FS_StBsy);
|
||||
if (rr)
|
||||
r |= FS_Ack;
|
||||
// clear the Bsy bits
|
||||
r &= ~(FS_Busy | FS_StBsy);
|
||||
fs.status = r;
|
||||
if (spi_busy_p())
|
||||
return r;
|
||||
if (r & FS_Dir == FS_Write && fs.block == 8)
|
||||
flash_burn_page();
|
||||
else if (!flash_stream_done()) {
|
||||
|
|
@ -331,6 +325,7 @@ ready:
|
|||
}
|
||||
else if (r & FS_Dir == FS_Erase)
|
||||
flash_erase_next_page();
|
||||
fs.status &=~ FS_Ack;
|
||||
}
|
||||
return fs.status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
#include <pipe.h>
|
||||
#include "pipe.h"
|
||||
#include "flash.h"
|
||||
|
||||
struct pipe pipe;
|
||||
|
||||
|
|
@ -11,12 +12,15 @@ struct pipe_config {
|
|||
uint8_t flash_page;
|
||||
};
|
||||
|
||||
uint8_t pipe_config(const uint8_t *, uint8_t flag)
|
||||
uint8_t pipe_config(const uint8_t *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint8_t pipe_poll(uint8_t flag)
|
||||
{
|
||||
uint8_t r = pipe.status;
|
||||
if (spi_busy_p() || flash_poll(0) & FS_Busy)
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t pipe_config(const uint8_t *, uint8_t flag);
|
||||
uint8_t pipe_config(const uint8_t *);
|
||||
uint8_t pipe_poll(uint8_t flag);
|
||||
|
||||
enum pipe_ports {
|
||||
|
|
|
|||
11
src/uart.c
11
src/uart.c
|
|
@ -51,7 +51,7 @@ ISR(USART0_DRE_vect)
|
|||
|
||||
#else
|
||||
|
||||
__attribute__ ((noinline, noclone))
|
||||
__attribute__ ((noinline, naked))
|
||||
void tx()
|
||||
{
|
||||
// This uses only three registers, to save stack in the ISR.
|
||||
|
|
@ -76,13 +76,13 @@ void tx()
|
|||
" lds r31, uart_tx_w \n"
|
||||
" cp r30, r31 \n"
|
||||
" breq 3f \n"
|
||||
" lds r30, %[STATUS] \n"
|
||||
" sbrc r30, %[DRE] \n"
|
||||
" lds r31, %[STATUS] \n"
|
||||
" sbrc r31, %[DRE] \n"
|
||||
" rjmp 1b \n"
|
||||
" ori r25, 1<<%[DRE] \n"
|
||||
"3: \n"
|
||||
" sts %[CTRLA], r25 \n"
|
||||
" sts uart_tx_r, r21 \n"
|
||||
" ret \n"
|
||||
:
|
||||
:
|
||||
[TXC] "n" (USART_TXCIF_bp),
|
||||
|
|
@ -96,8 +96,7 @@ void tx()
|
|||
|
||||
ISR(USART0_DRE_vect, ISR_NAKED)
|
||||
{
|
||||
// Doing this naked is a bit dangerous,
|
||||
// but saves five instructions and two bytes stack (r0, r1).
|
||||
// This saves five instructions and two bytes stack (r0, r1).
|
||||
// OTOH, the C implementation of tx() is not bad either,
|
||||
// if we are doing this asm, then we do it agressively.
|
||||
__asm__("\n"
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
.global send_hex_byte
|
||||
.global send_hex_byte_eol
|
||||
.global send_char
|
||||
.global _send_char22
|
||||
.global send_str
|
||||
.global _send_str26
|
||||
.global uart_busy
|
||||
|
|
@ -17,37 +18,16 @@
|
|||
|
||||
// `tx()` and `put_char()` do not gobble r18, r20, r21, r22, r24, r26, and r27.
|
||||
|
||||
put_char:
|
||||
// non-global, non-C
|
||||
// arg: char r22
|
||||
lds r23, uart_tx_r
|
||||
lds r30, uart_tx_w
|
||||
ldi r19, 1
|
||||
add r19, r30
|
||||
eor r23, r19
|
||||
andi r30, 0x1f // uart_tx_m
|
||||
ldi r31, 0
|
||||
subi r30, lo8(-(uart_tx))
|
||||
sbci r31, hi8(-(uart_tx))
|
||||
andi r23, 0x1f // uart_tx_m
|
||||
breq 1f
|
||||
st Z, r22
|
||||
sts uart_tx_w, r19
|
||||
1:
|
||||
// r22 preserved
|
||||
// r23 full when zero
|
||||
ret
|
||||
|
||||
// r18, r26, and 27 must be preseved in the hex functions
|
||||
// …, r20, r21, r24, must be preserved in `uart_busy()` and `put_char()'
|
||||
// r18, r26, and 27 must be preseved in the hex functions
|
||||
// …, r20, r21, r24, must be preserved in `uart_busy()` and `put_char()'
|
||||
|
||||
send_hex_byte_eol:
|
||||
ldi r22, ' '
|
||||
rcall send_char22
|
||||
rcall _send_char22
|
||||
rcall send_hex_byte
|
||||
send_eol:
|
||||
ldi r22, '\n'
|
||||
rcall send_char22
|
||||
rcall _send_char22
|
||||
uart_busy:
|
||||
cli
|
||||
rcall tx ; gobbles r25, r30, and r31
|
||||
|
|
@ -57,11 +37,13 @@ uart_busy:
|
|||
9:
|
||||
ret
|
||||
|
||||
#ifdef HEX_WORD
|
||||
send_hex_word:
|
||||
mov r20, r24
|
||||
mov r24, r25
|
||||
rcall send_hex_byte
|
||||
mov r24, r20
|
||||
#endif
|
||||
send_hex_byte:
|
||||
mov r21, r24
|
||||
swap r24
|
||||
|
|
@ -75,24 +57,43 @@ send_hex_nibble:
|
|||
subi r24, '9'+1-'A'
|
||||
send_char:
|
||||
mov r22, r24
|
||||
send_char22:
|
||||
rcall put_char
|
||||
brne 9f
|
||||
rjmp _send_char22
|
||||
1:
|
||||
rcall uart_busy
|
||||
sleep
|
||||
rjmp send_char22
|
||||
_send_char22:
|
||||
// non-global, non-C
|
||||
// arg: char r22
|
||||
lds r23, uart_tx_r
|
||||
lds r30, uart_tx_w
|
||||
ldi r19, 1
|
||||
add r19, r30
|
||||
sub r23, r19
|
||||
andi r30, 0x1f // uart_tx_m
|
||||
ldi r31, 0
|
||||
subi r30, lo8(-(uart_tx))
|
||||
sbci r31, hi8(-(uart_tx))
|
||||
subi r23, 0xe0
|
||||
brcs 1b
|
||||
st Z, r22
|
||||
sts uart_tx_w, r19
|
||||
9:
|
||||
ret
|
||||
|
||||
send_str:
|
||||
movw r26, r24
|
||||
rjmp _send_str26
|
||||
1:
|
||||
rcall send_char22
|
||||
__send_char22_str26:
|
||||
rcall _send_char22
|
||||
_send_str26:
|
||||
ld r22, X+
|
||||
tst r22
|
||||
brne 1b
|
||||
9:
|
||||
ret
|
||||
|
||||
#ifdef SEND_HEX
|
||||
send_hex:
|
||||
movw r26, r24
|
||||
mov r18, r22
|
||||
|
|
@ -103,6 +104,7 @@ send_hex:
|
|||
brcc 1b
|
||||
9:
|
||||
ret
|
||||
#endif
|
||||
|
||||
command:
|
||||
;; when any frame errors occured, dismiss the buffer
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue