Heath8080A — Product Design : H-19 Terminal

Page last updated

home   release   support   design   resources   legal   site map

21-December-2002

 

On this page

overview
keyboard mapping
graphic characters
character pacing
output processing
cursor display

Related links

system architecture
i/o package

H-19 Terminal

This page describes the emulator's implementation of the H-19 terminal.

A complete emulation of the H-19 was not completed; the device has a number of capabilities, such as the ability to interpret a set of ANSI escape sequences, that were not implemented. Refer to limitations for a complete list.


H-19 Overview

The H-19 Emulator supports the following capabilities.

Power-on configuration

  • underscore cursor;
  • discard at end of line (no wrap from column 80);
  • no auto-CR or auto-LF;
  • Heath-mode escape sequences (ANSI will not be supported at all);
  • keypad normal and unshifted.

All but Heath-mode escape sequences can be overridden by escape sequences after the emulator is started.

Tabs will be fixed at columns 9, 17, 25, 33, 41, 49, 57, 65, 73, 74, 75, 76, 77, 78, 79 and 80. A tab from column 80 will not move the cursor.

Block Diagram

Note: The words "transmit" and "receive" are used from the viewpoint of the H8, not the H-19.

H-19 Block Diagram

In order to support "scroll mode," characters are received into a buffer. The H-19 issues Xoff when the buffer is 80% full and Xon when the buffer is 25% full.

Mac keystrokes are translated and passed into a pacing buffer so that multiple-character sequences don't overrun the serial port (remember, we don't have an actual, slow serial line to slow things naturally). Incoming characters are paced at a rate of 200 cps.

The emulator can put characters into the receiver buffer in two cases:

  1. It needs to issue Xon or Xoff.

  2. A "transmit page" or "transmit 25th line" operation is executed. These operations can result in a burst of input that greatly exceeds the screen size.

As of release 5.3.2, you can paste text from the clipboard into the H-19 window. This text is sent to the H8 as if it were typed at the keyboard. The paste buffer is not passed through the receiver buffer; rather, the emulator bypasses the receiver buffer when pasting text. Pasted text and text coming from the keyboard or H-19 buffer will not intermingle.

The H-19 terminal window has a "spring open" feature. If the terminal window has not been displayed since the emulator was started, the first printable character output will cause the window to open in front of the PAM/8 GUI. This allows the user to key the boot address and press "go" and be able to use the H-19 immediately without fooling around with emulator menus.

When booting an HDOS 1.6 disk or a newly-sysgened HDOS 2.0 disk, HDOS will sound PAM/8's alarm and display "SPACE" in the front-panel LEDs to prompt the user to press the space key so HDOS can determine the terminal baud rate. In this instance, the user will have to manually display the terminal window before pressing space.

go to top


Keyboard Mapping

Keyboard Processing Overview

The Macintosh key-down event record contains both an ASCII character code and a virtual key code. While several keys on the keyboard may produce the same ASCII character — there are two "=" keys, for example — there is a one-to-one mapping between physical keys and virtual key codes that is consistent across all Macintosh keyboard layouts.

It's most convenient to use the virtual key code to identify keys to be mapped to H-19 emulation functions. In the documentation that follows, "virtual key code" refers to the unique key identifier and "ASCII character code" refers to the normal ASCII value of the keystroke.

The main body of the Macintosh keyboard has virtual key codes less than 0x41. All other key codes are equal to or greater than 0x41. This is actually a quite convenient bit of luck, in that it improves keyboard translation performance on the touch-typing keys. In pseudo-code, keyboard translation proceeds as follows:

    if (virtual key code is less than 0x41)
      if (the option key is down)
        translate key code against main keyboard function key table
        (option-1 = F1, etc.)
    
        if ( no hit in table )
          if ( virtual key code = scroll key or break key )
    
            handle these keys locally
    
      else
        send the ASCII character code to the H8 serial port
    
    else // virtual key code must be >= 0x41
    
      if ( virtual key code = the clear key )
        handle clear locally
    
      else if ( virtual key code = top row F9 )
        handle scroll locally
    
      else if (virtual key code = top row F12)
        handle break locally
    
      else
    
        if ((shift_mode xor shift_key) == '1')
    
          translate key code against the shifted keypad table
          (cursor keys, insert/delete char, etc.)
    
          if (no hit in table)
            if (virtual key code = IC key)
              if ( we are in insert-character mode )
                   send  exit-insert-character-mode sequence
              else send enter-insert-character-mode sequence
    
          else if (alternate keypad mode set)
                translate key code against the alternate keypad table
    
        else
          translate key code against the normal keypad table
    end
    

