1
1
import fs from 'fs' ;
2
- import minimist from 'minimist' ;
2
+ import packageJson from '../package.json' ;
3
+ import sade from 'sade' ;
3
4
import { GDBTCPServer } from '../src/gdb/gdb-tcp-server.js' ;
5
+ import { RP2040 } from '../src/index.js' ;
4
6
import { Simulator } from '../src/simulator.js' ;
5
7
import { USBCDC } from '../src/usb/cdc.js' ;
6
8
import { ConsoleLogger , LogLevel } from '../src/utils/logging.js' ;
7
9
import { bootromB1 } from './bootrom.js' ;
8
10
import { loadCircuitpythonFlashImage , loadMicropythonFlashImage , loadUF2 } from './load-flash.js' ;
9
11
10
- const args = minimist ( process . argv . slice ( 2 ) , {
11
- string : [
12
- 'image' , // UF2 image to load; defaults to "RPI_PICO-20230426-v1.20.0.uf2"
13
- 'expect-text' , // Text to expect on the serial console, process will exit with code 0 if found
14
- ] ,
15
- boolean : [
16
- 'gdb' , // start GDB server on 3333
17
- 'circuitpython' , // use CircuitPython instead of MicroPython
18
- ] ,
19
- } ) ;
20
- const expectText = args [ 'expect-text' ] ;
21
-
22
- const simulator = new Simulator ( ) ;
23
- const mcu = simulator . rp2040 ;
24
- mcu . loadBootrom ( bootromB1 ) ;
25
- mcu . logger = new ConsoleLogger ( LogLevel . Error ) ;
26
-
27
- let imageName : string ;
28
- if ( ! args . circuitpython ) {
29
- imageName = args . image ?? 'RPI_PICO-20230426-v1.20.0.uf2' ;
30
- } else {
31
- imageName = args . image ?? 'adafruit-circuitpython-raspberry_pi_pico-en_US-8.0.2.uf2' ;
32
- }
33
- console . log ( `Loading uf2 image ${ imageName } ` ) ;
34
- loadUF2 ( imageName , mcu ) ;
35
-
36
- if ( fs . existsSync ( 'littlefs.img' ) && ! args . circuitpython ) {
37
- console . log ( `Loading uf2 image littlefs.img` ) ;
38
- loadMicropythonFlashImage ( 'littlefs.img' , mcu ) ;
39
- } else if ( fs . existsSync ( 'fat12.img' ) && args . circuitpython ) {
40
- loadCircuitpythonFlashImage ( 'fat12.img' , mcu ) ;
41
- // Instead of reading from file, it would also be possible to generate the LittleFS image on-the-fly here, e.g. using
42
- // https://github.com/wokwi/littlefs-wasm or https://github.com/littlefs-project/littlefs-js
43
- }
12
+ type CliOptions = {
13
+ image : string | null ;
14
+ 'expect-text' : string | null ;
15
+ gdb : boolean ;
16
+ 'gdb-port' : number ;
17
+ 'circuit-python' : boolean ;
18
+ } ;
19
+
20
+ function loadImage ( mcu : RP2040 , image : string | null , useCircuitPython : boolean ) {
21
+ let selectedImage : string ;
22
+ if ( image ) selectedImage = image ;
23
+ else if ( useCircuitPython )
24
+ selectedImage = 'adafruit-circuitpython-raspberry_pi_pico-en_US-8.0.2.uf2' ;
25
+ else selectedImage = 'RPI_PICO-20230426-v1.20.0.uf2' ;
44
26
45
- if ( args . gdb ) {
46
- const gdbServer = new GDBTCPServer ( simulator , 3333 ) ;
47
- console . log ( `RP2040 GDB Server ready! Listening on port ${ gdbServer . port } ` ) ;
27
+ console . log ( `Loading uf2 image ${ selectedImage } ` ) ;
28
+
29
+ try {
30
+ loadUF2 ( selectedImage , mcu ) ;
31
+ } catch ( err ) {
32
+ const message = err instanceof Error ? err . message : String ( err ) ;
33
+
34
+ console . log ( `Error: Failed to load image file: "${ message } "` ) ;
35
+ process . exit ( 1 ) ;
36
+ }
37
+
38
+ if ( fs . existsSync ( 'littlefs.img' ) && ! useCircuitPython ) {
39
+ console . log ( `Loading uf2 image littlefs.img` ) ;
40
+ loadMicropythonFlashImage ( 'littlefs.img' , mcu ) ;
41
+ } else if ( fs . existsSync ( 'fat12.img' ) && useCircuitPython ) {
42
+ loadCircuitpythonFlashImage ( 'fat12.img' , mcu ) ;
43
+ // Instead of reading from file, it would also be possible to generate the LittleFS image on-the-fly here, e.g. using
44
+ // https://github.com/wokwi/littlefs-wasm or https://github.com/littlefs-project/littlefs-js
45
+ }
48
46
}
49
47
50
- const cdc = new USBCDC ( mcu . usbCtrl ) ;
51
- cdc . onDeviceConnected = ( ) => {
52
- if ( ! args . circuitpython ) {
53
- // We send a newline so the user sees the MicroPython prompt
54
- cdc . sendSerialByte ( '\r' . charCodeAt ( 0 ) ) ;
55
- cdc . sendSerialByte ( '\n' . charCodeAt ( 0 ) ) ;
56
- } else {
48
+ function handleDeviceConnected ( cdc : USBCDC , useCircuitPython : boolean ) {
49
+ if ( useCircuitPython ) {
57
50
cdc . sendSerialByte ( 3 ) ;
51
+ return ;
58
52
}
59
- } ;
60
53
61
- let currentLine = '' ;
62
- cdc . onSerialData = ( value ) => {
54
+ // We send a newline so the user sees the MicroPython prompt
55
+ cdc . sendSerialByte ( '\r' . charCodeAt ( 0 ) ) ;
56
+ cdc . sendSerialByte ( '\n' . charCodeAt ( 0 ) ) ;
57
+ }
58
+
59
+ function handleSerialData ( value : Uint8Array , expectText : string | null ) {
63
60
process . stdout . write ( value ) ;
61
+ let currentLine = '' ;
64
62
65
63
for ( const byte of value ) {
66
64
const char = String . fromCharCode ( byte ) ;
@@ -75,20 +73,52 @@ cdc.onSerialData = (value) => {
75
73
currentLine += char ;
76
74
}
77
75
}
78
- } ;
79
-
80
- if ( process . stdin . isTTY ) {
81
- process . stdin . setRawMode ( true ) ;
82
76
}
83
- process . stdin . on ( 'data' , ( chunk ) => {
84
- // 24 is Ctrl+X
85
- if ( chunk [ 0 ] === 24 ) {
86
- process . exit ( 0 ) ;
87
- }
88
- for ( const byte of chunk ) {
89
- cdc . sendSerialByte ( byte ) ;
77
+
78
+ function simulateMicropythonImage ( opts : CliOptions ) {
79
+ const simulator = new Simulator ( ) ;
80
+ const mcu = simulator . rp2040 ;
81
+ mcu . loadBootrom ( bootromB1 ) ;
82
+ mcu . logger = new ConsoleLogger ( LogLevel . Error ) ;
83
+
84
+ loadImage ( mcu , opts . image , opts [ 'circuit-python' ] ) ;
85
+
86
+ if ( opts . gdb ) {
87
+ const gdbServer = new GDBTCPServer ( simulator , opts [ 'gdb-port' ] ) ;
88
+ console . log ( `RP2040 GDB Server ready! Listening on port ${ gdbServer . port } ` ) ;
90
89
}
91
- } ) ;
92
90
93
- simulator . rp2040 . core . PC = 0x10000000 ;
94
- simulator . execute ( ) ;
91
+ const cdc = new USBCDC ( mcu . usbCtrl ) ;
92
+ cdc . onDeviceConnected = ( ) => handleDeviceConnected ( cdc , opts [ 'circuit-python' ] ) ;
93
+ cdc . onSerialData = ( value ) => handleSerialData ( value , opts [ 'expect-text' ] ) ;
94
+
95
+ if ( process . stdin . isTTY ) process . stdin . setRawMode ( true ) ;
96
+
97
+ process . stdin . on ( 'data' , ( chunk ) => {
98
+ // 24 is Ctrl+X
99
+ if ( chunk [ 0 ] === 24 ) {
100
+ process . exit ( 0 ) ;
101
+ }
102
+ for ( const byte of chunk ) {
103
+ cdc . sendSerialByte ( byte ) ;
104
+ }
105
+ } ) ;
106
+
107
+ simulator . rp2040 . core . PC = 0x10000000 ;
108
+ simulator . execute ( ) ;
109
+ }
110
+
111
+ sade ( 'rp2040js-micropython' , true )
112
+ . version ( packageJson . version )
113
+ . describe ( packageJson . description )
114
+ . option ( '-i, --image' , 'UF2 image to load' )
115
+ . option (
116
+ '-e, --expect-text' ,
117
+ 'Text to expect on the serial console, process will exit with code 0 if found' ,
118
+ )
119
+ . option ( '-g, --gdb' , 'If a GDB server should be started on 3333 or not' , false )
120
+ . option ( '-p, --gdb-port' , 'The port to start the gdb server on' , 3333 )
121
+ . option ( '-c, --circuit-python' , 'If CircuitPython should be used instead of MicroPython' , false )
122
+ . example ( '--image ./my-image.uf2' )
123
+ . action ( simulateMicropythonImage )
124
+ . parse ( process . argv ) ;
0 commit comments