▼
Posts: 355
Threads: 67
Joined: Nov 2005
In the last weeks I updated Emu48 Classic to v1.51, Emu28 to v1.23 and Emu42 to v1.14. All three emulators for Win32 now contain an interface for a Redeye printer simulation.
Normally the calculator send infrared pulses in the Redeye format to a HP82240 printer. These pulses are decoded inside the HP82240 to a data byte stream. Because I have no real chance to transfer the infrared pulses over an interface inside a PC, I decided to integrate the Redeye format decoder inside the emulator listening at the STL bit of the LED control register at Emu28 and Emu42 and at the half bit frame generator bit at Emu48.
This beginning of this project go back to the year 2002 or 2003. Cyrille send me a decoder sample for Emu48 at this time. I know the Redeye format since I wrote a decoder for it in the early 90'ties, so I find it a good idea. But I also knew that an implementation for Emu42 is much more difficult. So I decided to integrate the Redeye decoder inside Emu42 first. Because I already wrote such an decoder in 8052 assembler, an implementation in C was rapidly done. But in not "Authentic Speed" mode weather a HP28S nor the HP42S was able to print 10 or 20 characters successfully. In "Authentic Speed" mode printing with a HP42S was working, but not with the HP28S. The reason for the HP28S in "Authentic Speed" mode is a timing issue, which base on the timer integration concept inside the Emu42 emulator. So I decided to use a workaround which you normally don't recognize. But the problem in non "Authentic Speed" mode (full running) was still left. I knew that the reason for this misbehaviour was inside the CPU cycle clock measurement (see also my MoHPC article Inside Saturn Emulator Timing, but I had no idea how to solve it. So I cancelled further working on this project for over 7 years. In spring 2011 I restarted the printing project and solved the timing problem. All three emulators now got the Redeye decoder.
But still a printer simulation was missing. IMHO it makes no sense to add a printer simulation to each emulator, so I decided to write a separate HP82240B printer simulation. After my experiences with TCP/IP in Emu71 I decided to use UDP for the inter-process communication between the calculator emulator and the printer simulator. So all emulators send their decoded bytes over IPv4 to the address "localhost" port 5025 by default. The address and port can be changed in the "Settings" dialog.
My new HP82240B printer simulator, available on my homepage at http://hp.giesselink.com/, set the main focus on text input. So the main window is a text mode window only. To support most of the Roman8 and ECMA94 character set, I decided writing an Unicode application with translation tables from the printer fonts to Unicode. So be aware to use a Unicode font which support most of the used characters and when you are doing Copy&Paste to a non Unicode editor, you will get conversation losses. This is a limitation, but after more than 10 years after introducing Unicode to a Windows OS, when should we begin using Unicode? But there's also an optional windows in the printer simulation showing the printer output in the original HP82240B printer font.
As input interface the HP82240B simulator support the native IPv4 UDP interface of the Emu28, Emu42 and Emu48 emulators, a serial COM port interface for the HP48 series wire interface and finally USB over the original HP USB driver used by Conn4x for supporting the HP48GII, HP49G+ and HP50G calculators. The display dump capture over a key isn't supported for the HP49G and later. Since the HP49G calculator the display dump over a key use a HP82240B incompatible format. Use Conn4x for a display dump instead please.
I hope you enjoy using the new printing capability of the emulators. For those which want to add the UDP interface to their own HP82240 emulator or simulator, just integrate a normal UDP server listening for the data byte stream on the given port.
Caution: On slow PC's especially NET books with Intel Atom CPU the printing may not work properly with loosing transferred data or with decoding errors inside the Emu28 and Emu42 emulator.
Christoph
▼
Posts: 3,283
Threads: 104
Joined: Jul 2005
Quote:
Caution: On slow PC's especially NET books with Intel Atom CPU the printing may not work properly with loosing transferred data or with decoding errors inside the Emu28 and Emu42 emulator.
You can remedy this by making the printer a multi threaded process with a buffer that reads the UDP packets and feeds them to the printer window at a suitable pace. I'm wondering why the IP stack doesn't take care of this, it should buffer the packets until they are fetched by the server.
▼
Posts: 355
Threads: 67
Joined: Nov 2005
Quote:
You can remedy this by making the printer a multi threaded process with a buffer that reads the UDP packets and feeds them to the printer window at a suitable pace. I'm wondering why the IP stack doesn't take care of this, it should buffer the packets until they are fetched by the server.
The receivers are implemented in a separate thread. Since USB support there's also a 64K print buffer between the receiver and the printing thread. Loosing characters happend very early in development on an Atom Net-book. With this last version the Net-book got defect characters from time to time. We recognized a heavy CPU usage at printing caused by Emu42 and the printer simulation. I have the suspicion that the redeye decoder inside Emu42 don't work properly at high CPU usage on slow machines.
Christoph
▼
Posts: 102
Threads: 3
Joined: Sep 2007
The redeye decoder addition sounds like a nice project. :)
Quote:
I have the suspicion that the redeye decoder inside Emu42 don't work properly at high CPU usage on slow machines.
I haven't looked at the code yet, but I assume that the redeye decode is native code (not calculator code emulated by the emulator).
As the redeye decoder is checking the output bit, is it operating independently of the emulated machine (polling the emulated register)? Or is it in lock-step with the emulator (being triggered by changes to the emulated register and delaying the emulator until the decoder has finished)?
It seems if it were operating in lock-step with the emulator, it would be impossible to miss bits but that might affect emulator timing.
If it is operating independently of the emulated machine, it has to poll the emulated register very frequently and might miss a bit transition if the CPU is under heavy load. If that is the case, it probably needs to be multi-threaded such that the polling thread is high-priority and stores transitions in a ring buffer, while the decoder thread pulls transitions out of the ring buffer and decodes them to send out via UDP.
Using a ring buffer would allow the polling thread to detect overflow if the decoder was not keeping up. That overflow condition could possibly be used to pause the emulator (again affecting emulator timing).
▼
Posts: 355
Threads: 67
Joined: Nov 2005
Quote:
Or is it in lock-step with the emulator (being triggered by changes to the emulated register and delaying the emulator until the decoder has finished)?
Yes, it's done by this way. I watch for the rising edge of the STL bit and count the CPU cycles between them. So the decoding is independent from the real CPU speed during emulation.
Christoph
Posts: 102
Threads: 3
Joined: Sep 2007
Quote: reads the UDP packets and feeds them to the printer window at a suitable pace. I'm wondering why the IP stack doesn't take care of this, it should buffer the packets until they are fetched by the server.
UDP is allowed to lose packets.
▼
Posts: 3,283
Threads: 104
Joined: Jul 2005
Quote:
UDP is allowed to lose packets.
I know, but I assume that is more relevant on a physical line than inside the stack. It's IP in general that allows packets being dropped, split and/or delivered out of order. UDP doesn't add any error recovery logic and leaves it to the application while TCP is designed to just do all the error handling transparently for the application.
▼
Posts: 102
Threads: 3
Joined: Sep 2007
Quote:
I know, but I assume that is more relevant on a physical line than inside the stack. It's IP in general that allows packets being dropped, split and/or delivered out of order. UDP doesn't add any error recovery logic and leaves it to the application while TCP is designed to just do all the error handling transparently for the application.
Almost all IP loss is in the stack on one end or the other. You can see this if you use a network sniffer. In the old days network hardware had very small buffers (memory was expensive and wire speeds were slow) and if the stack didn't get the packet out of the hardware in time it would be overwritten by the next packet coming in. Even then loss on the wire essentially never occurred unless the equipment or install was faulty.
Speaking as someone who has implemented such stacks, usually today the loss is because there is little or no buffer in the receiving stack. Being stateless, there is no way to know if the layer for whom the packet is intended is still expecting it, so if for some reason it cannot be delivered before the limited buffer is full and the next packet comes in, something will be lost. Sometimes the sender will also throw away a packet for a similar reason -- if the line send queue is full a packet will be dropped instead of added to the queue.
The physical line essentially never loses packets. The hardware on both ends tries very hard not to lose packets with sender retransmit when it detects a problem and large direct to memory ring buffers in modern receivers. Of course, there was and is nothing in the ethernet physical layer for the recipient to request a resend so loss can still occur, but it is rare unless you have faulty hardware. (With WiFi physical layer there is ACK/NAK, so loss is almost never in the physical layer.)
▼
Posts: 3,283
Threads: 104
Joined: Jul 2005
Thanks for the insight. When IP was invented, things were different, of course: Wide area connections were unreliable and slow and CSMA/CD as the underlying Ethernet technology (shared media) for local networks is prone to data loss, too.
Either way, losing packets is part of IP and must be handled somewhere. I was thinking that modern implementations would have large memory buffers and only drop a packet when its TTL (time to live) field indicates it, but with the high speed networks of our days, this might not be the case.
The case of the printer emulation is special: with localhost being the destination there isn't a physical line involved at all so packet loss must occur in the software. I see two possible causes: The sender (low level IP driver) blocks because of a buffer full situation and this makes the timing critical decoder of the IR bit stream loss synchronization, or, if the sender does not block, packets are simply dropped if they don't fit in the available buffers. To get out of this situation, a lock-step method between the encoder and the decoder together with a large enough buffer in the printer emulator would be the only safe option.
▼
Posts: 355
Threads: 67
Joined: Nov 2005
TNX for the discussion above. I liked it very much forcing me to rethink about some implementation details. But I still think my implementation is ok.
The net-book (Win7 starter) I'm speaking about made trouble several times before. On almost all emulators on fast key input it loose keys, furthermore playing a keyboard macro works only with a very large delay between keystrokes.
The UDP packet loss on this machine happened with the two thread solution: 1st thread Main Windows and message loop, 2nd data receiver, converting and printing. An earlier proof of concept program with UDP server and text output only, worked without packet/byte loss.
The actual printer simulator is a three thread solution: 1st thread Main Windows and message loop, 2nd receiver thread putting the data into a 64K ring buffer, 3rd thread fetching the data from the ring buffer converting and printing. With this version we recognized no packet loss with UDP, but characters with code 127, which I use when I detected a decoding error in the emulator.
The ring buffer was primarily added for the USB receiver, because I also had CPU usage dependent character losses. It not really fixed the entire problem at USB, I had to do some additional work in the USB receiver thread to get rid of the problem, but it improved the software design and made some things easier.
Christoph
▼
Posts: 3,283
Threads: 104
Joined: Jul 2005
Quote:
With this version we recognized no packet loss with UDP, but characters with code 127, which I use when I detected a decoding error in the emulator.
I'm still wondering how this can happen with a fully synchronized (lock-step) decoder. A slow computer should slow down everything but not introduce such artifacts. Is there any timing involved in the decoder? Does it in fact poll the output triggered by the firmware in an independent thread or do you trap the toggle of the output when it's done? How do you determine the number of emulated clock cycles between state changes?
▼
Posts: 355
Threads: 67
Joined: Nov 2005
Quote:
Is there any timing involved in the decoder?
Not in the decoder itself. I had to slow down emulation speed during CPU speed measurement of the firmware which I described in MoHPC articel 1113. With the result of the speed measurement, the firmware generates the IR timing for the STL bit.
Quote:
How do you determine the number of emulated clock cycles between state changes?
The clock cycles are part of the CPU opcode emulation and are the basic for the "Authentic Speed" mode. In the case of the Redeye decoder I know that the first three IR data frames of each data byte are sync frames with half bit length, so I can combine the measured CPU cycles to the half bit length.
Christoph
Posts: 125
Threads: 9
Joined: Oct 2011
Christoph
Thanks for this work. Emu42 running an HP28S ROM, and EMU48, are in constant use on my computer desktops. I look forward to trying the latest versions.
Lately I noticed that Emu42.1.13 running the HP28S ROM sometimes has the empty battery annunciator active at times, which is unexpected.
Nick
▼
Posts: 355
Threads: 67
Joined: Nov 2005
Quote:
Lately I noticed that Emu42.1.13 running the HP28S ROM sometimes has the empty battery annunciator active at times, which is unexpected.
You run Emu42 on a battery powered computer. The Win OS know three battery states: OK, Low Bat, Critical. You see these states also in the Bat annunciator of the emulated calculator. This is a wanted emulated feature.
Christoph
▼
Posts: 125
Threads: 9
Joined: Oct 2011
Christoph
In that case, it is a clever feature :-)
Nick
|