8000 stmhal: Control-C doesn't work when using a UART REPL · Issue #1568 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

stmhal: Control-C doesn't work when using a UART REPL #1568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dhylands opened this issue Nov 1, 2015 · 15 comments
Closed

stmhal: Control-C doesn't work when using a UART REPL #1568

dhylands opened this issue Nov 1, 2015 · 15 comments

Comments

@dhylands
Copy link
Contributor
dhylands commented Nov 1, 2015

If you setup the REPL to be on a UART, then Control-C on the UART doesn't work. It works fine when connected over USB-serial.

Currently, the function to control whether Control-C should interrupt the REPL or not can be found in pyb.USB_VCP().

I'd like to propose that we move this someplace else (perhaps machine) and have that function call usb_vcp_set_interrupt_char and/or some new uart_set_interrupt_char function depending on how the repl is currently setup.

We could perhaps rename it to repl_setinterrupt, or leave it as setinterrupt. Just thought I'd throw this out to see what others think.

@pfalcon
Copy link
Contributor
pfalcon commented Nov 1, 2015

We could perhaps rename it to repl_setinterrupt, or leave it as setinterrupt. Just thought I'd throw this out to see what others think.

That's what I wanted to raise too, but given that I already raise 3-4 based issues based on my looking at USB_VCP/UART implementation, kinda skipped. This function cannot be called "set_interrupt" (on Python level). Interrupt is hardware signal which causes CPU to go to subroutine, setinterrupt() is obviously set such subroutine. It should be called set_break_char() or something. And it's both useful and confusing functionality - of course, it's beyond useful to be able to break to REPL, but when you need to transfer binary data, it's very confusing why everything randomly breaks. So, this function should be made very visible (like, mentioned in color at the beginning of sections for each class, then mentioned again along sections).

@dpgeorge
Copy link
Member
dpgeorge commented Nov 2, 2015

It's tricky (but of course doable) to make UART regocnise ctrl-C (or any char) as a KeyboardInterrupt. You'd need to add code to the UART irq handler that filters out ctrl-C from the buffer (and acts on it when one comes in), but only when that UART is duplicated on the REPL.

@dhylands
Copy link
Contributor Author
dhylands commented Nov 2, 2015

So the question becomes should we expose a UART.setinterrupt? Then the python code will need to call both the USB_VCP().setinterrupt and the UART.setinterrupt (because it may not know where the REPL is) or should we introduce a new repl_setinterrupt() which takes care of calling the appropriate internal functions? Or do both?

@dpgeorge
Copy link
Member
dpgeorge commented Nov 2, 2015