The search tables have the following format:

    typedef struct {
        unsigned char vkc;    // virtual key code
        char *str;            // output string
    } keyXlateTab, *keyXlateTabPtr;
    

Each table is sorted in virtual key code order. The last vkc in the table is 0xff. If there is no match in the table, and with the exception of the keys handled separately as noted in the pseudo code above, the keystroke will be ignored.

Keyboard Translation

The "keyboard translation" function (ref. h-19 overview) will perform the following mappings:

    Function Key Mapping

    H-19 Key

    Mac Key

    Virtual Key Code

    Output Sequence

    F1

    F1

    0x7a

    esc S

    F2

    F2

    0x78

    esc T

    F3

    F3

    0x63

    esc U

    F4

    F4

    0x76

    esc V

    F5

    F5

    0x60

    esc W

    Erase

    Replaced with the keypad Clear key. See "Other Mac Key Mappings" table below.

    Blue

    F6

    0x61

    esc P

    Red

    F7

    0x62

    esc Q

    Gray

    F8

    0x64

    esc R

    Scroll

    F9

    0x65

    (1)

    Break

    F12

    0x6f

    (2)

     

     

     

     

    F1

    option-1

    0x12 (w/ option)

    esc S

    F2

    option-2

    0x13 (w/ option)

    esc T

    F3

    option-3

    0x14 (w/ option)

    esc U

    F4

    option-4

    0x15 (w/ option)

    esc V

    F5

    option-5

    0x17 (w/ option)

    esc W

    Erase

    Replaced with the keypad Clear key. See "Other Mac Key Mappings" table below.

    Blue

    option-6

    0x16 (w/ option)

    esc P

    Red

    option-7

    0x1a (w/ option)

    esc Q

    Gray

    option-8

    0x1c (w/ option)

    esc R

    Scroll

    option-9

    0x19 (w/ option)

    (1)

    Break

    option-=

    0x18 (w/ option)

    (2)

Notes:

  1. The scroll key is a local function. When in scroll mode, pressing scroll will cause the next line of output to be displayed, and shift-scroll will cause the next page of output to be displayed. Scroll simply controls how many lines are pulled from the output buffer.

  2. The break key will cause the Break and Framing Error bits to be set in port 350q's status register.

    Normal, Unshifted Keypad Mapping

    H-19 Key

    Mac Key

    Virtual Key Code

    Output Sequence

    0

    0

    0x52

    0

    1

    1

    0x53

    1

    2

    2

    0x54

    2

    3

    3

    0x55

    3

    4

    4

    0x56

    4

    5

    5

    0x57

    5

    6

    6

    0x58

    6

    7

    7

    0x59

    7

    8

    8

    0x5b

    8

    9

    9

    0x5c

    9

    .

    .

    0x41

    .

    Enter

    Enter

    0x4c

    015



    Shifted Keypad Mapping

    H-19 Key

    Mac Key

    Virtual
    Key Code

    Output
    Sequence

    Function
    Description

    0

    0

    0x52

    0

     

    1

    1

    0x53

    esc L

    insert line

    2

    2

    0x54

    esc B

    down

    3

    3

    0x55

    esc M

    delete line

    4

    4

    0x56

    esc D

    left

    5

    5

    0x57

    esc H

    home

    6

    6

    0x58

    esc C

    right

    7

    7

    0x59

    esc @/esc O

    enter/exit
    IC mode

    8

    8

    0x5b

    esc A

    up

    9

    9

    0x5c

    esc N

    delete char

    .

    .

    0x41

    .

     

    Enter

    Enter

    0x4c

    015

    return



    Alternate Keypad Mapping

    H-19 Key

    Mac Key

    Virtual Key Code

    Output Sequence

    0

    0

    0x52

    esc ? p

    1

    1

    0x53

    esc ? q

    2

    2

    0x54

    esc ? r

    3

    3

    0x55

    esc ? s

    4

    4

    0x56

    esc ? t

    5

    5

    0x57

    esc ? u

    6

    6

    0x58

    esc ? v

    7

    7

    0x59

    esc ? w

    8

    8

    0x5b

    esc ? x

    9

    9

    0x5c

    esc ? y

    .

    .

    0x41

    esc ? n

    Enter

    Enter

    0x4c

    esc ? M



We have a number of additional keys available on the Mac extended keyboard that we might as well take advantage of. These keys will be supported as follows:

    Other Mac Key Mapping

    Mac Key

    Virtual
    Key Code

    Normal
    Output Sequence

    Alternate Keypad
    Output Sequence

    cursor up

    0x7e

    esc A

    esc ? x

    cursor left

    0x7b

    esc D

    esc ? t

    cursor right

    0x7c

    esc C

    esc ? v

    cursor down

    0x7d

    esc B

    esc ? r

    home

    0x73

    esc H

    esc ? u

    end

    0x77

    (key suppressed)

    n/a

    page up

    0x74

    (key suppressed)

    n/a

    page down

    0x79

    (same as
    shift-scroll)

    n/a

    del

    0x75

    esc N

    esc ? y

    clear
    (keypad)

    0x47

    esc J

    n/a

    shift-clear
    (keypad)

    0x47
    (w/ shift)

    esc E

    n/a

    keypad =

    0x51

    =

    n/a

    keypad /

    0x4b

    /

    n/a

    keypad *

    0x43

    *

    n/a

    keypad -

    0x4e

    -

    n/a

    keypad +

    0x45

    +

    n/a



Finally, there are eight command keys with local functionality. Note that the command key is held down to activate each key.

    Local Command Keys

    Mac Key

    Virtual
    Key Code

    Emulator Function

    command-clear

    0x47

    Clears the H-19 screen without transmitting anything to the H8.

    command-F9 (scroll)

    0x19

    Toggles hold mode on/off locally, without transmitting anything to the H8.

    command-home

    0x73

    Scrolls to the top of the 500-line scroll-back buffer.

    command-end

    0x77

    Scrolls to the bottom of the 500-line scroll-back buffer.

    command-page up

    0x74

    Scrolls up one page (23 lines) in the scroll-back buffer.

    command-page down

    0x79

    Scrolls down one page (23 lines) in the scroll-back buffer.

    command-up arrow

    0x7e

    Scrolls up one line in the scroll-back buffer.

    command-down arrow

    0x7d

    Scrolls down one line in the scroll-back buffer.



The scroll command keys effectively duplicate the functionality of the H-19 window scroll bar.

go to top


H-19 Graphics Character Generation

The emulator uses a modified a copy of the Monaco 10-point font which contains the H-19 graphic characters. The font is named "Heath 10."

The graphic characters replace the special characters at ASCII offset 336Q through 376Q in the font set ("Q" indicates octal notation). To display a graphics character, add 200Q to the corresponding ASCII character. Example: The first graphics character is the raised dot, corresponding with the ^ character, which is ASCII 136Q. 136Q + 200Q = 336Q or 222D, which is where the raised dot is in the font.

Here is the full set of graphics characters along with the octal and graphic representation of the corresponding normal character.

H-19 Graphics Characters

go to top


Character Pacing

As noted in H-19 Overview, all characters to be sent to the H8 are placed into a receive buffer. H8 input must be paced so that we don't exceed around 500 characters per second.

