;                  Colours
;
;  v1.2.1 for ION - TI-83/83+ Assembly Shell
;
;  By  Vasantha Crabb, ION port by Emir Sakic
;
; (C) 2000

.NOLIST
#DEFINE     end .end         ; To allow the use of TI headers
#DEFINE     END .end
#DEFINE     equ .equ
#DEFINE     EQU .equ
#INCLUDE    "ion.inc"        ; Include file
.LIST

;-----------------
; Program Constants
;-----------------

PROMPT_LOC      = $0A03             ; Screen location for prompt
keyRight        = 1                 ; Key code definitions
keyLeft         = 2
keyUp           = 3
keyDown         = 4
keyEnter        = 5
keyQuit         = 64

;-----------------
; Program Variables
;-----------------

#ifdef TI83P
safearea equ 8A3Ah         ;STATVARS
#else
safearea equ 858Fh         ;STATVARS
#endif
;(ion.inc has wrong equate for statvars for TI-83 Plus!)

BAND1_VAL       = safearea+$00      ; Menu codes for selected bands
BAND2_VAL       = safearea+$01
BAND3_VAL       = safearea+$02
BAND4_VAL       = safearea+$03
BAND5_VAL       = safearea+$04

CUR_BAND        = safearea+$05      ; The band being input
CUR_MENU_ITEM   = safearea+$06      ; The current menu selection
NEXT_PROMPT     = safearea+$07      ; Address of the next prompt string

OUTPUT_STR      = safearea+$09      ; What we put to the screen
VALUE_STR       = safearea+$0D      ; Resistance value string
TOL_STR         = safearea+$18      ; Tolerance value string

#ifdef TI83P		    	    ; displayed by ion and the 2 labels
        .org    progstart-2
        .db     $BB,$6D
#else
        .org    progstart
#endif
        ret
        jr      nc,Start 		; jumps to the label Start
TitleStr:                               ; Screen header
        .db     " ColÊurs 1.2",0
        .db     " by Vas Crabb",0


;---------------------
; Start of TI-83 PROGRAM
;---------------------

Start:
    bcall(_indicatorOff)            ; Kill that annoying busy indicator
    bcall(_GRBUFCLR)                ; Wipe the graph memory
    res     statsvalid,(iy+statflags)

    set     textwrite,(iy+SGRFLAGS) ; Send text to the graph memory
    ld      hl,OutputTemp           ; Initialise the output string
    ld      de,OUTPUT_STR
    ld      bc,21
    ldir

    ld      hl,$0100                ; Initialise variables
    ld      (CUR_BAND),hl

    ld      bc,$0000                ; Display the title
    ld      hl,TitleStr
    set     textEraseBelow,(iy+textflags)   ; Fully frame text
    set     textInverse,(iy+textflags)  ; White on black
    call    ShowStr
    res     textInverse,(iy+textflags)  ; Black on white
    call    ShowStr2

    ld      hl,BlackStr             ; This line added by Emir Sakic
    ld      e,$08                   ; Column to start drawing in
    ld      a,$15                   ; Row to start drawing in
    ld      b,7                     ; Number of strings to display
    call    DispColumnLoop          ; Draw first column of menu text

    ld      e,$28                   ; Column to start drawing in
    ld      a,$15                   ; Row to start drawing in
    ld      b,6                     ; Number of strings to display
    call    DispColumnLoop          ; Draw second column of menu text

    call    ShowPromptStr           ; Show the prompt
    ld      (NEXT_PROMPT),hl        ; Save the address in hl for later

    ld      b,$39                   ; Number of bytes to write
    ld      hl,Column1              ; Data address
    ld      de,PLOTSSCREEN+$52      ; Display memory address
    call    GrBufBlockWrite         ; Draw half the resistor

    ld      b,$29                   ; Number of bytes to write
    ld      de,PLOTSSCREEN+$B3      ; Display memory address
    call    GrBufBlockWrite         ; Draw the other half

    call    ionFastCopy             ; Send all the basic stuff to the display
    call    ShowMenuMarker          ; Show the menu marker
    call    ShowBandMarker          ; Show the band marker

MainLoop:
    ei                              ; Some ROM routines do a di
    res     onInterrupt,(iy+onFlags)
    bcall(_getkey)                  ; Get a key and handle it

    cp      keyQuit                 ; The user can exit at any time
    ret     z

    sub     keyUp
    call    z,HandleUpKey

    dec     a                       ; cp    K_DOWN
    call    z,HandleDownKey

    dec     a                       ; cp    K_ENTER
    call    z,HandleEnterKey        ; We've got some input!

    jr      MainLoop                ; Loop

