-
Notifications
You must be signed in to change notification settings - Fork 108
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
refactor transport into interface to allow extending serial implementations. #122
base: main
Are you sure you want to change the base?
Conversation
Thanks a lot but I do not think this solves the original problem. To me, it seems like the class implementing the Transport interface still has too much responsibility. I believe the algorithms (e.g. I think the Transport "interface" should only implement "raw read", "raw write", Another thing I would like you to consider when defining the interface - at least Chromium's webserial is quite fast and is able to set dtr/rts with low enough latency not to cause too many problems. This is not true for serial port implementations for Node.js, which have problems with inverting both of the signals at once during the reset sequence (specifically the SerialPort library has this problem). It then causes that while the signal on the EN pin is rising (which takes a surprisingly long time), there is a short period when the boot pin is set to logical 1 as well and so the esp boots in the wrong mode (I'm not sure now which sequence it was but can investigate this further later this week). In my fork, I've solved this problem by updating the reset strategy string and its interpretation:
This solution needs some function for setting both of the pins at once to be present in the interface. Also, I don't know, whether changing the strategy string is a viable option. Another problem, I see with the implementation is in the Anyways, the use of And just a little nitpick - wouldn't an interface suit the function better than an empty abstract class? Also, maybe it would make more sense to put the docstrings into the interface instead of "the one" implementation? |
Thank you for your feedback. The main reason I included these functions in the Abstract Transport class is because they are referenced in the ESPLoader class directly. I do agree that some functions are more of utility so will move those too. I think Thanks for noticing about ArrayBuffer, will fix these asap. About why using Abstract class is mostly because it enforce any implementation of Transport classes to implement these methods too which I think is better to keep consistency with esploader transport calls. |
Is it true, that the underlying serial port implementations can be so different, that they would not fit into the API I've outlined? I firmly believe, that having new Suppose the underlying serial port implementation does not support direct read/write via an async function. In such a case, it can be easily transformed using a wrapper, which exposes such API ~~ also, in such a case, the current API would break as well and a similar transformation would still be needed. While it may cause the implementation to use one more buffer than a more optimal solution, I believe that is not a problem, considering we are in a JS environment already and the data in the buffer wouldn't be stored in multiple copies anyway. On the other hand, we will get a much simpler way of implementing wrappers for new serial port implementations. |
Also, could you please comment on the section, where I'm discussing the handling of DTR/RTS in connection to the reset sequence? |
The current The I didn't think about the reset functionality because it seems to me that those We could add a way to inject these |
The problem is not the fact whether the functions are async, but the fact that they have too much responsibility. The way they are, the Regarding the reset, the same problem occurred not only with the reset string but with the mentioned functions, which implement the sequence directly. The problems I've encountered are caused by the configuration of the signals (in |
Isn't read N bytes Removed some of these function from abstract class and refactor reset methods and other functions. What do you think @cubicap ? |
I'm also interested in using esptool-js in node.js and I'd like to echo @cubicap's comments, specifically that |
df77691
to
260e5ea
Compare
Download the artifacts for this pull request: |
f8414ee
to
0af8c80
Compare
Thanks a lot, the refactor looks mostly like what I had in mind.
Also, I'm still not convinced that using an abstract class instead of an interface for The last thing is tracing -- I'm not sure, whether The problems with the reset sequence I've mentioned before will still probably persist but I'll investigate further and write a separate issue when I have the time for that. On a separate note - I'd like to ask, whether Espressif is interested in maintaining the implementation of other selected (possibly popular) transports (like node-serialport or connection through WebUSB). It could make it more clear to users that esptool-js is usable outside of the web context and as a test that everything works when used from inside node.js. |
Oh, I've looked inside the WebSerialTransport and it seems I've missed some stuff regarding slip - while slip is mostly separate, it still partly lives inside webserial transport: The attribute The Another thing is the
My suggestion would be to create a class (a large reason for these changes is that exposing data directly means there is no clear contract as to what can be done with them, which in turn means that to implement a custom transport, the user needs a deeper understanding of how the buffer is used and how it should be managed) |
Thank you for the feedback @cubicap ! Updated the changes to a Slip class and further remove from Transport layer and other changes like the tracer object into a Trace interface. the leftOver was reimplemented in @tve unread(buffer) method. Thank you @tve Regarding the reset functions you can see that the user can override the reset functions passing reset functions objects to esploader in loaderOptions. Please take a look guys. About supporting other transport I would be happy to add support for them if they don't require too much maintaining but community can help. Hopefully we can add an implementation that could be use in node electron and others. |
Thank you, that looks great! The last thing about the function leftOver(buffer) {
this.leftOver = this.leftOver.length == 0 ? buffer : appendArray(buffer, this.leftOver);
} I guess, this would mean the behaviour of transport's I think it's a bit closer to what @tve meant. |
I've completely missed the changes to reset. That looks like it should be able to fix most of the problems I've encountered - thanks for that. I've just noticed that some of the functions like It might also be nice to always use the named resets inside of esploader instead of sequence strings to make the behaviour more clear? |
I'm just writing a node-serialport transport to test whether things work in node.js and am wondering whether the |
I've just finished testing the new version with node.js and have encountered several problems:
Just to illustrate the first point - I believe I know how esptool-js works internally and how it should be used better than an average user. Still, I've spent more than an hour debugging what I am doing differently than the webserial transport. To make the tool portable, the json files will probably have to be loaded using a different approach. (the solution I use in my fork is transforming the jsons into ts source files, but it's not very elegant, and I'm not sure if it is even ok because of their license). Other than that, things seem to work well. |
I had a typo in one of my comments - in the code snippet, the function name should have been The current version behaves differently than the typical "unread" operation. Intuitively, it should just put the data back to the input, so they are the first bytes read by a read operation. Please take a look at C's ungetc - it only pushes the character into the read buffer. Similar behaviour can be observed with Node.js' Readable.unshift Such behaviour would be preferable because it is easier to imagine and more conventional. Changing the behaviour would remove a way just to read the |
For some reason the re implementation of this transport layer made the chip connection very unstable. Need to go back to review what went wrong. |
Interesting... When I tried the last commit with my ESP32-S3, things seemed to work fine both in a browser and Node.js. (I did not notice any difference from before) |
d833d4b
to
3399a67
Compare
de0755a
to
02444a7
Compare
Thanks for the work you've done. At first glance, I see a few things missing - the unread operation we discussed is not implemented and the read operation therefore still suffers from the mentioned problems. I am also not sure about Node.js - the imports of json stubs in the "target.ts" files do not seem to work under it. And just a nitpick regarding the reset functions interface - the ESPLoader constructor appears to check all of the reset functions for being defined (which seems sensible and allows for not specifying the defaults explicitly), however, the interface |
I haven't been able to successfully refactor About reset function can fix this. Regarding the JSON import, I believe tsconfig.json |
I have I think the problem is that while TypeScript has the concept of json imports, ES does not. AFAIK, it should work in CommonJS modules but ES is the standard that should be targeted (or that's what I believe). Dynamic import will probably have the same problems as the "normal" one. There is a proposal for ES to add "import attributes", which should allow json imports but it's not standardized yet. I wanted to finalize the interface as much as possible so that more breaking changes are not necessary in the near future. If it's not a problem, I can look at the |
Fix #117
This PR separate the Webserial transport into an abstract class
AbstractTransport
andISerialOptions
for such transport class construct options.This should enable external serial implementation such as node serialport.
PTAL @cubicap