The mechanism used is the 1ms emulation clock tick. On every other tick, we check to see whether there's a character in the buffer. If so, that character is placed on the UART via a call to ioPutSerialData.

For any given keystroke, there is a delay of up to 2ms before it appears on the UART. At present, there's a delay of up to 25ms before we get that keystroke from the Mac Event Manager, and this extra delay isn't noticeable.

(The original plan had been to input at a rate of around 1,000 cps. In testing this proved to be too fast for the emulated H8, which lost the occasional leading ESC character in a function key sequence. Slowing the rate to 500 cps has proven to be 100% reliable.)

Starting with release 4.1, outbound characters are paced so that output does not exceed 2,000 characters per second. Again, this is done using the 1ms emulation clock tick. On each tick, a 2-character output quota is refreshed. h19Status (ref. I/O Package) will return transmitterEmpty status only if this count is non-zero.

go to top


Output Character Processing

Note — Output, in this case, refers to characters sent by the H8 to the H-19 terminal.

Logic

H-19 terminal output processing is table driven, using a series of tables that taken together denote the state of the output data stream. Each time a character is output, the current table is searched and the appropriate action taken.

The tables are defined as follows:

    typedef struct {
        unsigned char outputChar;   // output by the H8
        int nextTableNdx;           // next table ndx
        void (*procRoutine) (void); // processing routine
    } outXlateTab, *outXlateTabPtr;
    
    outXlateTabPtr nextTable[] = { outNormal, outEsc, ... };
    

If the processing routine is nil, none will execute. But the table address will change to the next table. The last entry, outputChar = 0xff, will match any character output.

Let's process one easy example. The initial state has the current table set to the default table.

  1. A character (ESC) is output. We search the current table and find the character. Processing routine is nil so nothing is done. The current table pointer is changed (outEsc).

  2. A character (Y) is output. We search the current table and find the character. Processing routine is nil so nothing is done. The current table pointer is changed (outRow).

  3. A character (row) is output. We search the current table and find the final, default entry. Processing routine saves the row number. The current table pointer is changed (outCol).

  4. A character (col) is output. We search the current table and find the final, default entry. Processing routine saves the column number, and moves the cursor to the correct coordinates. The current table pointer is changed (outNormal).

  5. A character (A) is output. We search the current table and find the final, default entry. Processing routine updates the screen and moves the cursor to the right. The current table pointer is changed (outNormal).

The cascading order of tables effectively parses the output and sees that the correct function is performed for each character or escape sequence.

Output Escape Sequences

The characters following "esc" in the following tables are case sensitive. Esc is, of course, 033q (27d).

    Cursor Functions

    Escape Sequence

    Mnemonic

    Definition

    esc H

    HCUH

    cursor home

    esc C

    HCUF

    cursor forward

    esc D

    HCUB

    cursor backward

    esc B

    HCUD

    cursor down

    esc A

    HCUU

    cursor up

    esc I

    HRI

    reverse index

    esc n

    HCPR

    cursor position report

    esc j

    HSCP

    save cursor position

    esc k

    HRCP

    set cursor to previously saved position

    esc Y r c

    HDCA

    direct cursor addressing



Additional information:

cursor motion

None of the cursor movement functions in this table will cause the screen to scroll or move the cursor past the margins of the screen. For example, HCUU on line 1 will leave the cursor on line 1.

HCUU and HCUD do nothing when the cursor is on line 25.

HCPR

The response to Cursor Position Report is the sequence "esc Y r+31, c+31" where 'r' and 'c' are the current cursor row and column.

HRI

Reverse Index is Line Feed in reverse. HRI will move the cursor up one row. When issued with the cursor on line 1, the screen is scrolled down one line and a new blank line is opened on line 1.

(Note: The character following esc is an upper-case I ("eye")).

HDCA

Position the cursor to a specific row and column. The cursor is positioned to row 'r'-31 and column 'c'-31. If the resulting row is invalid, the cursor stays on its current row. If the resulting column is invalid, the cursor moves to column 80.

Direct Cursor Addressing is the only way to move the cursor to line 25. Line 25 must be enabled before moving the cursor there. Otherwise, it's considered to be invalid and the cursor will stay in its current row.

    Erasing and Editing

    Escape Sequence

    Mnemonic

    Definition

    esc E

    HCD

    clear display (shift erase key)

    esc b

    HBD

    erase beginning of display

    esc J

    HEOP

    erase to end of page (erase key)

    esc l

    HEL

    erase entire line

    esc o

    HEBL

    erase beginning of line

    esc K

    HEOL

    erase to end of line

    esc L

    HIL

    insert line

    esc M

    HDL

    delete line

    esc N

    HDCH

    delete character

    esc @

    HEIM

    enter insert character mode

    esc O

    HERM

    exit insert character mode



Additional information:

HIL

After an insert line, the cursor is left in column 1 of the inserted line.

HDL

After a delete line, the cursor is left in column 1 of the line following the deleted line. A new blank line is inserted on line 24.

HEL

The character following the esc is a lower case L.

    Configuration

    Escape Sequence

    Mnemonic

    Definition

    esc z

    HRAM

    reset to power up configuration

    esc x [n]

    HSM

    set (enable) operating mode

    esc y [n]

    HRM

    reset (disable) operating mode



The following Configuration Modes replace the [n] in the HSM and HRM sequences above.

    Configuration Modes

    Configuration Mode

    Definition

    1

    enable/disable line 25

    3

    enable/disable hold screen mode

    4

    enable/disable block cursor

    5

    enable/disable cursor off

    6

    enable/disable shifted keypad

    7

    enable/disable alternate keypad mode

    8

    enable/disable auto line feed on receipt of CR

    9

    enable/disable auto CR on receipt of line feed



Additional information:

unsupported Heath functions

A real H-19 will also support:

  • modify baud rate (esc r [b])
  • disable/enable key click (esc x 2 & esc y 2)
  • enter ANSI mode (esc <)

These are not supported by this emulator. You can send the sequences to the terminal and they will be "eaten" but not processed.

enable/disable cursor