MajickCode:                         ; This is where it all happens
    pop     hl                      ; Get rid of a return address

    ld      de,BAND1_VAL            ; Where we get the data
    ld      hl,VALUE_STR            ; Where we put the information
    ld      b,3                     ; There are three digits to handle

    ld      a,(BAND4_VAL)           ; Figure out where the DP goes
    add     a,3                     ; Add three as a safety net

    cp      13                      ; Troublesome small multipliers!
    jr      c,DPSearchLoop
    sub     11
    ld      c,a
    jr      DataOutLoop

DPSearchLoop:                       ; Do a modulo
    sub     3                       ; Decrease by three
    cp      3                       ; Compare to three
    jr      nc,DPSearchLoop         ; Loop if we're greater or equal
    neg
    add     a,4                     ; Trick to store b value when we
    ld      c,a                     ; should add a DP in c

    ld      a,4                     ; Move to the right if no DP needed
    cp      c
    jr      nz,DataOutLoop
    inc     hl

DataOutLoop:
    ld      a,(de)                  ; Add a digit to the string
    add     a,'0'
    ld      (hl),a
    inc     de                      ; Move to next digit
    inc     hl                      ; Move to next output character

    ld      a,c                     ; Put a DP in if appropriate
    cp      b
    jr      nz,LoopNow
    ld      (hl),'.'
    inc     hl
LoopNow:
    djnz    DataOutLoop             ; Loop

    ld      a,(de)                  ; The multiplier
    cp      12                      ; Check for mOhms
    jr      z,LdOhmsSymbol

ChkSmallVal:
    dec     hl
    cp      10                      ; Check for small multiplier
    jr      nc,LdOhmsSymbol
    inc     hl

    ld      (hl),'G'
    cp      7                       ; Is it a GigOhm resistor?
    jr      nc,LdOhmsSymbol

    ld      (hl),'M'
    cp      4                       ; Is it a MegOhm resistor?
    jr      nc,LdOhmsSymbol

    ld      (hl),'k'
    or      a                       ; If multiplier is black
    jr      nz,LdOhmsSymbol         ; Just load an omega
    dec     hl                      ; But kOhms jump a char

LdOhmsSymbol:
    inc     hl
    ld      (hl),$CA                ; Omega character


    ld      a,(BAND5_VAL)           ; Do the tolerance
    ld      hl,TOL_STR+3

    cp      6                       ; Blue (0.25%)
    jr      z,ShowIt

    ld      (hl),'0'
    dec     hl
    ld      (hl),'5'
    cp      5                       ; Green (0.5%)
    jr      z,ShowIt

    ld      (hl),'1'
    cp      7                       ; Purple (0.1%)
    jr      z,ShowIt

    dec     (hl)
    dec     hl
    dec     hl
    inc     (hl)
    cp      1                       ; Brown (1%)
    jr      z,ShowIt

    ld      (hl),'5'
    cp      10                      ; Gold (5%)
    jr      z,ShowIt

    ld      (hl),'2'
    cp      2                       ; Red (2%)
    jr      z,ShowIt

    inc     hl
    ld      (hl),'0'
    inc     hl
    ld      (hl),'.'
    dec     hl
    dec     hl
    or      a                       ; Black (20%)
    jr      z,ShowIt
    cp      12                      ; No Band (20%)
    jr      z,ShowIt

    dec     (hl)                    ; Must be silver (10%)

ShowIt:
    call    ionFastCopy             ; bcall(_grbufcpy_v)
    ld      hl,OUTPUT_STR           ; Display the value
    call    ShowPromptStr

    bcall(_getkey)                  ; Get a key and get out
    bcall(_clrLCDFull)
    bcall(_homeup)
    ret

;---------------------
; SUB for handling enter key on menu
;---------------------

HandleEnterKey:

    di                          ; So we can use the shadow regs.
    ld      a,(CUR_MENU_ITEM)   ; We use this later
    ex      af,af'              ; Put it in the shadow reg. for now

    ld      a,(CUR_BAND)        ; See if band three was a multiplier
    cp      2                   ; If we're not on band three..
    jr      nz,Band3Cleared     ; ..clear out
    ex      af,af'
    cp      10                  ; If it's not silver or gold..
    jr      c,SwapBand4Menu1    ; ..clear out

NoThirdDigit:
    cp      10
    jr      c,DropMultiplier
    inc     a
    jr      StoreMultiplier

DropMultiplier:
    or      a                   ; Check for black
    jr      nz,StraightDrop
    ld      a,11                ; Black becomes gold
