11import fs from 'fs' ;
2- import minimist from 'minimist' ;
2+ import packageJson from '../package.json' ;
3+ import sade from 'sade' ;
34import { GDBTCPServer } from '../src/gdb/gdb-tcp-server.js' ;
5+ import { RP2040 } from '../src/index.js' ;
46import { Simulator } from '../src/simulator.js' ;
57import { USBCDC } from '../src/usb/cdc.js' ;
68import { ConsoleLogger , LogLevel } from '../src/utils/logging.js' ;
79import { bootromB1 } from './bootrom.js' ;
810import { loadCircuitpythonFlashImage , loadMicropythonFlashImage , loadUF2 } from './load-flash.js' ;
911
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' ;
4426
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+ }
4846}
4947
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 ) {
5750 cdc . sendSerialByte ( 3 ) ;
51+ return ;
5852 }
59- } ;
6053
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 ) {
6360 process . stdout . write ( value ) ;
61+ let currentLine = '' ;
6462
6563 for ( const byte of value ) {
6664 const char = String . fromCharCode ( byte ) ;
@@ -75,20 +73,52 @@ cdc.onSerialData = (value) => {
7573 currentLine += char ;
7674 }
7775 }
78- } ;
79-
80- if ( process . stdin . isTTY ) {
81- process . stdin . setRawMode ( true ) ;
8276}
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 } ` ) ;
9089 }
91- } ) ;
9290
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