Please notice the odd case, here: You are enabling the cursor to be off, and disabling that condition to turn the cursor on.

    Modes of Operation

    Escape Sequence

    Mnemonic

    Definition

    esc [

    HEHS

    enter hold screen mode

    esc \

    HXHS

    exit hold screen mode

    esc p

    HERV

    enter reverse video mode

    esc q

    HXRV

    exit reverse video mode

    esc F

    HEGM

    enter graphics mode

    esc G

    HXGM

    exit graphics mode

    esc t

    HEKS

    enter keypad shifted mode

    esc u

    HXKS

    exit keypad shifted mode

    esc =

    HAKM

    enter alternate keypad mode

    esc >

    HXAM

    exit alternate keypad mode



Additional information:

hold screen mode

You can toggle hold screen mode locally by typing command-Scroll (that's command F9 or command-option-9). This local toggle does not transmit escape sequences to the H-19.

alternate keypad

The keypad in alternate mode replaces the normal mode; it is not possible to get the digits 1-9 from the keypad until you exit alternate keypad mode.

The shifted-mode sequences are not affected by alternate keypad mode.

shifted keypad

Shifted keypad mode reverses the shift mode of the keypad. For example: when in keypad shifted mode pressing '1' will send the Insert Line sequence, while pressing shift-1 will send either '1' or esc ? q, depending on the alternate keypad mode setting.

    Additional Functions

    Escape Sequence

    Mnemonic

    Definition

    esc v

    HEWA

    wrap around at end of line

    esc w

    HXWA

    discard at end of line

    esc Z

    HID

    identify as VT52 (send esc K)

    esc ]

    HX25

    transmit 25th line

    esc #

    HXMP

    transmit page

    cr

     

    carriage return

    lf

     

    line feed

    bel

     

    bell

    tab

     

    horizontal tab

    bs

     

    backspace



Additional information:

unsupported Heath functions

A real H-19 will also support enable/disable keyboard (esc { and esc }). These are ignored in this emulator.

HID

Sending HID simply causes the emulator to return esc K. Pointless? Sure. But there it is.

HX25 and HXMP

These sequences will cause line 25 or lines 1-24 to be transmitted to the H8. Transmission proceeds as follows:

  • each character is sent in turn starting at line 1 column 1 and proceeding across then down the screen;
  • when transmitting the main screen, the cursor wraps from column 80 to column 1 of the next line but with no carriage return or line feed between lines;
  • the appropriate escape sequences are sent to enter and exit reverse video and graphics modes, depending on the characters encountered on the screen — effectively, what you get back is what you sent in the first place;
  • when the transmission is complete, a single carriage return is sent and the H-19 bell rings.

Due to the enter/exit reverse video and graphics sequences, the amount of data returned can be significantly more than the 80 or 1,920 characters on lines 25 and the main screen body, respectively. For example, if the last two characters on the screen are a normal character followed by a reverse-video graphics character, the last character of the screen will actually cause nine characters to be transmitted: enter reverse video, enter graphics, the character, exit reverse video, and exit graphics.

If there is a long string of text in a particular mode, the mode is changed only at the beginning and end of the string.

If line 25 is not enabled, HX25 will return only a carriage return.

horizontal tab

Tab will cause the cursor to move to the next tab stop. The tab stops are fixed at columns 8, 16, 24 , 32, 40, 48, 56, 64, 72, 73, 74, 75, 76, 77, 78, 79 and 80. A tab in column 80 will not move the cursor.

Tab moves the cursor over the characters on the screen. Blanks are neither inserted nor written over the characters on the screen.

go to top


Cursor Display

H-19 emulation spends an extraordinary amount of time drawing and undrawing the cursor. This was mitigated to a degree by batching character output; the cursor is removed and drawn for each small batch of characters instead of for each character output. But when there's a long, fast burst of output, all that cursor drawing is just unnecessary overhead.

QuickDraw is blazing fast, but overhead is overhead.

This overhead was removed by delaying the drawing of the cursor on the screen. The amount of delay could have been anything, really, but testing showed that at 25ms a human operator can actually see the delay. I settled on 10ms because cursor motion is uniform and smooth when typing or moving the cursor by hand, and yet it's long enough to ride over small gaps in a burst of output.

Cursor display is now done in the 1ms clock tick processing routine, and is controlled by three variables:

    int h19CursorDisplayed;     // cursor has been drawn
    int h19CursorDesired;       // cursor should be drawn
    int h19CursorTimer;         // 10ms delay timer
    

H-19 processing routines call insertCursor and removeCursor to put the cursor on the screen and take it off, respectively.

insertCursor

Instead of drawing the cursor, insertCursor sets h19CursorDesired to '1' and sets h19CursorTimer to 10. Unless removeCursor is called during that 10ms delay period, the cursor should appear on screen in 9-10ms.

removeCursor

If h19CursorDisplayed = 1, the cursor is removed from the screen and h19CursorDisplayed is set to 0. In either case, h19CursorDesired is set to zero.

h19Clock

If h19CursorDesired is set, h19Clock counts down the clock and calls drawCursor when the timer hits zero. (This among other functions.)

drawCursor

drawCursor draws the actual cursor on screen, clears h19CursorDesired, and sets h19CursorDisplayed.

Note — Regardless, the cursor is never displayed on screen if the cursor has been disabled (h19ModeCursor = 0) by an output escape sequence.

The cursor itself defaults to an underline, and can be configured as a block. The underline cursor is a black line drawn using modeXor so that it is visible in both reverse and normal video. The cursor is erased by simply redrawing the cursor.

The block cursor is drawn using the PaintRect function, with a drawing mode of patXor. As such, it shows on a normal screen as a black box with a reverse-video character inside, and is reversed on a reverse-video character. When the cursor is idle, it blinks at a rate of: on for one second, off for one-half second. The blink is accomplished simply by calling removeCursor and insertCursor.

go to top



home   release   support   design   resources   legal   site map