Conversation
Added bus messages "serial<N>-data-terminal-ready-output" and "serial<N>-request-to-send-output" for RS-232 hardware output signals DTR and RTS, respectively.
- added new files "modem.js" and its documentation "modem.md" - added new debug log type LOG_MODEM - integrated Modem device into V86 options and web interface
| * [TELIT] [AT Commands Reference Guide](https://docs.rs-online.com/c5f6/0900766b81541066.pdf) | ||
| * [websocketd](http://websocketd.com/), also [websockify](https://linux.die.net/man/1/websockify) | ||
| * [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) | ||
| * [WebRTC API](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API) |
There was a problem hiding this comment.
Is WebRTC mentioned/used anywhere?
There was a problem hiding this comment.
Is WebRTC mentioned/used anywhere?
That's the only place it's mentioned, it's not used anywhere, and here's why I mentioned it:
The WebSocket backend implementation I'm currently using for the Modem only allows outbound calls, but Modems can make outbound calls and also accept inbound calls (therefore, the whole RING/ATA-mechanics of the Modem are currently dead).
WebRTC, on the other hand, supports both in- and outbound "calls" (connections), but needs a signalling server and protocol to signal things like for example INVITE/BUSY/ACCEPT and to penetrate firewalls using TURN/STUN/ICE (or whatever).
WebRTC supports binary end-to-end data channels, but I couldn't find an easy way to set this up (like I was able to with the general-purpose WebSocket server websocketd), and the implementation in Javascript looks like a piece of work. I lack practical experience with WebRTC, so I didn't pursue this any further, but I wanted to mention it to not forget about it :)
|
Thanks! This looks very cool and I'd like to merged it. I've given a basic review, but due to unfamiliarity with modems I can't review it detail. That's fine, it makes you the official maintainer of the modem code :-)
I agree, in the future I would like to remove internal-only bus events and use direct method calls (e.g. modem receives an uart object or vice-versa). Adding an initialise function sounds fine to me. Or move the modem to cpu.js and pass the uart object to it (that also makes the state handling easier). I tested some basic commands and connecting to a websocket server. Is there a way to test internet connectivity with user-mode-style networking (e.g. slirp, passt or our own code)? |
New uart number scheme: - 0: disable Modem (no UART) - 1: use UART0 (COM1) - 2: use UART1 (COM2) - 3: use UART2 (COM3) - 4: use UART3 (COM4) This new scheme is used in the web UI and in the modem configuration, only the Modem class maps the uart number x to UARTx-1. In starter.js, a Modem object is instantiated only if the uart number is not 0 (or undefined). Also: - added query parameter for modem (uart number) in main.js - removed UART0 from web UI (reserved for serial connection) in index.html and debug.html
In addtion to the strict zero-padded IP/Port-number number notation, added support for dotted IPv4-notation with arbitrary separator characters (i.e. "1.2.3.4:5678" may also be written as "1-2-3-4-5678"). Any non-digit and non-whitespace characters may be used as separator characters. Added range checks for all numbers (0-255 for IPv4 octets, 0-65535 for Port numbers). Updated dial string documentation in modem.md.
Great, and that's perfectly fine with me! When I was a teenager I went around, told people what kind of Modem to buy and then installed Trumpet Winsock on their PCs to show them the Internet. Modems and I go way back (as well as BBSes, MUDs and such). I'm still using Modems at work, they now have SIM cards but the basics never changed :)
I've also thought about using direct calls instead of the bus here. But I've left the code as it is now, this is a larger topic.
At the bottom of the Modem manual "docs/modem.md" you find two example websocket servers for the Modem, the second one is a complete PPP server (PPP is much superior to SLIP and CSLIP) which provides an IP address pool for clients and gives them full internet access (PPP clients can also directly access each other, so one PPP client can run an IP server and another PPP client can connect to it). If you or anybody else wants, download my Win3.11 image win311-128m.zip (32 MB) with everything preinstalled, here is how you use it: First, get the PPP server up and running (see my second example in "docs/modem.md"). Then:
I don't know why I need Boch's with thie image, but SeaBIOS crashes with some memory error. |
Changed the response to command lines without any AT command from ERROR to OK (this might be an empty line or some garbage characters). ITU-T V.250 states in "5.6 Executing commands": If no commands appear in the command line, the OK result code is issued. Trumpet Winsock's auto-dial script tripped over this, I didn't notice this earlier.
| settings.disable_audio = bool_arg(query_args.get("mute")); | ||
| if(query_args.has("modem")) | ||
| { | ||
| settings.modem = { modem_uart: parseInt(query_args.get("modem"), 10) || 0 }; |
There was a problem hiding this comment.
Ah thanks!
There was another little issue with this, see commit 7826553.
|
I'm trying to get the Trumpet Winsock auto-dialler to work properly, which it currently doesn't. During debugging I've found two problems:
The first issue is easy, I think I know what to do there after having played around with this a bit. But the second one is strange. I've looked at the code in @copy: Is it possible that this was forgotten? This would explain why Trumpet Winsock can't detect the signal transition (and thus hangs in the auto-dialler). In case someone knows more please post, else I'll try to look up a proper source for this information later. |
| } | ||
| } | ||
|
|
||
| if(DEBUG) |
There was a problem hiding this comment.
Is there any purpose for this if(DEBUG)?
There was a problem hiding this comment.
Oh, that's just a leftover from an earlier state when I had lots of debugging information there, since it isn't needed anymore I removed this condition in commit 2a93655.
Thank you!
- fixed options member name confusion (modem_uart/uart) - added assignment of "modem" query argument to the HTML <select> element's value on page load
- changed AT command line evaluation (after receiving the line terminating CR character): - if the command line buffer is empty, either abort the current dial attempt with NO CARRIER response, or else return OK response - if the command line buffer is not empty but without AT command, do NOT send any response (else Trumpet Winsock trips over this) - if the command line buffer has overflown in the past, do NOT send any response (else Trumpet Winsock trips over this) - clear data-mode send buffer after connecting to WebSocket server - fixed &F command, it now no longer terminates commmand line evaluation
|
The first problem with the Trumpet Winsock auto-dialler is fixed, but not the second one. It's true that the 16550A raises an interrupt for Modem Status Register changes (when it's asked to), I'm trying to add it but I'm struggeling a bit with class UART. Since there wasn't any Modem in v86 before, I think I'm the first to use the UART's Modem Status register, this register's delta bits and the associated interrupt. A plain serial connection doesn't use any of these. I thought I had figured out what to change in uart.js (raising the Modem Status Register interrupt under the right conditions), but the guest freezes the moment the interrupt is raised. So I looked a bit deeper into class UART, and I believe to have found several issues around this, it's a bit of a rabbit hole. I don't remember all the 16550A details (it's been forever that I worked directly with one), so before I can get into details I'll have to check some things in the datasheet, ugh. Not sure what I've stumbled into this time, but does it sound plausible what I'm thinking? How (well) was this tested, if I may ask? :-) |
Well, it was ported from jor1k and most other changes after that were quick fixes. The modem status was added in #980. |
Looks like I just fixed it, the auto-dialler is now working without any issues (yeah!). I'll post more about this tomorrow. |
Please see the comment in method UART.set_modem_status_bit() for details
about the MSR.
1. Fixed register read access to MSR, we must return the unmodified MSR
value to the PC before clearing its delta bits.
2. Removed register write access to MSR (MSR is a read-only register).
3. Removed UART bus event handler for "serial<N>-modem-status-input(data)" and
its accompanying API method V86.serial_set_modem_status(serial, status).
Without detailled documentation about the MSR it's too easy to derail the
internal state of class UART with this level of access. Instead use these
methods to modify the MSR:
V86.serial_set_carrier_detect(serial, status)
V86.serial_set_ring_indicator(serial, status)
V86.serial_set_data_set_ready(serial, status)
V86.serial_set_clear_to_send(serial, status)
I checked and couldn't find the bus event or V86 method used anywhere
in v86.
4. Replaced UART.set_modem_status(status) with UART.set_modem_status_bit(msr_bit, set_bit)
This simplified (also fixed?) implementation of UART bus event handlers:
serial<N>-carrier-detect-input(data)
serial<N>-ring-indicator-input(data)
serial<N>-data-set-ready-input(data)
serial<N>-clear-to-send-input(data)
5. Added MSR interrupt management, when interrupts are enabled: raise when
any MSR delta bit is set, lower after MSR has been read.
6. Normalized source code formatting of a few methods.
That BBS mentioned there must have not used interrupts for the MSR and must have ignored the MSR delta bits in order to work. That's very, very old-school. I've revised the UART's Modem Status Register (MSR) implementation, please see commit 44b9e08 for details. I hope the third point in the commit comment is Ok (my goal is to simplify things), I think the UART method that I removed only complicates things unneccesarily. I'm aware that this might potentionally break other v86 applications in the field, but there's a clear path which methods to use instead. Trumpet Winsock turned out to be a good sparring partner for the Modem, getting that auto-dialler to work lead to a bunch of fixes. Here's a short video of the basically unmodifed Trumpet Winsock auto-dialler (only minor things like the COM port were configured previously): win311-trumpet-winsock.mp4I've re-uploaded the Win3.11 image file here: win311-128m.zip, there were a few leftover misconfigurations with Trumpet Winsock. This is the image I've used in the video (it's so much simpler to use than Trumpet's Manual login procedure from above). I think this PR is good to go now! |
Addresses #1512.
Add a serial Modem device, see the included documentation for a user guide.
With a few exceptions, this device follows ITU Recommendation V.250 in regards to the AT command interpreter, AT command syntax and the chosen subset of AT commands.
The UART class had to be extended to emit bus messages for changes of its DTR and RTS hardware signals.
There is a slight ugliness in the Modem constructor: It needs to use the bus to send configuration messages to the UART device, but the bus/UART isn't ready at that point in time, so this is delayed until bus event "emulator-ready" is received. It works reliably, but is there a better pattern for this, perhaps move the Modem construction down in the v86 boot sequence to a later point in time, after the CPU has initialized? Or add and call a method Modem.initialize() that is called after CPU initialization?
The only open issue left is what to store in v86 state snapshots for this device, I thinks this needs to be talked over. For now I've left out Modem.get_state() and set_state() entirely.