Having setinterrupt for both USB_VCP and UART is simpler to implement, but having a global repl_setinterrupt (or whatever it's called) is logically easier for the user. Note that os.dupterm(stream), which is used to duplicate the REPL, takes an aribtrary stream as the argument (must implement read/write) and how to configure the interrupt char on an arbitrary stream? Maybe have an ioctl call that sets the character? Then the semantics would be: when os.dupterm(stream) is called, the existing stream (if any) has ioctl called which disables the interrupt char, and then the same ioctl function is called on the new stream to enable the char.

If there was such an ioctl function (eg MP_IOCTL_SET_BREAK_CHAR) then you could expose this somehow to the user so they can disable the interrupt char if needed.

@dhylands
Copy link
Contributor Author
dhylands commented Nov 2, 2015

That sounds reasonable. Let me muddle my way through and see if I can make something along those lines work.

@dhylands
Copy link
Contributor Author
dhylands commented Nov 3, 2015

I don't see any ioctl exposed at the python level yet. CPython has fcntl.ioctl

Going the ioctl route would presumably mean creating ufcntl module with ioctl

Currently pyexec.c calls mp_hal_set_interrupt_char, but if we add an ioctl we could change pyexec to be more stream based rather than hard coded to use usb/uart.

Just wanting to make sure that this is the direction I should go in.

@dhylands
Copy link
Contributor Author
dhylands commented Nov 3, 2015

Scratch the whole fcntl.ioctl thing.

I think I need to expose an ioctl method in pybstdio.c so that the python code can do sys.stdin.ioctl(MP_IOCTL_SET_INTERRUPT_CHAR, -1) and this winds up calling into an ioctl function in pybstdio.c, which would in turn call mp_hal_set_interrupt_char, which would know where the duplciated REPLS are. I think I should also expose the MP_IOCTL_SET_INTERRUPT_CHAR constant as well (in the stdio_localc_dict_table).

I was also going to rename mp_const_vcp_interrupt to be mp_const_kbd_interrupt so that there is only a single KeyboardInterrupt exception allocated.

Which ever of usb or uart init runs first would allocate the KeyboardInterrupt object.

@DavidWhaleMEF
Copy link

We really need a way to consistently turn on and turn off CTRL-C handling, regardless of where the uart is directed to. All 4 use-cases are desirable:

  1. you use USB and you want CTRL-C to work, because you are using it interactively
  2. you use USB and you want CTRL-C to be transparent, because you are doing a binary file transfer over the USBSER UART
  3. You use UART on the pins and you want CTRL-C to work, because you are actually driving the REPL from some remote hardware at 3V that doesn't support USB
  4. You use UART on the pins and you want CTRL-C to be transparent, because you are sending back binary data from a sensor and you don't want an 0x03 to stop your program running.

@robert-hh
Copy link
Contributor

There is the method micropython.kbd_intr(), which is designed to control keyboard interrupt handling in a way you ask for. Unfortunately, there is an omission in that it does not work when REPL is extended to a different UART on Pyboard. So uses cases 1,2, (and 4 by chance) are implemented, and use case 3 is intended to be covered too, but does not work at the moment and has to be fixed.

@DavidWhaleMEF
Copy link

Thanks @robert-hh although that's not present on the BBC microbit port...

Type "help()" for more information.
>>> import micropython
>>> dir(micropython)
['__name__', 'mem_info', 'qstr_info', 'stack_use', 'heap_lock', 'heap_unlock']
>>>

I have confirmed here: bbcmicrobit/micropython#472 that on the BBC micro:bit port of MicroPython, receiving a 0x03 via uart when redirected to the bottom pins, still generates a KeyboardInterrupt. cc @dpgeorge

bbcmic 8000 robit/micropython#472

i.e. when interfacing to a sensor on the pins and if the sensor sends back a binary 0x03, it will generate a KeyboardInterrupt and stop the program running, dropping to the REPL, and sending the MicroPython banner and prompt to the device.

Also, I hadn't realised, but a generic catch Exception as e will not catch KeyboardInterrupt, which is why I did not understand this sooner! (It was observed as the micro:bit locking and requiring a hard reboot, but clearly it was just sitting at the REPL prompt with the REPL redirected to the pins).

@robert-hh
Copy link
Contributor
robert-hh commented Dec 10, 2017

I used to use a structure like:

try:
    c = sys.stdin.read(1)
except KeyboardInterrupt:
    c = '\x03'

But I'm not sure about the microbit port.

@dpgeorge
Copy link
Member

@DavidWhaleMEF micropython.kbd_intr() is available on micro:bit but only in the version1 branch at this point in time. But anyway, such a discussion should be kept to the micro:bit repo.

kwagyeman added a commit to kwagyeman/openmv that referenced this issue Jan 22, 2018
OpenMV IDE includes an ini file generator which will let you set board
settings easily from the IDE. Currently, the IDE has support for setting
the WiFi shield up along with adding a REPL Uart.

Anyway, this commit adds support for the OpenMV Cam to parse an ini file
on startup to configure things before starting main.py. WiFi support is
not yet implmented. However, we now have the ability to turn the UART
and put the REPL terminal on it on startup given a setting in the ini
file.

(Why not use boot.py like normal MP? While that is more flxible it's
much harder for the IDE to easily write out settings for you which is
what most users will want to do versus coding this up).

...

The movitation for adding REPL UART support in particular is so that the
OpenMV Cam can be used as a slave processor to IoT type processors like
the ESP32/ESP8266/ParticlePhoton/ElectricImp. In particular, a processor
like the ParticlePhoton can control the OpenMV Cam's reset wire. Wake
the camera up by releasing reset, then send a script to it after it
powers on over the UART. The camera will then run the script, do
computer vision, and report results back over the UART to the
ParticlePhoton. Users can then push new scripts to the OpenMV Cam from
the cloud allowing for semi-flexible firmware fixes for the OpenMV Cam
over low data rate networks.

By setting this feature up the need for OpenMV to offer a WiFi IoT
system is reduced as we can now just be the best camera for everything.

...

Due to... I don't know... ctrl-c doesn't work on the duplicated UART.

micropython/micropython#1568

Not sure how to handle this. I don't want to fix it since it needs to be
fixed by MP upstream. Right now the work around is for the mastering MCU
to just reset the OpenMV Cam when it's done with the system.

That said, this does mean that once you start a script using the Open
Terminal command line system you won't be able to stop the script.
kwagyeman added a commit to kwagyeman/openmv that referenced this issue Jan 23, 2018
OpenMV IDE includes an ini file generator which will let you set board
settings easily from the IDE. Currently, the IDE has support for setting
the WiFi shield up along with adding a REPL Uart.

Anyway, this commit adds support for the OpenMV Cam to parse an ini file
on startup to configure things before starting main.py. WiFi support is
not yet implmented. However, we now have the ability to turn the UART
and put the REPL terminal on it on startup given a setting in the ini
file.

(Why not use boot.py like normal MP? While that is more flxible it's
much harder for the IDE to easily write out settings for you which is
what most users will want to do versus coding this up).

...

The movitation for adding REPL UART support in particular is so that the
OpenMV Cam can be used as a slave processor to IoT type processors like
the ESP32/ESP8266/ParticlePhoton/ElectricImp. In particular, a processor
like the ParticlePhoton can control the OpenMV Cam's reset wire. Wake
the camera up by releasing reset, then send a script to it after it
powers on over the UART. The camera will then run the script, do
computer vision, and report results back over the UART to the
ParticlePhoton. Users can then push new scripts to the OpenMV Cam from
the cloud allowing for semi-flexible firmware fixes for the OpenMV Cam
over low data rate networks.

By setting this feature up the need for OpenMV to offer a WiFi IoT
system is reduced as we can now just be the best camera for everything.

...

Due to... I don't know... ctrl-c doesn't work on the duplicated UART.

micropython/micropython#1568

Not sure how to handle this. I don't want to fix it since it needs to be
fixed by MP upstream. Right now the work around is for the mastering MCU
to just reset the OpenMV Cam when it's done with the system.

That said, this does mean that once you start a script using the Open
Terminal command line system you won't be able to stop the script.
kwagyeman added a commit to kwagyeman/openmv that referenced this issue Jan 23, 2018
OpenMV IDE includes an ini file generator which will let you set board
settings easily from the IDE. Currently, the IDE has support for setting
the WiFi shield up along with adding a REPL Uart.

Anyway, this commit adds support for the OpenMV Cam to parse an ini file
on startup to configure things before starting main.py. WiFi support is
not yet implmented. However, we now have the ability to turn the UART
and put the REPL terminal on it on startup given a setting in the ini
file.

(Why not use boot.py like normal MP? While that is more flxible it's
much harder for the IDE to easily write out settings for you which is
what most users will want to do versus coding this up).

...

The movitation for adding REPL UART support in particular is so that the
OpenMV Cam can be used as a slave processor to IoT type processors like
the ESP32/ESP8266/ParticlePhoton/ElectricImp. In particular, a processor
like the ParticlePhoton can control the OpenMV Cam's reset wire. Wake
the camera up by releasing reset, then send a script to it after it
powers on over the UART. The camera will then run the script, do
computer vision, and report results back over the UART to the
ParticlePhoton. Users can then push new scripts to the OpenMV Cam from
the cloud allowing for semi-flexible firmware fixes for the OpenMV Cam
over low data rate networks.

By setting this feature up the need for OpenMV to offer a WiFi IoT
system is reduced as we can now just be the best camera for everything.

...

Due to... I don't know... ctrl-c doesn't work on the duplicated UART.

micropython/micropython#1568

Not sure how to handle this. I don't want to fix it since it needs to be
fixed by MP upstream. Right now the work around is for the mastering MCU
to just reset the OpenMV Cam when it's done with the system.

That said, this does mean that once you start a script using the Open
Terminal command line system you won't be able to stop the script.
@numbatboy
Copy link

Just checking in to see if there is any progress on the CTRL-C from dupterm on PyBoard issue? Such functionality would be very helpful.

@dpgeorge
Copy link
Member

Just checking in to see if there is any progress on the CTRL-C from dupterm on PyBoard issue?

This is now implemented via a60efa8 . Ctrl-C works with UARTs put on the REPL via os.dupterm() and the legacy pyb.repl_uart().

@numbatboy
Copy link

Just flashed my Pyboard with the latest firmware and wow. Ctrl-C now breaks a running program through os.dupterm() with KeyboardInterrupt: This helps my project along immensely. Great work - thanks.

davidhuwyler pushed a commit to davidhuwyler/openmv that referenced this issue Oct 31, 2019
OpenMV IDE includes an ini file generator which will let you set board
settings easily from the IDE. Currently, the IDE has support for setting
the WiFi shield up along with adding a REPL Uart.

Anyway, this commit adds support for the OpenMV Cam to parse an ini file
on startup to configure things before starting main.py. WiFi support is
not yet implmented. However, we now have the ability to turn the UART
and put the REPL terminal on it on startup given a setting in the ini
file.

(Why not use boot.py like normal MP? While that is more flxible it's
much harder for the IDE to easily write out settings for you which is
what most users will want to do versus coding this up).

...

The movitation for adding REPL UART support in particular is so that the
OpenMV Cam can be used as a slave processor to IoT type processors like
the ESP32/ESP8266/ParticlePhoton/ElectricImp. In particular, a processor
like the ParticlePhoton can control the OpenMV Cam's reset wire. Wake
the camera up by releasing reset, then send a script to it after it
powers on over the UART. The camera will then run the script, do
computer vision, and report results back over the UART to the
ParticlePhoton. Users can then push new scripts to the OpenMV Cam from
the cloud allowing for semi-flexible firmware fixes for the OpenMV Cam
over low data rate networks.

By setting this feature up the need for OpenMV to offer a WiFi IoT
system is reduced as we can now just be the best camera for everything.

...

Due to... I don't know... ctrl-c doesn't work on the duplicated UART.

micropython/micropython#1568

Not sure how to handle this. I don't want to fix it since it needs to be
fixed by MP upstream. Right now the work around is for the mastering MCU
to just reset the OpenMV Cam when it's done with the system.

That said, this does mean that once you start a script using the Open
Terminal command line system you won't be able to stop the script.
andrewleech pushed a commit to andrewleech/openmv that referenced this issue Sep 21, 2020
OpenMV IDE includes an ini file generator which will let you set board
settings easily from the IDE. Currently, the IDE has support for setting
the WiFi shield up along with adding a REPL Uart.

Anyway, this commit adds support for the OpenMV Cam to parse an ini file
on startup to configure things before starting main.py. WiFi support is
not yet implmented. However, we now have the ability to turn the UART
and put the REPL terminal on it on startup given a setting in the ini
file.

(Why not use boot.py like normal MP? While that is more flxible it's
much harder for the IDE to easily write out settings for you which is
what most users will want to do versus coding this up).

...

The movitation for adding REPL UART support in particular is so that the
OpenMV Cam can be used as a slave processor to IoT type processors like
the ESP32/ESP8266/ParticlePhoton/ElectricImp. In particular, a processor
like the ParticlePhoton can control the OpenMV Cam's reset wire. Wake
the camera up by releasing reset, then send a script to it after it
powers on over the UART. The camera will then run the script, do
computer vision, and report results back over the UART to the
ParticlePhoton. Users can then push new scripts to the OpenMV Cam from
the cloud allowing for semi-flexible firmware fixes for the OpenMV Cam
over low data rate networks.

By setting this feature up the need for OpenMV to offer a WiFi IoT
system is reduced as we can now just be the best camera for everything.

...

Due to... I don't know... ctrl-c doesn't work on the duplicated UART.

micropython/micropython#1568

Not sure how to handle this. I don't want to fix it since it needs to be
fixed by MP upstream. Right now the work around is for the mastering MCU
to just reset the OpenMV Cam when it's done with the system.

That said, this does mean that once you start a script using the Open
Terminal command line system you won't be able to stop the script.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labe 416D ls
None yet
Projects
None yet
Development

No branches or pull requests

6 participants
0