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

'getch()' #231

Open
ladyada opened this Issue Sep 5, 2017 · 20 comments

Comments

Projects
None yet
10 participants
@ladyada
Copy link
Member

ladyada commented Sep 5, 2017

OK its odd but hear me out :)

python used to allow raw REPL keygrabs (e.g. 'press any key to continue') but deprecated it in 3 for just input() which is blocking and requires a return key

it would be useful for interactive-at-the repl scripts to have a non-input() way of getting raw characters. i mean, you can send individual chars with print("x", end='') so why not have the reverse :D

also, using input() wonks with the REPL history: if you use input() it puts that entry into the history which i think is a bit odd:
image

@tannewt

This comment has been minimized.

Copy link
Collaborator

tannewt commented Sep 5, 2017

Try sys.stdin.read(1). I'm not sure if CircuitPython supports it but CPython should. We can add it if its closer to what you want.

Reference: https://docs.python.org/3/library/sys.html#sys.stdin

@ladyada

This comment has been minimized.

Copy link
Member Author

ladyada commented Sep 5, 2017

not really - its basically input() but it only gives you a char at a time. i wanted something where it was timeout-not-blocking AND you didnt have to hit return

@tannewt

This comment has been minimized.

Copy link
Collaborator

tannewt commented Sep 6, 2017

We'll have to add an new API for this. Its not well covered in CPython. More background is here: https://stackoverflow.com/questions/2408560/python-nonblocking-console-input

@tannewt tannewt added this to the 3.0 milestone Sep 6, 2017

@deshipu

This comment has been minimized.

Copy link

deshipu commented Sep 20, 2017

Shouldn't read() be non-blocking, returning an empty string if there is nothing in the buffer? I think it works that way for the sockets and the serial — returning at most n characters.

@dhalbert

This comment has been minimized.

Copy link
Collaborator

dhalbert commented Sep 20, 2017

Just tried this: sys.stdin.read() in CPython 3.5 will read until EOF (ctrl-D); it's blocking. Reading a single character, sys.stdin.read(1) hangs until one character is typed (and it buffers by line, so it waits for a newline as well) or EOF is encountered.

@deshipu

This comment has been minimized.

Copy link

deshipu commented Sep 20, 2017

Yes, but that's not consistent with other stream-like interfaces.

@dhalbert

This comment has been minimized.

Copy link
Collaborator

dhalbert commented Sep 20, 2017

I think we want to make the behavior consistent with CPython. Do you mean other stream-like interfaces in Python or in general? It's a file-like interface, where the reads might be really slow, because the device (the human) is slow to supply characters. I tried to find some asyncio examples for stdin, but I didn't see anything right away.

@deshipu

This comment has been minimized.

Copy link

deshipu commented Sep 20, 2017

Looking at the documentation at https://docs.python.org/3/library/io.html I can see there is a whole zoo of different behaviors, depending on what the object on which you call read() is and how it was created, and also what options were used. Sometimes it will block, sometimes it will return 0 bytes, sometimes None, and sometimes it will raise an exception.

It seems that there is a way to switch the stdio into a non-blocking mode, at least on Linux, using non-standard terminal libraries: https://stackoverflow.com/questions/21791621/python-taking-input-from-sys-stdin-non-blocking

@ladyada

This comment has been minimized.

Copy link
Member Author

ladyada commented Sep 20, 2017

there's nothing in 'standard' python that works on all OS's - windows uses a DLL and mscvt or whatnot - we have to do something custom :)

@tdicola

This comment has been minimized.

Copy link

tdicola commented Feb 21, 2018

IMHO the canonical python way to handle non-blocking io is with select: https://docs.python.org/3/library/select.html Like Radomir mentions though it quickly gets into platform specific optimizations for desktop though (poll, epoll, kpoll, etc.), but at the end of the day they're all the same idea of polling for availability of data from an arbitrary file descriptor with a select-like API. Adding a select API and ability to use it to poll for new chars from stdin, etc. would be handy, and it would be a natural progression to add polling for other descriptors like sockets (same way python likes to handle sockets on the desktop). With a light wrapper on top it could become a general purpose async IO engine too (i.e. your main loop is just a big poll of awaiting descriptors with select).