StraightDrop:
    dec     a                   ; Drop the multimplier by 1
StoreMultiplier:
    ld      (BAND4_VAL),a       ; Store the band multiplier
    xor     a                   ; Make third digit zero
    ld      (BAND3_VAL),a

    ld      a,4                 ; Select the tolerance band
    ld      hl,Band5Prompt      ; Select the correct prompt
    ld      (NEXT_PROMPT),hl
    jr      StoreNewBand

SwapBand4Menu1:
    ex      af,af'
Band3Cleared:
    cp      3                   ; Check for 4-band code
    jr      nz,Band4Cleared
    ex      af,af'
    cp      12                  ; It's 4-band if band 4 isn't there
    jr      nz,SwapBand4Menu2

    ld      a,(BAND3_VAL)
    jr      NoThirdDigit        ; Re-use code

SwapBand4Menu2:
    ex      af,af'
Band4Cleared:
    ld      c,a                 ; Store the selection for this band
    ld      b,0                 ; Get the address by adding band
    ld      hl,BAND1_VAL        ; number to base address
    add     hl,bc
    ex      af,af'              ; Get the menu selection back
    ld      (hl),a              ; Store it away

    ex      af,af'              ; Select the next band
    inc     a
StoreNewBand:
    ld      (CUR_BAND),a
    ei                          ; No more use for the shadow regs.

    cp      5                   ; If we've got the data..
    jp      z,MajickCode        ; ..process it

    ld      hl,(NEXT_PROMPT)    ; Remember we saved this?
    set     textwrite,(iy+SGRFLAGS)
    call    ShowPromptStr
    ld      (NEXT_PROMPT),hl    ; Save the next prompt's address

    xor     a                   ; Reset menu selection to black
    jr      StoreMenuItem       ; Re-use some code

;---------------------
; SUB for handling up key on menu
;---------------------

HandleUpKey:
    ld      a,(CUR_BAND)        ; Return if we're on the first item
    or      a                   ; Band one can't be black
    ld      a,(CUR_MENU_ITEM)
    jr      nz,NotOnBand1
    dec     a
NotOnBand1:
    or      a
    ret     z

    ld      a,(CUR_BAND)        ; Check for tolerance band
    cp      4                   ; because it's non-linear
    ld      a,(CUR_MENU_ITEM)   ; If we're on silver, jump to purple
    jr      nz,DecMenuItem
    cp      10
    jr      nz,CheckGreen
    ld      a,7
    jr      StoreMenuItem
CheckGreen:
    cp      5                   ; If we're on green, jump to red
    jr      nz,DecMenuItem
    ld      a,3

DecMenuItem:
    dec     a                   ; Decrement current item
StoreMenuItem:
    ld      (CUR_MENU_ITEM),a
    call    ionFastCopy         ; Erase marker in old position
    call    ShowMenuMarker      ; Show marker in updated position
    call    ShowBandMarker      ; Re-display band marker, too

    xor     a
    ret                         ; Return

;---------------------
; SUB for handling down key on menu
;---------------------

HandleDownKey:
    ld      a,(CUR_MENU_ITEM)   ; Return if we're on the last item
    cp      12
    ret     z

    ld      c,a                 ; Save menu item for later
    ld      a,(CUR_BAND)        ; We'll set limits for each band

    ld      b,9                 ; Bands one and two go up to white
    cp      3                   ; If we're on band four or five..
    jr      nc,BandGT3          ; ..clear out
    cp      2                   ; See if we're on band three
    jr      nz,BandLE2          ; If not, the limit's in b
    ld      b,11                ; Band three goes up to gold
BandLE2:
    ld      a,c                 ; Get menu item back
    cp      b                   ; Compare to upper limit
    ret     z
    jr      IncMenuItem

BandGT3:
    cp      4                   ; Fifth band is non-linear
    ld      a,c                 ; Get menu item back
    jr      nz,IncMenuItem
    cp      2                   ; Jump if we're on red...
    jr      nz,CheckPurple
    ld      a,5
    jr      StoreMenuItem
CheckPurple:
    cp      7                   ; ...or purple!
    jr      nz,IncMenuItem
    ld      a,9

IncMenuItem:
    inc     a
    jr      StoreMenuItem       ; Re-use some code

;---------------------
; SUB for displaying a column of text
;---------------------

DispColumnLoop:
    ld      d,a                 ; Load cursor row
    ld      (PENCOL),de         ; Set cursor location
    call    ShowStr2            ; Display the text
    add     a,6                 ; Move down a line
    djnz    DispColumnLoop      ; Loop
    ret                         ; Return

