Search This Blog

Sunday, July 29, 2018

ChibiTerm - PS/2 keyboard and terminal emulation

Projects / ChibiTerm  Original post date: 03/26/2016

I have rewrote most of the low level PS/2 routines for the event handling loop for this project. It is a pain as it was a lot easier to code as a thread in my RTOS code with message queues, mutex and non-blocking I/O than a finite state machine that have to remember where it was every time a new byte from the PS/2 shows up. Kind of like those mystery amnesia story having to reconstruct what has happened every time the MC wakes up and he has to scribble a note for himself before going to bed.

The error handling and time out logic was a bit of a nightmare, but I think I have most of it working with exception of hot plugging recovery of a keyboard. (Neither can some of the older PC.) Hot-plugging the keyboard might introduce glitches at the PS/2 clock line, the IRQ code might get out of sync. The IRQ code only checks on for parity errors and unexpected inputs, so it might take close to a dozen keys (depending on luck) before realizing it is out of sync and resets the keyboard.

I have added the following piece of code at the top of the IRQ that checks for an idle time out for the incoming clock bit and reinitializes the variables. It works really well as I can type right after hot-plugging in a keyboard. MicroTimer1 is decremented at each horizontal sync.


if(!MicroTimer1)
  PS2_IF.Init = 0;
        
MicroTimer1 = us_to_Tick(PS2_BIT_TIMEOUT);

I got some of the PS/2 raw scan code translated to ASCII code. The keyboard recognizes the shift/control/caps lock/num lock keys and can update the keyboard LED accordingly. There are still quite a bit of work to be done as I have to figure out the key mapping of the function keys/cursor keys and numeric keypad etc. Terminal programs all seems to do different things.


Since the VGA text is really limited to monochrome and 8-bit buffer for characters, I am probably only going to have 2 character sets - normal+inverted ASCII 7-bit characters. I'll try to implement a baseline "No options" VT100 terminal and something enough to use a Linux console for full screen file editing.

Only going to worry about US keyboard for now as that's what I use. The PS/2 raw keycode translation is done in a table and the fonts can be imported, so hopefully people can localize that.

Right now I have yet to implement the support for a cursor efficiently. Seems like taking snapshots and swapping character in the text buffer is going to be a bit of a pain, but better that than complicating the rendering code.

Before I knew it, I have implemented a very simple dumb terminal. I have yet to implement the non-text keys and the fancy ANSI escape sequence.

I was thinking too much as updating the cursor in an IRQ as it is not an easy thing to do without some synchronization mechanism. I overlook the possibility of updating the cursor in another task. Since the tasks run all the way to its end, sharing variables between them do not need synchronization.
"On the standard VGA, the blink rate is dependent on the vertical frame rate. The on/off state of the cursor changes every 16 vertical frames, which amounts to 1.875 blinks per second at 60 vertical frames per second."
The cursor task get called every 16 frames alternating between the cursor character or the text under it. That actually works quite nicely as the new text simply overwrites the cursor until the next time the task get called again and pops up at the new location without leaving a trail.

Trying to conserve RAM as much as I can right now as I have only 40 bytes of RAM left.

I have refractored some of my code to use packed bitfields instead of bitwise logic operations. While the amount of RAM usage is the same, ARMCC seems to be using slightly more code space than my original code. ARMCC is pretty good as I have refractored my code a different way in the past only to find out it uses the same amount of memory. The code is a bit more readable for the extra tens of bytes of code space and the compiler will allocate more space transparently when more bitfields are needed. This is both good and bad at the same time I guess.

At some point, I'll need to analyse the maximum amount of FIFO usage to tune them for RAM usage. The code usage is quite compact as I am coding in bare metal and not using a lot of library functions. ARM code also have a good code density. The terminal demo uses just over 6KB of FLASH.

I have been reading over a few web pages on the parsing of ANSI sequence. They all pretty much say parse the data first before trying to decode the sequence. This is going to be finite state machine work again. The terminal sends back report packets, so having the keyboard and receive data in separate task seems to be the right move again.

I think I have a good idea on what's needed to follow the specs, but implementing the quirky behaviour of a VT100 that programs relies on might be a different matter.


No comments:

Post a Comment

Note: Only a member of this blog may post a comment.