@deshipu

This comment has been minimized.

Copy link

deshipu commented Feb 22, 2018

It seems to me that being able to select or await on a DigitaIO object (or something that wraps it) would handle most of the cases for us. SPI and I2C are clocked by master, so nothing interesting happens with them without the master initiating it. AnalogIO could be selectable/awaitable also, but would require specifying a threshold. Selecting on a timer would pretty much be equivalent to doing select with a timeout, so I'm not that sure this is useful.

@tannewt

This comment has been minimized.

Copy link
Collaborator

tannewt commented Feb 27, 2018

Another way to achieve this is to provide a second "raw" serial connection to the computer in addition to the input. This would allow for binary data transmission in addition to text. It could work just like a UART connection.

We'd want dynamic USB descriptors for this (mentioned in #190) so that its only on as needed.

@ladyada

This comment has been minimized.

Copy link
Member Author

ladyada commented Feb 27, 2018

good idea! that's probably the 'right' way to do it, but yeah would have to wait until you can select the USB interfaces cauz there'd be juggling between webusb, cdc, HID.

@hybotics

This comment has been minimized.

Copy link

hybotics commented Apr 19, 2018

I have a situation where I need to have a Raspberry Pi 3 interact with a board running Circuit Python. I need to use Firmata between the two for two-way communication. I would need to transfer both ASCII and binary data. Being able to do this is highly desirable for some applications, like robotics.

@hybotics

This comment has been minimized.

Copy link

hybotics commented Apr 19, 2018

PS I am geekguy on the Adafruit forums.

@themzlab

This comment has been minimized.

Copy link

themzlab commented Jun 15, 2018

member hybotics/geekguy mentioned the same use case that I have for which this feature is highly desirable. At my company we use Raspberry Pi boards to host our internal test and production machines and sometimes have Arduino boards hanging on them over USB. CircuitPython boards are preferred compared to Arduino because we can stay with one language and also the instrument is self-documenting because it hold's its own code and readme files. The hardware is relatively elegant because it only requires that a USB cable be run to each remote device or sensor.

A problem is that we don't have a great way to send serial data instructions to the boards.

as a work-around is there a way to query the input buffer so that I can know if sys.stdin.read(1) would pass through or block?

@protothesis

This comment has been minimized.

Copy link

protothesis commented Aug 11, 2018

Hello folks!

I was directed to this thread by Scott (@tannewt ) over at the Adafruit forums, in reply to my query about "Arduino-like 'serial' with Circuit Python".

For what I'm trying to achieve, being able to send and receive serial data in this way through the USB connection would be really great.

Thanks all!

-Casey

@WRadigan

This comment has been minimized.

Copy link

WRadigan commented Sep 6, 2018

Ditto to @protothesis comments above... and I was similarly directed by @tannewt from the Arduino Discord... My goal would be to have something similar to the Arduino CmdMessenger. Right now the best I can come up with is using two boards: 1 for communication via the Serial Console, and 1 for Device Control with a UART between them. If anybody has already been down that road, I'd love to hear about it...

https://playground.arduino.cc/Code/CmdMessenger

@ladyada

This comment has been minimized.

Copy link
Member Author

ladyada commented Sep 6, 2018

an intermediate solution for now is to use the hardware UART + a usb/uart cable. elegant? not as much but it does work now :)
https://learn.adafruit.com/circuit-playground-express-serial-communications
(code works for any/all circuitpy boards)

@ATMakersBill

This comment has been minimized.

Copy link
Collaborator

ATMakersBill commented Sep 16, 2018

I created a workaround for this and am sharing it via this pull request
#1193

Not sure it's the right solution, but it does solve our issues.

@tannewt tannewt referenced this issue Sep 19, 2018

Closed

uart 4.0 #1128

5 of 5 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment