QBasic/QuickBASIC Program Downloader


================================================================
' Author: Jorge Codina 12 November 1994
' 
' heroload.bas
' Qbasic program to transfer a machine lang file to the HERO via the 
' PC's Printer Port and the HERO's Expansion Board
' 
' The Cable is a standard PC Printer Coble with the 36 Pin Centronics
' Connector removed.
' The wiring is as follows:
' 25 Pin D-Shell    Hero Expansion Board
'   2               DI0
'   3               DI1
'   4               DI2
'   5               DI3
'   6               DI4
'   7               DI5
'   8               DI6
'   9               DI7
'  17               INT
'  18-25            GND
'
' To run this program:
' 1) enter the program "hcode7.txt" into the HERO via the HEX
'    Keypad or cassette
' 2) Attach the cable to a printer port and the HERO, Change the
'    DataPort address below if necessary
' 3) Start the HERO load program by entering AD 00 60 on the HEX
'    Keypad 
' 4) execute Qbasic /RUN heroload
' 5) Enter the filename to load
' 6) When done the HERO will return to the Executive and say "READY"
'
' The program writes a file to the HERO in a predefine format
' All Address and Data bytes are represented by 2 hex characters
' first two bytes are the starting program address
' the last two byte are "S9"
' eventually this program and the HERO load code will be re-written
' to accept true S-Record format
'
' After each byte is written on the DataPort
' control pin three (D25 pin 17) is set LOW
' to signal an interupt to on the HERO
'
' StatusPort is not used in this program
'
' DataPort = &H3BD  First Printer Port, Mono adaper card, not present
' DataPort = &H378  Second Printer Port, LPT1 on my system

CONST DataPort = &H278      'Thrid Printer Port, LPT2 on my system
CONST StatusPort = DataPort + 1
CONST ControlPort = DataPort + 2
CONST TRUE = 1
CONST FALSE = 0
CONST IntOff = &H0
CONST IntOn = &HFF

DIM WorkByte AS STRING * 1

DIM ByteNo AS INTEGER
DIM ProcessCount AS INTEGER
DIM SkipFlag AS INTEGER

OUT ControlPort, IntOff    'set interupt high

INPUT "Enter file to send to HERO: ", HeroProgram$

IF HeroProgram$ = "" THEN END

OPEN HeroProgram$ FOR RANDOM AS #1 LEN = 1

ByteNo = 0
ProcessCount = 0

'
'Main Loop
'
DO
    SkipFlag = FALSE
    ByteNo = ByteNo + 1
    ProcessCount = ProcessCount + 1
    GET #1, ByteNo, WorkByte
'
'       Skip Comments
'
    IF (ASC(WorkByte)) = 59 THEN          'it is a semi-colon ;
        GOSUB SkipCommentLine
    END IF
'
' Check for "S" (record header)
'
    IF (ASC(WorkByte)) = 83 THEN       'it is an "S"
        GOSUB HeaderProcess
    END IF
'
' skip anything not between 0-9 and A-F
'
    WByte = ASC(WorkByte)
    IF WByte < 48 OR WByte > 70 THEN
        SkipFlag = TRUE
        ProcessCount = ProcessCount - 1
    END IF
    IF WByte > 57 AND WByte < 65 THEN
        SkipFlag = TRUE
        ProcessCount = ProcessCount - 1
    END IF
'    
    IF SkipFlag = FALSE THEN
        IF (ProcessCount MOD 2) = 0 THEN
            SecondByte$ = WorkByte
            GOSUB SetHex
        ELSE
            FirstByte$ = WorkByte
        END IF
    END IF
LOOP UNTIL (EOF(1))
END


'
' SkipCommentLine
'
' Skip over the rest of the line
' Returns when it hits a Line Feed (Ascii 10)
' Line feed is the character left in WorkByte
'
SkipCommentLine:
DO
    ByteNo = ByteNo + 1
    GET #1, ByteNo, WorkByte
LOOP UNTIL (ASC(WorkByte)) = 10
RETURN


'
' SetHex
'
' FirstByte$ and SecondByte$ both contain ascii characters between 0-9
' or A-F. FirstByte is HighOrder and must be multiplied by 10h.
' SecondByte is LowOrder. Together they make up one byte to be sent
' to the HERO.
'
SetHex:

    SELECT CASE SecondByte$
        CASE "0"
            SecondByte = &H0
        CASE "1"
            SecondByte = &H1
        CASE "2"
            SecondByte = &H2
        CASE "3"
            SecondByte = &H3
        CASE "4"
            SecondByte = &H4
        CASE "5"
            SecondByte = &H5
        CASE "6"
            SecondByte = &H6
        CASE "7"
            SecondByte = &H7
        CASE "8"
            SecondByte = &H8
        CASE "9"
            SecondByte = &H9
        CASE "A"
            SecondByte = &HA
        CASE "B"
            SecondByte = &HB
        CASE "C"
            SecondByte = &HC
        CASE "D"
            SecondByte = &HD
        CASE "E"
            SecondByte = &HE
        CASE "F"
            SecondByte = &HF
    END SELECT

    SELECT     CASE FirstByte$
        CASE "0"
            FirstByte = &H0
        CASE "1"
            FirstByte = &H10
        CASE "2"
            FirstByte = &H20
        CASE "3"
            FirstByte = &H30
        CASE "4"
            FirstByte = &H40
        CASE "5"
            FirstByte = &H50
        CASE "6"
            FirstByte = &H60
        CASE "7"
            FirstByte = &H70
        CASE "8"
            FirstByte = &H80
        CASE "9"
            FirstByte = &H90
        CASE "A"
            FirstByte = &HA0
        CASE "B"
            FirstByte = &HB0
        CASE "C"
            FirstByte = &HC0
        CASE "D"
            FirstByte = &HD0
        CASE "E"
            FirstByte = &HE0
        CASE "F"
            FirstByte = &HF0
    END SELECT

    HexByte = FirstByte + SecondByte
    GOSUB WriteOut
RETURN

'
' HeaderProcess
'
' Process S0, S1 and S9 records eventually
' right now just translate the bytes to Hex
'
HeaderProcess:
    HexByte = &H53
    GOSUB WriteOut
    ByteNo = ByteNo + 1
    GET #1, ByteNo, WorkByte
    WByte$ = WorkByte
    SELECT CASE WByte$
        CASE "0"
            HexByte = &H30
        CASE "1"
            HexByte = &H31
        CASE "9"
            HexByte = &H39
    END SELECT
    GOSUB WriteOut
    ByteNo = ByteNo + 1
    GET #1, ByteNo, WorkByte
RETURN
'
' WriteOut
'
' Write Byte to DataPort and set the Interupt on the Hero by 
' writing FF to the ControlPort
'
WriteOut:
    OUT DataPort, HexByte
    OUT ControlPort, IntOn   'Write FFh to control forcing pin 3 LOW
    OUT ControlPort, IntOff  'set interupt high
RETURN