' PMK-OLED 1.02 17-July-2023 ' ******************************************************* ' OLED Addition by George Heron, N2APB ' Based on PMK v2.1 code base ' PMK Copyright 2022-2023 Dave Benson, K1SWL ' ******************************************************** ' All trademarks referred to in source code and documentation are copyright their respective owners. ' This program is free software: you can redistribute it and/or modify' ' it under the terms of the GNU General Public License as published by ' the Free Software Foundation, either version 3 of the License, or ' (at your option) any later version. ' ' This program is distributed in the hope that it will be useful, ' but WITHOUT ANY WARRANTY; without even the implied warranty of ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ' GNU General Public License for more details. ' ' You should have received a copy of the GNU General Public License ' along with this program. If not, see . ' ******************************************************** MM.Startup INITS ' Variable Initialization VAR RESTORE Dim Integer Lookup(59) =(128,255,128,128,254,128,128,128,128,128,128,128,128,206,134,86,148,252,124,60,28,12,4,132,196,228,244,128,128,128,128 ,148,50,128,96,136,168,144,64,40,208,8,32,120,176,72,224,160 ,240,104,216,80,16,192,48,24,112,152,184,200) '****************************************************** ' P R O G R A M E X E C U T I O N B E G I N S CLS Text 0,0,"PICOMITE KEYER" If Pin(GP5) = 1 Then UserInterface ' PMK Setup uses the GUI ***Changed 6/12 Text 0,15,"Paddles: " If REV = 1 Then REVStr$ = "REV" Else REVStr$ = "NOR" Text (12*displaycharbitwidth),15,REVStr$ Text 0,29,"Iambic Mode: " If Mode = 0 Then ModeStr$ = "A" Else ModeStr$ = "B" Text (17*displaycharbitwidth),29,ModeStr$ ' -------------------------------- ' M A I N L O O P : I D L E ' -------------------------------- IDLE: Text 0,43,"WPM: " SpeedStr$ = Str$(WPM,2) Text (6*displaycharbitwidth),43,Speedstr$ If Pin(GP16) = 0 Then DA = 1 If Pin(GP17) = 0 Then DI = 1 If DA =1 Or DI=1 Then KEYERlogic ' Call KeyerLogic to process pending dit/dah ' ----------------------------------------------------- ' M E S S A G E M E M O R Y H A N D L I N G If KM=0 Then ' Message 1-4 from Terminal Mode If Pin(GP8)=0 Or Pin(GP10)=0 Or Pin(GP12)=0 Or Pin(GP14)=0 Then '----- Message 1 handling If Pin(GP8)= 0 Then Pin(GP9)=1 D$ = MSG1$ SPEED FORMSTR1 STREAM VAR SAVE MSG1$ Pin(GP9)=0 EndIf '----- Message 2 handling If Pin(GP10)=0 Then Pin(GP11)=1 ' LED #2 ON D$= MSG2$ SPEED QSOCNT= QSOCNT+1 VAR SAVE QSOCNT FORMSTR2 MSG2$=D$ STREAM VAR SAVE MSG2$ Pin(GP11)=0 ' LED #2 OFF EndIf '----- Message 3 handling If Pin(GP12)=0 Then Pin(GP13)=1 ' LED #3 ON SPEED STREAM Pin(GP13)=0 ' LED #3 OFF EndIf '---- Message 4 Handling If Pin(GP14)= 0 Then Pin(GP15)=1 ' LED #4 ON SPEED QSOCNT = QSOCNT - 1 VAR SAVE QSOCNT Pause 700 Pin(GP15) = 0 ' LED #4 OFF EndIf EndIf EndIf '--------------------- ' Press RECORD button. If Pin(GP6)=0 Then Pin(GP7)=1 RFL=1: KM=1 ' ENABLES KeyerLogic to accumulate a string" B4=0:NOTb4=0:ONESY=0:TWOSEY=0:DONE=0 If Onesy=1 And Twosey=1 Then ONESY=0: TWOSEY=0 EndIf '----------------- ' Pressing button #4 BEFORE entering a message on paddles adds the QSO ' Count to the beginning of the message. (Needed for ARRL CW Sweepstakes) If DONE=1 Then GoTo Skip8 If RFL=1 Then Do If Pin(GP14) = 0 Then ' Button #4 pressed Pin(GP15)=1 ' Turn on LED #4 Pause 500 Pin(GP15)=0 ' Turn off LED #4 B4=1 EndIf Loop Until Pin(GP16)=0 Or Pin(GP17)=0 EndIf SKIP8: DONE =1 '------------------------------------------------------------- ' Poll until Button #1 or #2 is pressed. (Sensing the 'After' press.) If RFL=1 Then If Pin(GP14) = 0 Then ' Button #4 pressed Pin(GP15)=1 ' Turn on LED #4 Pause 500 Pin(GP15)=0 ' Turn off LED #4 NOTB4=1 EndIf EndIf If Pin(GP8) = 0 And RFL=1 Then TRANSFER_1 ' Copies contents of MMSG1$ to Message 1 memory If Pin(GP10)= 0 And RFL=1 Then TRANSFER_2 ' Copies contents of MMSG2$ to Message 2 memory If Pin(GP5)=0 Then KM=1 If DONE2=0 Then SPEED M3$= "010202000202130002103001100" ' "RESET SN ?" sent in Morse PLAYBACK_3 Timer =0 ' RESET MASTER TIME Do While Timer<3000 ' WAIT FOR paddles inputs for 3 seconds If DA=1 Or DI=1 Then DA=0:DI=0: QSOCNT=0:GoTo SKIP14 Loop SKIP14: Done2=1 EndIf EndIf '----------------- If Pin(GP8)=0 And KM=1 And RFL=0 Then ' Button #1 plays Msg1 Pin(GP9)=1 ' Msg1 LED on SPEED Playback_1 ' Play Msg1 Pin(GP9)=0 ' Msg1 LED off Pin(GP7)=0 ' REC LED off EndIf '------------------ If Pin(GP10)=0 And KM=1 And RFL=0 Then ' Button #2 plays Msg2 Pin(GP11)=1 ' Msg2 LED on QSOCNT= QSOCNT+1 VAR SAVE QSOCNT SPEED Playback_2 ' Play Msg2 Pin(GP11)=0 ' Msg2 LED off Pin(GP7)=0 ' REC LED off EndIf '------------------ If Pin(GP12)=0 And KM=1 And RFL=0 Then ' Button #3 repeats Message #2 ' in Standalone Mode Pin(GP13)=1 ' Msg3 LED on SPEED Playback_2 ' Play Msg3 Pin(GP13)=0 ' Msg3 LED off EndIf '------------------- If Pin(GP14)=0 And KM=1 And RFL=0 Then ' Button #4 decrements SN Pin(GP15)=1 ' Msg4 LED on QSOCNT=QSOCNT-1 Pause 500 Pin(GP15)=0 ' Msg4 LED off EndIf GoTo IDLE ' <<<<<<<<<<<< B A C K T O S T A R T O F M A I N L O O P '*********************** '*********************** ' S U B R O U T I N E S '*********************** '******************* Sub Playback_1 For W= 1 To Len(M1$) P$ = Mid$(M1$, W, 1) If P$ ="0" Then DDOUT =0: ELEMENT If P$ ="1" Then DDOUT =1: ELEMENT If P$ ="2" Then Pause (2*DotTime):GoTo skip5 If P$= "3" Then Pause (6*DotTime):GoTo skip5 If DI=1 Or DA=1 Then DA=0:DI=0: GoTo SKIP12 SKIP5: Next W VAR SAVE M1$ Skip12: End Sub '******************** Sub Playback_2 If B4=1 Then SSN For W= 1 To Len(M2$) P$ = Mid$(M2$, W, 1) If P$ ="0" Then DDOUT =0: ELEMENT If P$ ="1" Then DDOUT =1: ELEMENT If P$ ="2" Then Pause (2*DotTime):GoTo skip7 If P$= "3" Then Pause (6*DotTime):GoTo skip7 If DA=1 Or DI=1 Then DA=0:DI=0: GoTo SKIP13 SKIP7: Next W VAR SAVE M2$ If NOTB4=1 Then SSN SKIP13: End Sub '********************* Sub Playback_3 For W= 1 To Len(M3$) P$ = Mid$(M3$, W, 1) If P$ ="0" Then DDOUT =0: ELEMENT If P$ ="1" Then DDOUT =1: ELEMENT If P$ ="2" Then Pause (2*DotTime):GoTo skip11 If P$= "3" Then Pause (6*DotTime):GoTo skip11 If DA=1 Or DI=1 Then DA=0:DI=0:GoTo SKIP15 ' Paddle input. CLR INTRPTs, abort. SKIP11: Next W SKIP15: End Sub ' *************** Sub MSGFL ' Eliminate bogus characters from a string. MSGTEMP$ = "" A: For X =1 To Len(D$) C$ = Mid$(D$,X,1) If 31 <= Asc(C$) And Asc(C$) > 90 Then GoTo SKIP1 ' Skip 0-to-1F hex and 5B hex-to-end MSGTEMP$= MSGTEMP$ + C$ Skip1: Next X End Sub '******************* Sub Formstr1 MSGTEMP$="" A: For X =1 To Len(D$) C$ = Mid$(D$,X,1) If C$= "#" Then GoTo SKIP15 ' Ignore this character for message #1 MSGTEMP$= MSGTEMP$ + C$ Skip15: Next X MSG1$ = MSGTEMP$ D$= MSG1$ End Sub '******************* Sub formstr2 ' D$ = MSG2$ ' Scan Message and finds '#' character in string ------------- For W =1 To Len(D$) SNPOS= Instr(D$, "#") ' Return position at which "#" is found. If SNPOS > 0 Then SNFLAG=1 Next W ' loop back until end of string ' End loop. If "#" found, branch to string manipulation If SNFLAG =1 Then GoTo Build ' Build must be executed repeatedly as the serial number increments If SNPOS=0 Then GoTo BYPASS ' No "#" found BUILD: L_LEN= SNPOS-1 ' Found a "#". remove and replace w/ serial number. Static R_Len= Len(D$)- SNPOS SN$ = Str$(QSOCNT) ' Serial number (integer) converted to string Static G$=Left$(D$, L_LEN) H$= G$ + SN$ ' Add serial number after left side of string. 1st concatenation J$= H$ + Right$(D$, R_LEN) ' 2nd concatenation. String now complete BYPASS: If SNFLAG = 1 Then D$ = J$ End Sub '****************************** Sub STREAM ' Converts encoded Morse character to serial Morse Keyer and audio outputs For W = 1 To Len(D$) C$ = Mid$(D$,W,1) LTR = Asc(C$)-31 CODE = LOOKUP(LTR) If CODE =255, Then Pause 4*DoTTime: GoTo SKIPPY ' space between words EOCtest = 128 LOOP1: If CODE = EOCtest Then GoTo EXIT1 CODE=CODE<<1 ' shift left 1 bit into bit 8 If CODE>256 Then ' bit was a '1' DDOUT=1 CODE=CODE-256 ' set bit 8 to zero Else DDOUT=0 EndIf ELEMENT If DI=1 Or DA=1 Then DI=0:DA=0: Exit Sub ' Abort if wrong button pressed. Oops. GoTo LOOP1 EXIT1: ' add pause at end of character Pause 2*DOTTime SKIPPY: Next W End Sub '******************* Sub SPEED 'Returns speed in WPM SetPin 31, AIN WPM = Int(8+(9*Pin(31))) DotTime =Int(1200/WPM) End Sub '****************** Sub ELEMENT ' Plays the Morse element ... ONLY in Memory message playback! If DDOUT = 1 Then EL_LEN = 3*DOTTime 'In case of a dash If DDOUT = 0 Then EL_LEN = DOTTIME Pin(GP18) = 1 Play TONE 800,800, el_len Pause el_LEN Pin(GP18) = 0 ELPAUSE ' Append SPACE betw. dots/dashes End Sub '****************** Sub ELPAUSE ' SPACE between dots/dashes Pause 1 Play Tone hifreq,hifreq,DotTime Pause DotTime End Sub '****************** Sub SERIALNO ' Inserts the SERIALNO string (from the QSOCNT integer) into Msg2$ TRIG$ = "#" SNPOS = Instr(D$, TRIG$) If SNPOS= 0 Then GoTo SNEXIT L_LEN= SNPOS-1 R_LEN = Len(D$)-SNPOS SN$ = Str$(QSOCNT) ' Type conversion from (Integer) QSOCNT To String G$=Left$(D$, L_LEN) G$= G$ + SN$ G$= G$ + Right$(D$, R_LEN) D$ = G$ MSG2$=D$ SNEXIT: End Sub '******************************************************************** ' K E Y E R L O G I C ' Generate a dot or dash ' Sub KEYERlogic SPEED LOOPBACK: If REV=0 Then If DA=0 And DI =1 Then DDOUT=0 : DI=0 ' added 8_10 If DA= 1 And DI=0 Then DDOUT=1: DA=0 ' added 8_10 If MODE=1 And DA = 1 And DI= 1 Then ' IAMBIC MODE B DDOUT=INV CC And &B00000001: DI=0: DA=0 ' added 8_10 EndIf CC=DDOUT EndIf If REV=1 Then If DA=0 And DI =1 Then DDOUT=1: DI=0 If DA= 1 And DI=0 Then DDOUT=0:DA=0 If DA = 1 And DI=1 And MODE=1 Then 'IAMBIC MODE B DDOUT=INV CC And &B00000001 : DA=0: DI=0 'added 8_10 EndIf EndIf CC=DDOUT Pin(GP9)=0 ' Turn Msg 1 LED off ' ------------------------------------------- ' Key the transmitter and play the sound in headphones If DDOUT = 1 Then MMSG1$= MMSG1$ + "1": EL_LEN = 3*DOTTime 'Dash If DDOUT = 0 Then MMSG1$= MMSG1$ + "0": EL_LEN = DOTTIME 'Dot Pin(GP18) = 1 ' KEY on Play TONE 800,800,el_len ' Sound the dot or dash Pause el_len Pin(GP18) = 0 ' KEY off Pause DotTime ' Inter-element time EndIf ' Continue X: If Mode=0 Then DA=0:DI=0 ' (Iambic A) clear any dot/dash inputs ' arriving during the current character If DA=1 Or DI=1 Then GotTo LOOPBACK ' ------------------------------------------- ' Detect the length of a gap between elements Timer = 0 ' timer master reset LOOP2: If Pin(GP16) =0 Or Pin(GP17) = 0 Then GoTo SKIP3 If Int(Timer) >= (10*DotTime) Then GoTo SKIP3 ' Timeout GoTo LOOP2 SKIP3: If Int(Timer) >= (10*dottime) Then mmsg1$ = mmSG1$+ "3": GoTo SKIP6 'Timeout T2 = Int(Timer) If T2 >= 6* DotTime Then MMSG1$ = MMSG1$ + "3" :GoTo SKIP6 ' Long pause If T2 >= DotTime Then MMSG1$ = MMSG1$ + "2" ' Short pause SKIP6: If RFL=1 Then GoTo SKIP4 MMSG1$="" ' Prevent overflow condition in normal operation SKIP4: Pin(GP9)=0:DI=0:DA=0 If Len(MMSG1$)=253 Then RFL=0 :Pin(GP7)=0 ' overflow safety EndIf End Sub '---------------- ' Code table: ' "0" = DOT ' "1" = DASH ' "2" = SHORT PAUSE ' "3" = LONG PAUSE ' "4" (unused) ' "5" = (unused) ' "6" (unused) ' "7" (unused) ' "8" (unused) ' "9" (unused)) '****************** Sub Transfer_1 ' Copies contents of MMSG1$ to Message 1 memory, ' Triggered by pressing Message 1 button in Record Mode If ONESY=1 Then GoTo Skip9 M1$="" 'Go-path executed only once in Record mode. For W= 1 To Len(MMSG1$) P$= Mid$(MMSG1$, W, 1) M1$= M1$ + P$ Next W SKIP9: Pin(GP7)=0: RFL=0:MMSG1$="": ONESY=1 End Sub '****************** Sub Transfer_2 ' Copies contents of MMSG1$ to Message 2 memory 'Triggered by pressing Message 2 button in Record mode If TWOSEY=1 Or RFL=0 Then GoTo Skip10 M2$="" ' Go-path executed only once in Record mode. For W= 1 To Len(MMSG1$) P$= Mid$(MMSG1$, W, 1) M2$= M2$ + P$ Next W Pin(GP7)=0: RFL=0:MMSG1$="": TWOSEY=1 Skip10: End Sub '****************** Sub SSN 'STANDALONE mode Serial number If KM=1 Then D$ = Str$(QSOCNT) 'convert serial number to String STREAM EndIf End Sub '************************************************************************* ' U S E R I N T E R F A C E Sub UserInterface Print " ------------------------------------------------------------------------------------" Print " WELCOME TO THE K1SWL MEMORY KEYER OLED v1.02 (PMK Version 2.1) 17-July-2023" Print " ------------------------------------------------------------------------------------" Print "" Print "" Print "" Print "Press the letter 'N' for notes on setting up the Keyer software" Print """" Input N$ If UCase$(N$)="N" Then OPNOTES Print """" Print "Press the letter 'S' for an explanation of STANDALONE Mode" Print "": Input H$ If UCase$(H$) = "S" Then STANDALONE Print """""" Print Print "'---------------------------------------------------------------" ' Print """" 'Print " Would you like to add/update MESSAGE 1?" 'Print " If yes, press Y (CR)" 'Print " Or any other key (CR) to skip":Print "" 'Input R$ 'If Not (UCase$(R$)="Y") Then ' GoTo NextQ1 ' EndIf 'Print "" 'Print " Enter MESSAGE 1 Text followed by Carriage Return (CR)" ' Print " (Press Carriage Return to Skip)" ' Print " Your callsign typically goes in this field." ' Print """" ' Line Input D$ ' D$= UCase$(D$) ' returns upper case string ' If D$ ="" Then GoTo NextQ1 'MSGFL ' eliminates bogus characters 'MSG1$=MSGTEMP$ ' input saved as MSG1$ 'Print MSG1$ ' and print it 'VAR SAVE MSG1$ 'NextQ1: ' Pause 300 ' Print """" ' Print " Would you like to add/update MESSAGE 2?" 'Print " If yes, press Y (CR)" 'Print " Or any other key (CR) to skip":Print "" 'Input R$ ' If Not (UCase$(R$)="Y") Then ' GoTo NextQ2 ' EndIf 'Print "" 'Print " Enter MESSAGE 2 Text followed by Carriage Return (CR)" 'Print " (Press Carriage Return to Skip)" 'Print """""" 'Print " TO INSERT A SERIAL NUMBER IN A MESSAGE, ENTER A '#' SIGN IN THE" 'Print " POSITION WHERE YOU WANT THE NUMBER TO APPEAR. " 'Print "" 'Print " (This is typically at the end of the message)" 'Print """" 'Print """""" 'Pause 500 'Line Input D$ 'D$=UCase$(D$) 'If D$= "" Then GoTo NextQ2 'MSGFL ' eliminate bogus characters 'MSG2$=MSGTEMP$ ' input saved as MSG2$ 'Print MSG2$ ' and print it 'VAR SAVE MSG2$ 'NextQ2: ' Print """""" ' Print " Do you need to reset the Serial number count?" ' Print " (Enter 'Y' or 'N' and CR) This is USUALLY a 'YES'." ' Print " If 'NO', the count is restored after a power interruption." ' Print "" ' Input CLRCNT$ ' If UCase$(CLRCNT$) = "N" Then GoTo KeepCounting ' If UCase$(CLRCNT$) = "Y" Then QSOCNT =0 ' Print UCase$(CLRCNT$) 'KeepCounting: ' VAR SAVE QSOCNT Print """""" Pause 500 Print " Do you need to reverse the DOT and DASH Paddles?" Print " (Enter 'Y' or 'N' and CR) This setting is saved through" Print " removal of power. " TryAgn1: Print "" Input PDL$ If Not ((UCase$(PDL$) = "Y") Or (UCase$(PDL$) = "N")) Then Print "Try Again" GoTo TryAgn1 EndIf If UCase$(PDL$) = "Y" Then Rev=1 Else Rev=0 EndIf VAR SAVE Rev Pause 500 Print """""" Print " Do you want Iambic Mode A or mode B?" Print " Mode A: Stops after the current character (preferrred by most)" Print " Mode B: Adds an extra character (i.e., 'Squeeze keying')." Print """""" Print " Type 'A' or 'B'[CR]" TryAgn2: Print "" Input IAMB$ If Not ((UCase$(IAMB$) = "A") Or (UCase$(IAMB$) = "B")) Then Print "Try Again" : GoTo TryAgn2 EndIf If UCase$(IAMB$)="B" Then Mode =1 Else Mode =0 EndIf VAR SAVE MODE Print """""" Print "YOU'RE NOW OPERATIONAL- GO WORK SOME DX!" SPEED: Print """""" End Sub '************************************************************************* ' O P E R A T I O N A L N O T E S Sub OPNOTES: Print " OPERATIONAL NOTES:" Print """" Print "Before you get rolling, there are several operational steps to complete:" Print "" Print "If you're reading this, you've downloaded and started the software." Print """" Print " Type Cntrl-C to halt program excution. Do this NOW. " Print "" Print "On the Command Line (with the '>' prompt), type OPTION AUDIO GP20,GP21" Print "This enables the Audio Sidetone" Print """" Print "Save the PMK Software in one of the seven memory slots available." Print " Type FLASH SAVE (#) where # is the number you chose." Print "" Print "When the command prompt returns ,Type OPTION AUTORUN (#)." Print " This causes the software to start automatically upon application of power." Print """" Print "Press button F2 on your computer to restart the software." Print """" 'Print "You're now operational in SETUP mode." Print """" End Sub '************************************************************************* ' STANDALONE MODE N O T E S Sub STANDALONE Print """""" 'Print "Standalone Mode is typically used for Portable operation- or for shacks" 'Print "without a dedicated computer." 'Print """" 'Print "To enter Standalone Mode from Terminal Mode, simply Press the Record Button." 'Print "Its red LED will light and stay lit." 'print "" ' below- changed text 6/12 Print "TO START OPERATION AUTOMATICALLLY (WITHOUT A USB CABLE) ON POWER APPLICATION, " Print "ADD A JUMPER TO J5 (below Pico pins 7/8)" Print "" 'Print "This assumes you already set up operation in Terminal Mode." Print "The paddle Reverse and Iambic mode selection rarely need to change." Print """As a result, the OPERATIONAL dialog will ask only one question in Morse:" Print """" Print " 'RESET SN ?' (Reset QSO Count?)" Print "" Print " Tap either keyer paddle within 3 seconds to reset the count." Print " (If you're not using the QSO Count in a contest, " Print " you can ignore the question.)" Print """""" Print "To enter messages #1 and #2 without a QSO Count:" Print """" Print "Enter your intended message on the keyer paddles. When complete," Print " press the message #1 or #2 buttons to store a message to either " Print "of those memories. The green message LED will illuminate for 0.5" Print "seconds and the red Record LED will extinguish. " Print """" Print "To enter a message with a QSO Count:" Print "" Print " For a QSO Count at the START of a message, press message button #4" Print " and THEN enter your message via the keyer paddles. (This feature is" Print "needed for the ARRL CW Seepstakes." Print """" Print " For a QSO Count at the END of the message, enter message via the" Print "keyer paddles and THEN press the message button #4." Print "When complete, press message buttons #1 or #2 to store messages as before." Print """""" 'Print "Note: The messages entered in SETUP Mode are no longer available once" 'Print " Standalone Mode is entered." End Sub '***************************************************************** ' V A R I A B L E I N I T I A L I Z A T I O N Sub INITS SetPin GP5, DIN, PULLUP ' Jumper ON for startup in STANDALONE mode SetPin GP8, DIN, PULLUP ' Message #1 pushbutton SetPin GP10, DIN, PULLUP ' Message #2 pushbutton SetPin GP12, DIN, PULLUP ' Message #3 pushbutton SetPin GP14, DIN, PULLUP ' Message #4 pushbutton SetPin GP6, DIN, PULLUP ' Record pushbutton SetPin GP9, DOUT ' Message #1 LED SetPin GP11, DOUT ' Message #2 LED SetPin GP13, DOUT ' Message #3 LED SetPin GP15, DOUT ' Message #4 LED SetPin GP7, DOUT ' Record LED SetPin GP18, DOUT: Pin(GP18)=0 ' Keyer output on J3 SetPin GP16, DIN, PULLUP ' Paddle RING contact SetPin GP17, DIN, PULLUP ' Paddle TIP contact SetPin GP5, DIN, PULLUP ' P2: Keyer Mode Jumper: STANDALONE mode(low) Dim DI = 0 ' DIT pending Dim DA = 0 ' DAH pending Dim REV =0 ' Reverse paddles Dim DD ' Ditdah- raw output of stream and keyer Dim CC =0 ' Current Character Dim MODE =0 ' 0= Iambic MODE A, 1= Iambic MODE B Dim LEN0 ' Length of Text input string Dim LEN1 ' Length of Serial number string Dim DDOUT, WPM Dim QSOCNT =0 ' Initial value of contact Serial number. Dim SNFLAG =0 Dim SNPOS ' Position of S/N in test stream. Assigned in FORMSTR Dim RFL=0 ' Record Flag (allows messages to accumulate into PB1/2) Dim KM =0 ' Keyboard Mode (as opposedto STANDALONE Mode) Dim displaycharbitwidth = 6 ' # bits/char in OLED display character Dim STRING D$,SN$,G$,MSG1$,MSG2$, MSGTEMP$, MMSG1$,M1$, M2$,M3$ Dim B4,NOTB4, DONE, ONESY, TWOSEY Dim HIFREQ = 19000 'AUDIO SIDETONE in Hz- inaudible during pauses Const EOCTEST=128 Dim CODE UINT16 End Sub '****************** Sub MM.STARTUP Option DISPLAY 60,100 End Sub