11// SPDX-License-Identifier: MIT
22// Copyright (c) 2025 The Pybricks Authors
33
4+ #include <errno.h>
5+ #include <fcntl.h>
6+ #include <signal.h>
47#include <stdio.h>
8+ #include <stdlib.h>
9+ #include <termios.h>
10+ #include <unistd.h>
511
612#include "../../drv/motor_driver/motor_driver_virtual_simulation.h"
713
@@ -133,11 +139,9 @@ const pbdrv_motor_driver_virtual_simulation_platform_data_t
133139 },
134140};
135141
136- extern uint8_t pbsys_hmi_native_program_buf [PBDRV_CONFIG_BLOCK_DEVICE_RAM_SIZE ];
137- extern uint32_t pbsys_hmi_native_program_size ;
138-
139142int main (int argc , char * * argv ) {
140143
144+ // Parse given program, else otherwise default to REPL.
141145 if (argc > 1 ) {
142146
143147 // Pybricksdev helper script, pipes multi-mpy to us.
@@ -150,6 +154,8 @@ int main(int argc, char **argv) {
150154 }
151155
152156 // Read the multi-mpy file from pipe.
157+ extern uint8_t pbsys_hmi_native_program_buf [PBDRV_CONFIG_BLOCK_DEVICE_RAM_SIZE ];
158+ extern uint32_t pbsys_hmi_native_program_size ;
153159 pbsys_hmi_native_program_size = fread (pbsys_hmi_native_program_buf , 1 , sizeof (pbsys_hmi_native_program_buf ), pipe );
154160 pclose (pipe );
155161
@@ -159,6 +165,52 @@ int main(int argc, char **argv) {
159165 }
160166 }
161167
168+ // Save the original terminal settings
169+ struct termios term_old , term_new ;
170+ if (tcgetattr (STDIN_FILENO , & term_old ) != 0 ) {
171+ printf ("DEBUG: Failed to get terminal attributes\n" );
172+ return 0 ;
173+ }
174+ term_new = term_old ;
175+
176+ // Get one char at a time instead of newline and disable CTRL+C for exit.
177+ term_new .c_lflag &= ~(ICANON | ECHO | ISIG );
178+
179+ // MicroPython REPL expects \r for newline.
180+ term_new .c_iflag |= INLCR ;
181+ term_new .c_iflag &= ~ICRNL ;
182+
183+ if (tcsetattr (STDIN_FILENO , TCSANOW , & term_new ) != 0 ) {
184+ printf ("Failed to set terminal attributes\n" );
185+ return 0 ;
186+ }
187+
188+ // Set stdin non-blocking so we can service it in the runloop like on
189+ // embedded hubs.
190+ int stdin_flags = fcntl (STDIN_FILENO , F_GETFL , 0 );
191+ if (stdin_flags == -1 ) {
192+ printf ("Failed to get fcntl flags\n" );
193+ return 0 ;
194+ }
195+ if (fcntl (STDIN_FILENO , F_SETFL , stdin_flags | O_NONBLOCK ) == -1 ) {
196+ printf ("Failed to set non-blocking\n" );
197+ return 0 ;
198+ }
199+
200+ // Runs the 'embedded' main.
162201 extern void _main (void );
163202 _main ();
203+
204+ // Restore stdin flags.
205+ if (fcntl (STDIN_FILENO , F_SETFL , stdin_flags ) == -1 ) {
206+ printf ("Failed to restore stdin flags\n" );
207+ }
208+
209+ // Restore terminal settings.
210+ if (tcsetattr (STDIN_FILENO , TCSANOW , & term_old ) != 0 ) {
211+ printf ("Failed to restore terminal attributes\n" );
212+ return 0 ;
213+ }
214+
215+ return 0 ;
164216}
0 commit comments