-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Add support for the USB CDC Serial JTAG console #3536
base: dev-esp32
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't had time to get across the CDC support, but this looks like a mighty good start! I added some comments/questions for your consideration, but overall consider this to have my blessing :)
(And if there are other things you want me to look over, tag me please. I've got the main feed on mute still for my own sanity's sake)
@@ -354,6 +497,19 @@ void platform_uart_stop( unsigned id ) | |||
int platform_uart_get_config(unsigned id, uint32_t *baudp, uint32_t *databitsp, uint32_t *parityp, uint32_t *stopbitsp) { | |||
int err; | |||
|
|||
#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG | |||
if (id == 0) { | |||
// Return dummy values |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it not be more honest to just return an error code here instead of dummy values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was nervous that it might frighten some code that thinks that it ought to be able to get the config....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good code should be able to handle jump scares! :D
Come to think of it though, isn't the USB device accepting serial configuration settings? And shouldn't we return those (even if they aren't being used)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It accepts settings from the PC side, but there isn't any way to get those from the ESP32 side (as far as I can tell). I think that the CDC device is hardware and just exposes a few registers to look like a UART. In particular, on the C3 I know that you cannot reprogram the USB to like anything except a CDC device. I don't think that is true for all variants of the ESP32.
In case anyone is interested I've rebased this onto latest |
I'm wondering if we need to completely change our approach to the Lua input. With the variation of consoles that the ESP32 series provide now, it makes me think we should switch to using plain old posix stdin for the Lua purposes. We'd have to somehow work out how to make that play nice with the uart module though... There are definitely some pesky legacy assumptions built into our API from the 8266 days. |
Check this out, jonsmirl@80c76ec That commit shows how to use ESP IDF linenoise() to implement a console. ESP IDF linenoise() works for every console type (serial, CDC, JTAG) and you control it via menuconfig. Using linenoise() removes the console support from the generic UART code. I don't know exactly how to set the Lua prompt. Needs something like this
|
The posix stdin approach should work on ESP IDF except O_NONBLOCK support is broken (I am working with them to fix it). Until they fix it using linenoise() is a better solution. Plus linenoise has history and editing support. |
This is how I modified standard lua before moving to nodemcu.
|
@jonsmirl I like this approach! I think our main challenge then is going to be how we change the deal with |
What about going back to the original lua console code and use pushline() like I modified above? I've only been using NodeMCU for two days so I have no experience with legacy issues. I do know that all of the new Espressif CPUs have the integrated JTAG/console so that is definitely something you will want to support. Edit - I see now, that will block lua and you don't want to do that. |
If you use linenoise() in a separate task, I don't know how to communicate the correct prompt to it. |
Looking at the linenoise stuff now, I'm not sure that would work for us as-is, since we currently have the requirement to be able to both receive the console data in a Looking at what Espressif have done themselves in their It's been ages since I had to work in this area of the code. I think our headaches can be summarised as:
The "easiest" solution given this would be, in my view, to:
That solution would however lose us some existing functionality, namely the ability to stop/start the console itself (unless we make the hypothetical On the other hand, this approach would gain us chip-side line editing support if we're using linenoise. Plus we wouldn't have to maintain a heap of We'd be neutral on the @pjsg Thoughts? You've spent more time in this area recently than I have. I can put in some work towards resolving this, but I don't want to do it without some discussion & agreement first. |
Ah, linenoise only supports a "pull" API, which means it's not compatible with the "push" / async architecture we have and can't be used as a replacement for our |
I've put together a quick proof of concept here. I don't have an S2 board with direct-to-USB, and the S3 CDC-ACM refused to build, so I haven't been able to test the CDC ACM one, but in theory it should work. Both the UART and USB-SER-JTAG ones work, though there seems to be a flush issue with the prompt. Haven't investigated yet. If anyone has recommendations for a cheap S2 dev board that brings out the CDC-ACM, that'd be great :) |
fcntl(fileno(stdin), F_SETFL, 0); is broken in the ESP IDF. fcntl(fileno(stdin), F_SETFL, O_NONBLOCK); should set non-blocking and 0 turn it off. If you dig around you will see that it powers on in blocking mode, then the ESP console code sets it to non-block via O_NONBLOCK. Once you set O_NONBLOCK you can't turn it off again because the API is broken. So that call to 0 should be putting it back into blocking mode, but it doesn't work. I've sent them the details of this a couple of weeks ago and they are looking at it. The way the current stdin ESP code works stdin is always non-blocking and you can't do anything about it. When I started on this I was using the standard lua and modified pushline() which needs to block. The stdin approach did not work because I could not set it to block. That pushed me into linenoise. nodemcu is the opposite, it does not want to block so the stdin approach should be used. |
I'm not seeing that here. My new console task is happily doing a blocking Do you have a github issue number for it? I searched the open esp-idf issues but couldn't find anything. |
I reported it directly to an Espressif employee who entered into their internal system. What you are seeing is consistent, it is loading the console component which breaks things. My issued asked them to fix the console component. I do think if you turn on O_NONBLOCK you won't be able to turn it off again. The console component is messed up because it has only been partially ported onto posix calls. It still has things like this in it which ignore O_NONBLOCK. I also pointed out that if they fixed the various issues in the console component they would be able to implement signal() and catch ctrl-C. Just proceed with caution when using ESP console and blocking behavior, the implementation behavior is not consistent. |
They are in the process of rewriting all of this, if you look in esp-idf/master console code is very different than v5.2. |
Yeah feels like there is a lot of gremlins in the stdio related code at the moment (see recent commit in my proof-of-concept). |
@jmattsson I tried your console code from dius on my S3 system. First problem I don't get any echo as I type, but after I hit return it echos. probably something with fflush or buffering. I also have to hit return before I can see the first prompt. Edit: read(fileno(stdin), linebuf, sizeof(linebuf)); is buffering the line. Second problem, I had to set the stack up to 4K to keep from overflowing. I moved the stack into PSRAM. This is likely something else in my system, is there some what to tell what is causing it to use so much stack? Edit: 2KB seems to be ok, 1KB is not enough on the S3. |
I got echo working by adding fsync(fileno(stdout)); at the bottom of feed_lua_input(). That is what I meant by saying the ESP posix console code works inconsistently. |
Yeah it feels like they haven't gotten their abstractions quite right yet. I added that |
Where does it print the very first prompt? That needs a fsync(fileno(stdout)); right after it too. |
Which Lua version? In 5.3 the first prompt should be the same as any other prompt. We start off by injecting a newline into the LVM to trigger the prompt print. See |
I had to set the read buffer down to one char. Obviously setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); is not working on the USB JTAG serial. I read around in the IDF source for a while and didn't come up with an obvious way to turn it off.
|
With read buffer at one char everything appears to work except the very first prompt doesn't appear until you type something. Maybe you can spot a way to turn off buffering on the jtag serial? The _IONBF is CRT buffering, I think the problem is buffering in the driver itself. |
We have to use read of one char, IDF is just broken. if you read 100 bytes you end up here: |
🤦♀️ |
Since this approach doesn't seem to be entirely dead in the water, I spent some time to make it actually process the console input in the correct thread context. That should also have addressed the unexpected need for larger stack size in the console task, but yell if it's being an issue again. Also fixed the prompt-not-flushed issue on ACM console. Interestingly, to get the prompt to show up I had to use |
Have also ordered an S2 mini board, so should hopefully be able to test the third console mode at some point. |
Fixes #3526.
dev
branch rather than for therelease
branch.docs/*
.If the USB CDC console is configured, then it appears as the default console for the Lua REPL. It also appears as UART 0 and bumps the other uart(s) down one. The baud rate cannot be configured as there is no actual serial line.
When configured this way, stdin and stdout are connected to this device. Unfortunately, async reading is not possible at the moment. Thus the input side is handled by doing blocking reads in a seperate thread, and then posting the data into the Lua environment. Happily this is very similar to how the uart code works.