forked from DangerousPrototypes/BusPirate5-firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpirate.c
492 lines (423 loc) · 17 KB
/
pirate.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "pico/multicore.h"
#include "hardware/spi.h"
#include "hardware/timer.h"
#include "hardware/uart.h"
#include "pico/mutex.h"
#include "ws2812.pio.h"
#include "pirate.h"
#include "system_config.h"
#include "opt_args.h"
#include "ui/ui_lcd.h"
#include "pirate/rgb.h"
#include "pirate/shift.h"
#include "pirate/bio.h"
#include "pirate/button.h"
#include "pirate/storage.h"
#include "pirate/lcd.h"
#include "pirate/amux.h"
#include "pirate/mcu.h"
#include "ui/ui_init.h"
#include "ui/ui_info.h"
#include "ui/ui_term.h"
#include "ui/ui_prompt.h"
#include "ui/ui_process.h"
#include "ui/ui_flags.h"
#include "commands/global/button_scr.h"
#include "commands/global/freq.h"
#include "queue.h"
#include "usb_tx.h"
#include "usb_rx.h"
#include "debug.h"
#include "ui/ui_cmdln.h"
#include "bytecode.h"
#include "modes.h"
#include "displays.h"
#include "system_monitor.h"
#include "ui/ui_statusbar.h"
#include "tusb.h"
#include "hardware/sync.h"
#include "pico/lock_core.h"
//#include "helpers.h"
#include "mode/binio.h"
#include "commands/global/p_pullups.h"
#include "pirate/psu.h"
#include "commands/global/w_psu.h"
//#include "display/scope.h"
#include "mode/logicanalyzer.h"
#include "msc_disk.h"
static mutex_t spi_mutex;
void core1_entry(void);
int64_t ui_term_screensaver_enable(alarm_id_t id, void *user_data){
system_config.lcd_screensaver_active=true;
lcd_screensaver_enable();
return 0;
}
int main(){
char c;
uint8_t bp_rev=mcu_detect_revision();
//init buffered IO pins
bio_init();
// setup SPI0 for on board peripherals
uint baud=spi_init(BP_SPI_PORT, BP_SPI_HIGH_SPEED);
gpio_set_function(BP_SPI_CDI, GPIO_FUNC_SPI);
gpio_set_function(BP_SPI_CLK, GPIO_FUNC_SPI);
gpio_set_function(BP_SPI_CDO, GPIO_FUNC_SPI);
// init shift register pins
shift_init();
#ifdef BP5_REV
system_config.hardware_revision=BP5_REV;
#else
#error "No platform revision defined. Check pirate.h."
#endif
// SPI bus is used from here
// setup the mutex for spi arbitration
mutex_init(&spi_mutex);
//init psu pins
psucmd_init();
// LCD pin init
lcd_init();
// ADC pin init
amux_init();
// TF flash card CS pin init
storage_init();
// configure the defaults for shift register attached hardware
shift_clear_set_wait(CURRENT_EN_OVERRIDE, (AMUX_S3|AMUX_S1|DISPLAY_RESET|DAC_CS|CURRENT_EN));
pullups_init(); //uses shift register internally
shift_output_enable(true); //enable shift register outputs, also enabled level translator so don't do RGB LEDs before here!
//reset the LCD
lcd_reset();
// input button init
button_init();
// setup the system_config defaults and the initial pin label references
system_init();
//setup the UI command buffers
ui_init();
//voltage and current monitor for toolbar and display
//highly optimized to only update changed characters
monitor_init();
// Now continue after init of all the pins and shift registers
// Mount the TF flash card file system (and put into SPI mode)
// This must be done before any other SPI communications
#if BP5_REV <= 9
spi_set_baudrate(BP_SPI_PORT, BP_SPI_START_SPEED);
storage_mount();
if(storage_load_config()){
system_config.config_loaded_from_file=true;
}
spi_set_baudrate(BP_SPI_PORT, BP_SPI_HIGH_SPEED);
#endif
// RGB LEDs pins, pio, set to black
//this must be done after the 74hct245 is enabled during shift register setup
//NOTE: this is now handled on core1 entry
//rgb_init();
//psucmd_init();
//uart
//duplicate the terminal output on a debug uart on IO pins
if(system_config.terminal_uart_enable){
debug_uart_init(system_config.terminal_uart_number, true, true, true);
}
//a transmit only uart for developers to debug (on IO pins)
if(system_config.debug_uart_enable){
debug_uart_init(system_config.debug_uart_number, true, true, false);
}
multicore_launch_core1(core1_entry);
// LCD setup
lcd_configure();
monitor(system_config.psu);
if (modes[system_config.mode].protocol_lcd_update){
modes[system_config.mode].protocol_lcd_update(UI_UPDATE_ALL);
} else if (displays[system_config.display].display_lcd_update){
displays[system_config.display].display_lcd_update(UI_UPDATE_ALL);
}
lcd_backlight_enable(true);
translation_set(system_config.terminal_language);
// turn everything off
bio_init(); // make all pins safe
psucmd_disable(); // disable psu and reset pin label, clear any errors
// mount NAND flash here
#if BP5_REV >= 10
storage_mount();
if(storage_load_config()){
system_config.config_loaded_from_file=true;
}
#endif
// begin main loop on secondary core
// this will also setup the USB device
// we need to have read any config files on the TF flash card before now
multicore_fifo_push_blocking(0);
// wait for init to complete
while(multicore_fifo_pop_blocking()!=0xff);
//test for PCB revision
//must be done after shift register setup
// if firmware mismatch, turn all LEDs red
if(bp_rev!=BP5_REV){ //
//printf("Error: PCB revision does not match firmware. Expected %d, found %d.\r\n", BP5_REV, mcu_detect_revision());
rgb_irq_enable(false);
while(true){
rgb_set_all(0xff, 0, 0);
busy_wait_ms(500);
rgb_set_all(0, 0, 0);
busy_wait_ms(500);
}
}
enum bp_statemachine{
BP_SM_DISPLAY_MODE,
BP_SM_GET_INPUT,
BP_SM_PROCESS_COMMAND,
BP_SM_COMMAND_PROMPT,
BP_SM_SCRIPT_MODE
};
uint8_t bp_state=0;
uint32_t value;
struct prompt_result result;
alarm_id_t screensaver;
bool has_been_connected = false;
while(1){
if(script_entry()){ //enter scripting mode?
bp_state=BP_SM_SCRIPT_MODE; //reset and show prompt
}
if (tud_cdc_n_connected(0)){
if(!has_been_connected){
has_been_connected = true;
make_usbmsdrive_readonly();
//sync with the host
storage_unmount();
storage_mount();
}
}
else{
if (has_been_connected){
has_been_connected = false;
}
make_usbmsdrive_writable();
}
switch(bp_state){
case BP_SM_DISPLAY_MODE:
if(system_config.terminal_ansi_color){ //config file option loaded, wait for any key
char c;
result.error=false;
result.success=false;
if(rx_fifo_try_get(&c)){
value='a';
result.success=true;
}
}else{
ui_prompt_vt100_mode(&result, &value);
}
if(result.success){
switch(value){
case 'y':
system_config.terminal_ansi_color=UI_TERM_FULL_COLOR;
system_config.terminal_ansi_statusbar=1;
case 'a': // case were configuration already exists
ui_term_detect(); // Do we detect a VT100 ANSI terminal? what is the size?
ui_term_init(); // Initialize VT100 if ANSI terminal
ui_statusbar_update(UI_UPDATE_ALL);
break;
case 'n':
system_config.terminal_ansi_statusbar=0;
system_config.terminal_ansi_color=UI_TERM_NO_COLOR;
break;
default:
break;
}
// show welcome
//ui_info_print_info(&args, &res);
bp_state=BP_SM_COMMAND_PROMPT;
}else if(result.error){ // user hit enter but not a valid option
printf("\r\n\r\nVT100 compatible color mode? (Y/n)> ");
}
//printf("\r\n\r\nVT100 compatible color mode? (Y/n)> ");
button_irq_enable(0, &button_irq_callback); //enable button interrupt
break;
case BP_SM_GET_INPUT:
//helpers_mode_periodic();
//it seems like we need an array where we can add our function for periodic service?
displays[system_config.display].display_periodic();
modes[system_config.mode].protocol_periodic();
la_periodic();
switch(ui_term_get_user_input()){
case 0x01:// user pressed a key
if(system_config.lcd_timeout){
if(system_config.lcd_screensaver_active){
lcd_screensaver_disable();
system_config.lcd_screensaver_active=false;
}else{
cancel_alarm(screensaver);
}
//TODO: figure out how to just reset the timer instead...
screensaver = add_alarm_in_ms(system_config.lcd_timeout*300000, ui_term_screensaver_enable, NULL, false);
}
break;
case 0xff: //user pressed enter
if(system_config.lcd_timeout){
cancel_alarm(screensaver);
}
printf("\r\n");
bp_state=BP_SM_PROCESS_COMMAND;
button_irq_disable(0);
break;
}
enum button_codes press_code = button_check_press(0);
if (press_code != BP_BUTT_NO_PRESS) {
button_irq_disable(0);
button_exec(press_code); // execute script based on the button press type
bp_state = BP_SM_COMMAND_PROMPT; //return to command prompt
}
break;
case BP_SM_PROCESS_COMMAND:
system_config.error=ui_process_commands();
bp_state=BP_SM_COMMAND_PROMPT;
break;
case BP_SM_SCRIPT_MODE:
script_mode();
case BP_SM_COMMAND_PROMPT:
if(system_config.subprotocol_name){
printf("%s%s-(%s)>%s ", ui_term_color_prompt(), modes[system_config.mode].protocol_name, system_config.subprotocol_name, ui_term_color_reset());
}else{
printf("%s%s>%s ", ui_term_color_prompt(), modes[system_config.mode].protocol_name, ui_term_color_reset());
}
cmdln_next_buf_pos();
if(system_config.lcd_timeout){
screensaver = add_alarm_in_ms(system_config.lcd_timeout*300000, ui_term_screensaver_enable, NULL, false);
}
bp_state=BP_SM_GET_INPUT;
button_irq_enable(0, &button_irq_callback);
break;
default:
bp_state=BP_SM_COMMAND_PROMPT;
break;
}
// shared multitasking stuff
// system error, over current error, etc
if(system_config.error){
printf("\x07"); // bell!
psucmd_over_current(); //check for PSU error, reset and show warning
system_config.error=0;
bp_state=BP_SM_COMMAND_PROMPT;
}
}
return 0;
}
// refresh interrupt flag, serviced in the loop outside interrupt
bool lcd_update_request=false;
bool lcd_update_force=false;
// begin of code execution for the second core (core1)
void core1_entry(void){
char c;
uint32_t temp;
tx_fifo_init();
rx_fifo_init();
rgb_init();
// wait for main core to signal start
while(multicore_fifo_pop_blocking()!=0);
// USB init
if(system_config.terminal_usb_enable){
tusb_init();
}
lcd_irq_enable(BP_LCD_REFRESH_RATE_MS);
//terminal debug uart enable
if(system_config.terminal_uart_enable){
rx_uart_init_irq();
}
multicore_fifo_push_blocking(0xff);
while(1){
//service (thread safe) tinyusb tasks
if(system_config.terminal_usb_enable){
tud_task(); // tinyusb device task
}
//service the terminal TX queue
tx_fifo_service();
//bin_tx_fifo_service();
if(system_config.psu==1 && system_config.psu_irq_en==true && !psu_fuse_ok()){
system_config.psu_irq_en=false;
psucmd_irq_callback();
}
if(lcd_update_request){
monitor(system_config.psu); //TODO: fix monitor to return bool up_volts and up_current
uint32_t update_flags=0;
if (lcd_update_force) { lcd_update_force=false;update_flags|= UI_UPDATE_FORCE|UI_UPDATE_ALL;}
if(system_config.pin_changed) update_flags|= UI_UPDATE_LABELS; //pin labels
if(monitor_voltage_changed()) update_flags|= UI_UPDATE_VOLTAGES; //pin voltages
if(system_config.psu && monitor_current_changed()) update_flags|= UI_UPDATE_CURRENT; //psu current sense
if(system_config.info_bar_changed) update_flags|=UI_UPDATE_INFOBAR; //info bar
if(!system_config.lcd_screensaver_active){
if (modes[system_config.mode].protocol_lcd_update){
modes[system_config.mode].protocol_lcd_update(update_flags);
}else if (displays[system_config.display].display_lcd_update){
displays[system_config.display].display_lcd_update(update_flags);
}
}
if(system_config.terminal_ansi_color && system_config.terminal_ansi_statusbar
&& system_config.terminal_ansi_statusbar_update && !system_config.terminal_ansi_statusbar_pause){
ui_statusbar_update(update_flags);
}
//remains for legacy REV8 support of TF flash
#if BP5_REV<10
if(storage_detect())
{
}
#endif
freq_measure_period_irq(); //update frequency periodically
monitor_reset();
lcd_update_request=false;
}
// service any requests with priority
while(multicore_fifo_rvalid()){
temp=multicore_fifo_pop_blocking();
switch(temp){
case 0xf0:
lcd_irq_disable();
lcd_update_request=false;
break;
case 0xf1:
lcd_irq_enable(BP_LCD_REFRESH_RATE_MS);
lcd_update_request=true;
break;
case 0xf2:
lcd_irq_enable(BP_LCD_REFRESH_RATE_MS);
lcd_update_force=true;
lcd_update_request=true;
break;
case 0xf3:
rgb_irq_enable(false);
break;
case 0xf4:
rgb_irq_enable(true);
break;
default:
break;
}
multicore_fifo_push_blocking(temp); //acknowledge
}
}// while(1)
}
struct repeating_timer lcd_timer;
bool lcd_timer_callback(struct repeating_timer *t) {
lcd_update_request=true;
return true;
}
void lcd_irq_disable(void){
bool cancelled = cancel_repeating_timer(&lcd_timer);
}
void lcd_irq_enable(int16_t repeat_interval){
// Create a repeating timer that calls repeating_timer_callback.
// If the delay is negative (see below) then the next call to the callback will be exactly 500ms after the
// start of the call to the last callback
// Negative delay so means we will call repeating_timer_callback, and call it again
// 500ms later regardless of how long the callback took to execute
add_repeating_timer_ms(repeat_interval, lcd_timer_callback, NULL, &lcd_timer);
}
//gives protected access to spi (core safe)
void spi_busy_wait(bool enable){
if(!enable){
// the check is to protect against the first csel_deselect call not matched by a csel_select
if (lock_is_owner_id_valid(spi_mutex.owner))
mutex_exit(&spi_mutex);
}else{
mutex_enter_blocking(&spi_mutex);
}
}