;---------------------
; SUB for displaying the menu marker
;---------------------

ShowMenuMarker:
    ld      a,(CUR_MENU_ITEM)
    ld      l,$04               ; Choose the column to draw in
    cp      7
    jr      c,MenuFindRow       ; If we're in menu column 2..
    ld      l,$24               ; ..use display column $24
    sub     7                   ; And decrease a by seven

MenuFindRow:                    ; Find the LCD row
    ld      b,6                 ; Spacing
    ld      c,a
    ld      a,$15               ; Offset
MenuMulLoop:                    ; Cheap multiplication
    add     a,c
    djnz    MenuMulLoop
    ld      h,a                 ; Put the result into h

ShowTheArrow:
    ld      (PENCOL),hl         ; Set the cursor location
    ld      a,$05
    res     textwrite,(iy+SGRFLAGS)
    bcall(_vputmap)             ; Actually draw the marker
    ret

;---------------------
; SUB for displaying band marker
;---------------------

ShowBandMarker:
    ld      a,(CUR_BAND)
    ld      hl,$2F4C            ; Choose the column to draw in
    cp      4                   ; Band 5 is spaced differently
    jr      z,ShowTheArrow

    ld      b,7                 ; Spacing
    ld      c,a
    ld      a,$0F               ; Offset
    jr      MenuMulLoop         ; Re-use menu code

;---------------------
; SUB for sending a block of data to the GraphMem
;---------------------

GrBufBlockWrite:
    ld      a,(hl)              ; Get a byte
    ld      (de),a              ; Display it
    inc     hl                  ; Increment data counter
    ld      c,b                 ; Save loop counter
    ld      b,12                ; Increment screen counter by twelve
GrBufIncLoop:
    inc     de
    djnz    GrBufIncLoop
    ld      b,c                 ; Restore loop counter
    djnz    GrBufBlockWrite     ; Loop
    ret                         ; Return

;---------------------
; SUB for displaying the string at (hl) at c,b in menu font
;---------------------

ShowPromptStr:
    ld      bc,PROMPT_LOC
ShowStr:
    ld      (PENCOL),bc
ShowStr2:
    bcall(_vputs)
    ret

;---------------------
; Program Data
;---------------------

BlackStr:                        ; Band colours for menu
    .db     "Black",0
BrownStr:
    .db     "Brown",0
RedStr:
    .db     "Red",0
OrangeStr:
    .db     "Orange",0
YellowStr:
    .db     "Yellow",0
GreenStr:
    .db     "Green",0
BlueStr:
    .db     "Blue",0
PurpleStr:
    .db     "Purple",0
GreyStr:
    .db     "Grey",0
WhiteStr:
    .db     "White",0
GoldStr:
    .db     "Gold",0
SilverStr:
    .db     "Silver",0
MissingStr:
    .db     "None",0

Band1Prompt:                            ; Prompt strings
    .db     "First digit band?",0
Band2Prompt:
    .db     "Second digit band?",0
Band3Prompt:
    .db     "Third digit/multiplier?",0
Band4Prompt:
    .db     "Multiplier band?"          ; The blanks are to erase
    .db     "                      ",0  ; the previous prompts
Band5Prompt:
    .db     "Tolerance band?"
    .db     "                    ",0

OutputTemp:                             ; This is always part of the output
    .db     "R =  xxm   +/- 0.25%",0

Column1:                                ; The resistor picture
    .dw $0101
    .dw $0101
    .dw $0101
    .dw $0101
    .dw $80FF
    .dw $FF80
    .dw $FFFF
    .dw $8080
    .dw $40C0
    .dw $7F7F
    .dw $407F
    .dw $4040
    .dw $7F40
    .dw $7F7F
    .dw $4040
    .dw $4040
    .dw $7F7F
    .dw $407F
    .dw $4040
    .dw $4040
    .dw $80C0
    .dw $FF80
    .dw $FFFF
    .dw $8080
    .dw $01FF
    .dw $0101
    .dw $0101
    .dw $0101
    .db $01
Column2:
    .dw $02FE
    .dw $FE02
    .dw $FEFE
    .dw $0202
    .dw $0406
    .dw $FCFC
    .dw $04FC
    .dw $0404
    .dw $FC04
    .dw $FCFC
    .dw $0404
    .dw $0404
    .dw $FCFC
    .dw $04FC
    .dw $0404
    .dw $0404
    .dw $0206
    .dw $FE02
    .dw $FEFE
    .dw $0202
    .db $FE

.end
