gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 1 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00001 ;*********************************************************************** 00002 ; Simple CW Keyer Program for Microchip's PIC16F628A microcontroller * 00003 ; * 00004 ; Copyright (c) 2000,2011 Wolfgang Buescher (DL4YHF) * 00005 ; * 00006 ; This program is free software; you can redistribute it and/or modify * 00007 ; it under the terms of the GNU General Public License as published by * 00008 ; the Free Software Foundation; version 2 dated June, 1991. * 00009 ; * 00010 ; This program is distributed in the hope that it will be useful, * 00011 ; but WITHOUT ANY WARRANTY; without even the implied warranty of * 00012 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00013 ; GNU General Public License for more details. * 00014 ; * 00015 ; You should have received a copy of the GNU General Public License * 00016 ; along with this program; if not, write to the Free Software * 00017 ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00018 ; * 00019 ;*********************************************************************** 00020 ; $Id: qrpkeyer4.asm,v 1.2 2011/09/01 20:25:56 carlo Exp carlo $ 00021 ;*********************************************************************** 00022 00023 ;*********************************************************************** 00024 ; ELBUG-firmware for PIC16F628 * 00025 ; * 00026 ; - power-saving operation at 48 KHz, using SLEEP-Mode, * 00027 ; no need for ON/OFF-switch * 00028 ; - RECORD and PLAY of a message with max. 63 letters in EEPROM * 00029 ; and about 50 letters in RAM * 00030 ; - two function keys for "MSG1", "MSG2", combined="MODE" * 00031 ; * 00032 ; * 00033 ; Revision date: 04/2004 * 00034 ; recent changes: * 00035 ; 07/1999: * 00036 ; - changed the oscillator from "LP-crystal" to "RC" * 00037 ; because wake-up with 32kHz-crytal was too slow * 00038 ; - changed storage format of "pauses" from "bit" to "byte" * 00039 ; to allow different "pause times" between WORDs * 00040 ; - implemented a second "message memory" in RAM, which is * 00041 ; o.k. because RAM-contents don't get lost during * 00042 ; sleep mode (also applies to "configuration data"). * 00043 ; - implemented two macro-codes (NNN) and (ANN) for a * 00044 ; "contest number generator" * 00045 ; 03/2000: Upward compatible with rev 07/1999. * 00046 ; - implemented a "BEACON" mode which is quite the same as * 00047 ; the "LOOP" mode but it does not automatically "stop" * 00048 ; after 255 message replays. Also good for ARDF-TX. * 00049 ; Beacon mode may be activated with the command "C" (!). * 00050 ; - about 20 words of program memory left * 00051 ; for "future extensions". * 00052 ; - used MPLab for Windows/16 3.99.23, processor V6.3205 * 00053 ; 07/2000: Changed from MPLab V3.99 to V5.11 and rebuilt the * 00054 ; project, just to find out that I still get 8 messages * gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 2 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00055 ; from MPASM telling the "same old story": * 00056 ; > Register in operand not in bank 0. * 00057 ; > Ensure that bank bits are correct. * 00058 ; The resulting hex file is still exactly 5999 bytes long. * 00059 ; 07/2001: Started project KEYER2 which uses exactly the same * 00060 ; Hardware as KEYER1 but has a QRSS transmission mode * 00061 ; instead of the contest-number-generator. * 00062 ; 07/2002: Made a variant of KEYER1(!) for the PIC16F628. * 00063 ; Project name: keyer628.asm . * 00064 ; - All RAM locations changed * 00065 ; - CONFIG word changed ( _RC_OSC -> _ER_OSC_CLKOUT) * 00066 ; - 128 byte EEPROM instead of 64 now used completely * 00067 ; - lots of other mods because PIC16F84 and F628 are not as * 00068 ; compatible as first hoped, among them: * 00069 ; RC-oscillator, lousy EEPROM access, comparators off, * 00070 ; 04/2004: Switched from EXTERNAL to INTERNAL RC-Oscillator . * 00071 ; (Caution: the PIC16F628 had an "ER"-Oscillator, no cap * 00072 ; required; the PIC16F628A has the old "ext RC"-Osc again, * 00073 ; which again requires an external capacitor. Too bad ! * 00074 ; So we have to live with the internal RC which both have) * 00075 ; 09/2005: Caution again: The PIC16F628A is *NOT* compatible with * 00076 ; the PIC16F628 ! Google for PIC16F62XA/16F648A Migration. * 00077 ; This PIC-QRP-Keyer seems not to be affected by most of * 00078 ; these differences, BUT: THE BITS IN THE CONFIG WORD HAVE * 00079 ; BEEN CHANGED, SO YOU WILL MOST LIKELY NEED A DIFFERENT * 00080 ; FIRMWARE FOR THE 'NEW' PIC16F628A ! * 00081 ; 08/2011: Modified for the PIC16F628A-based 4SQRP EZ-keyer * 00082 ; circuit by Carlo Strozzi (IZ4KBS). New code released * 00083 ; under the terms of the GNU General Public License (GPL) * 00084 ; with permission of the original author. For the hardware * 00085 ; schematic please refer to the following link: * 00086 ; http://www.wa0itp.com/aa0zzkeyerschematicv3.pdf * 00087 ; SPK1 in the schematic is a piezo speaker. * 00088 ; * 00089 ;*********************************************************************** 00090 ; Usage of this file on the GNU/Linux Operating System: * 00091 ; - Install the "gputils" package (tested with version 0.13.7) * 00092 ; - Install the "picprog" package (tested with version 1.9) * 00093 ; - Compile with command: gpasm qrpkeyer4.asm * 00094 ; gpasm keyer.asm * 00095 ; - Burn the program into the a PIC16F628A with command: * 00096 ; sudo nice -n -19 picprog --slow [--erase] --burn \ * 00097 ; --input qrpkeyer4.hex --pic /dev/ttyS0 * 00098 ; If your JDM-type programmer is on a different serial port * 00099 ; adapt the above command line accordingly. See the relevant * 00100 ; program man-pages for more info. * 00101 ; * 00102 ;*********************************************************************** 00103 00104 ; radix dec 00105 list p=16F628A ; list directive to define processor 00106 #include ; processor specific variable definitions 00001 LIST 00002 ; P16F628A.INC Standard Header File, Version 1.10 Microchip Technology, Inc. gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 3 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00265 LIST 00266 00107 00108 00109 ; '__CONFIG' directive is used to embed configuration data within .asm file. 00110 ; The lables following the directive are located in the respective .inc file. 00111 ; See respective data sheet for additional information on configuration word. 00112 ; EX(16F84:) __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _RC_OSC 00113 ; EX(<2004-04): __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON &_ER_OSC_CLKOUT & _LVP_OFF & _BODEN_OFF 00114 ; 2004-04-13: changed from EXTERNAL RC-OSCILLATOR to INTERNAL, SLOW, RC-OSCILLATOR (37kHz) 002007 3F10 00115 __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _LVP_OFF & _BODEN_OFF & _MCLRE_OFF 00116 ; See Notes on the clock oscillator below, and in the datasheet. The INTERNAL OSCILLATOR 00117 ; must be configured for 37 kHz operation by software; using bit OSCF in the PCON register. 00118 ; Don't enable the watchdog... I don't "feed" it in this program ! 00119 00120 00121 ; '__IDLOCS' directive may be used to set the 4 * 4(?!?) ID Location Bits . 00122 ; These shall be placed in the HEX file at addresses 0x2000...0x2003 . 2000 0001 0002 00123 __IDLOCS H'1234' 0003 0004 00124 00125 00126 ;======================================================================= 00127 ; Hardware description and software considerations 00128 ;======================================================================= 00129 ; 00130 ; Clock Oscillator 00131 ; ---------------- 00132 ; The PIC WAS running in "low power mode" with 32.768kHz crystal. 00133 ; Worked fine for the first tests, but: 00134 ; In "low power 32kHz-crystal mode" wake-up took up to 5 seconds... 00135 ; thats why the keyer now uses the RC-oscillator. 00136 ; In "RC-oscillator"-mode wake-up only needs some 100 Microseconds 00137 ; which is ok for this purpose. In the prototype the oscillator was: 00138 ; R=100kOhm, Cext=450pF (!), the resulting clock frequency was 00139 ; 50 KHz ... though the data sheet says something different. 00140 ; You may change the clock oscillator if you don't like the pitch 00141 ; of the sidetone. 00142 ; A PIC instruction takes 4 clock cyles, so 8192 instructions are executed 00143 ; per second, or one instruction needs 122 Microseconds. 00144 ; 00145 ; Sidetone 00146 ; -------- 00147 ; Because the 500 Hz (*) sidetone has to be genereated by the software, 00148 ; the audio output pin has to be inverted every 8 instructions, which 00149 ; a tough job if the timer is busy also with other tasks. 00150 ; 00151 ; (*) Possibly higher after my mods - Carlo, IZ4KBS 00152 ; 00153 ; Power Consumption 00154 ; ----------------- 00155 ; The PIC itself only draws about 60 uA when operating and less than 00156 ; 1 uA when in standby-mode. The software enters "standby-mode" if 00157 ; there is no action (no playback and no key pressed) for more than gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 4 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00158 ; 0.x seconds. The PIC will wake up on any change on Port B inputs 00159 ; (that's where the paddle and the function keys are connected). 00160 ; Additional power is only required for the sidetone output, up to 00161 ; 300uA with low-impedance speakers. 00162 ; 00163 00164 ;======================================================================= 00165 ; Application Switches (SWI_xx) 00166 ;======================================================================= 0000 00167 #define SWI_TEST_QRQ 0 ; 1: Test "REPLAY" with MPSIM, low delay 0000 00168 #define SWI_WARN_QRK 1 ; 1: Warn with a "humming" sidetone 00169 ; if the letter-gap is too short to decode 00170 00171 ; This block is no longer used but is left here for documentation purposes. 00172 ; 00173 ; #define MAIN_CYCLE 14 ; for calculation of morse speed table entries: 00174 ; ; "number of cycles in the main loop when the clock freq was 32kHz" 00175 ; ; When using 32kHz clock and still 20 cycles main loop: MAIN_CYCLE=20 00176 ; ; When using 50kHz clock and still 20 cycles main loop: MAIN_CYCLE=13 00177 00178 00179 ;======================================================================= 00180 ; Port definitions (IOP_xx) 00181 ;======================================================================= 00182 ; Some Port-assignments are compatible with the ingenious NorCal-Keyer 00183 ; "KC1" by Wayne Burdick, Rev.B, 4-7-96. 00184 ; The following definitions are Operands for BTFSS etc. 00185 00186 ; Note: PORTA has no internal pull-ups. Unused INPUTS should be tied to Vcc 00187 ; with an external pull-up to avoid floating, which draws add'l current. 0000 00188 #define IOP_UNUSED_RA0 PORTA, 0 0000 00189 #define IOP_UNUSED_RA2 PORTA, 2 0000 00190 #define IOP_UNUSED_RA3 PORTA, 3 0000 00191 #define IOP_UNUSED_RA4 PORTA, 4 0000 00192 #define IOP_UNUSED_RA5 PORTA, 5 00193 0000 00194 #define IOP_TX_CONTROL PORTA, 1 ; transmitter control: 1=TX, 0=RX 0000 00195 #define IOP_KEY_OUTPUT PORTA, 6 ; modulation output: 1=HF on, 0=HF off 0000 00196 #define IOP_AUDIO_OUT PORTA, 7 ; sidetone (piezo speaker, also "signals") 00197 ; ex: #define IOP_COUNTER PORTA, 4 ; frequency counter only with 4 MHz XTAL 0000 00198 #define IOP_I2C_CLK PORTA, 4 ; serial clock for I2C bus (optional) 00199 00200 ; Note: PORTB will have its internal pullups enabled. 00201 ; (so there's no need to tie unused pins to GND or VCC.) 0000 00202 #define IOP_RESERVE1 PORTB, 0 ; "for future use" .... .. 0000 00203 #define IOP_SIGNAL_LED PORTB, 2 ; "Signal"-LED instead of piezo speaker 0000 00204 #define IOP_HAND_KEY PORTB, 3 ; from NORCALs keyer. not used yet. 0000 00205 #define IOP_DOT PORTB, 4 ; the inputs of PORTB are used for wake-up 0000 00206 #define IOP_DASH PORTB, 5 0000 00207 #define IOP_KEY_MSG2 PORTB, 6 ; my "MESSAGE 2" is NORCALs "MSG" 0000 00208 #define IOP_KEY_MSG1 PORTB, 7 ; my "MESSAGE 1" is NORCALs "FREQ" 00209 00210 ;======================================================================= 00211 ; other constants gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 5 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00212 ;======================================================================= 00213 00214 00215 ; Storage format of "spaces", "control characters" and "transmittable CW letters" 00216 ; --------------------------------------------------------------------------------- 00217 ; The most significant bits define the code type. 00218 ; Bit7: 1 = "this is SPACE (=pause) or CONTROL character", in this case: 00219 ; Bit6,Bit5 = control character type: 00220 ; 0x = SPACE (=pause, bits5..0 contain the length in DOTS (max.63) 00221 ; 10 = extra long "dash", bits4..0 contain the length in DOTS (max.31) 00222 ; 11 = future reserve, bits4..0 contain 31 possible codes 00223 ; Bit7: 0 = "this is a transmittable character (not SPACE or CONTROL)". 00224 ; Bits6..0 contain a maximum of 6 dashes or dots, 00225 ; with leading 1="Startbit" before the "dash/dot-matrix", 00226 ; dash/dot-matrix is in Bit0..max.Bit5: 00227 ; 0=dot 1=dash 00228 ; Bit0 always contains the LAST TRANSMITTED dash/dot. 00229 ; See definitions below for some examples how CW letters are stored in memory. 0000 00230 #define CW_CHR_0 b'00111111' ; "0" 0000 00231 #define CW_CHR_1 b'00101111' ; "1" 0000 00232 #define CW_CHR_2 b'00100111' ; "2" 0000 00233 #define CW_CHR_3 b'00100011' ; "3" 0000 00234 #define CW_CHR_4 b'00100001' ; "4" 0000 00235 #define CW_CHR_5 b'00100000' ; "5" 0000 00236 #define CW_CHR_6 b'00110000' ; "6" 0000 00237 #define CW_CHR_7 b'00111000' ; "7" 0000 00238 #define CW_CHR_8 b'00111100' ; "8" 0000 00239 #define CW_CHR_9 b'00111110' ; "9" 00240 0000 00241 #define CW_CHR_A b'00000101' ; 'A' 0000 00242 #define CW_CHR_B b'00011000' ; 'B' 0000 00243 #define CW_CHR_C b'00011010' ; 'C' 0000 00244 #define CW_CHR_D b'00001100' ; 'D' 0000 00245 #define CW_CHR_E b'00000010' ; 'E' 0000 00246 #define CW_CHR_F b'00010010' ; 'F' 0000 00247 #define CW_CHR_G b'00001110' ; 'G' 0000 00248 #define CW_CHR_H b'00010000' ; 'H' 0000 00249 #define CW_CHR_I b'00000100' ; 'I' 0000 00250 #define CW_CHR_J b'00010111' ; 'J' 0000 00251 #define CW_CHR_K b'00001101' ; 'K' 0000 00252 #define CW_CHR_L b'00010100' ; 'L' 0000 00253 #define CW_CHR_M b'00000111' ; 'M' 0000 00254 #define CW_CHR_N b'00000110' ; 'N' 0000 00255 #define CW_CHR_O b'00001111' ; 'O' 0000 00256 #define CW_CHR_P b'00010110' ; 'P' 0000 00257 #define CW_CHR_Q b'00011101' ; 'Q' 0000 00258 #define CW_CHR_R b'00001010' ; 'R' 0000 00259 #define CW_CHR_S b'00001000' ; 'S' 0000 00260 #define CW_CHR_T b'00000011' ; 'T' 0000 00261 #define CW_CHR_U b'00001001' ; 'U' 0000 00262 #define CW_CHR_V b'00010001' ; 'V' 0000 00263 #define CW_CHR_W b'00001011' ; 'W' 0000 00264 #define CW_CHR_X b'00011001' ; 'X' 0000 00265 #define CW_CHR_Y b'00011011' ; 'Y' gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 6 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0000 00266 #define CW_CHR_Z b'00011100' ; 'Z' 00267 0000 00268 #define CW_CHR_SEPAR b'00110001' ; '=' (-...-) this is the "official" separator 0000 00269 #define CW_CHR_SEPA2 b'01100001' ; '-' (-....-) but this is also frequenty used 0000 00270 #define CW_CHR_POINT b'01010101' ; '.' (-.-.-.) 0000 00271 #define CW_CHR_SLASH b'00110010' ; '/' (-..-.) 0000 00272 #define CW_CHR_? b'01001100' ; '?' (..--..) 0000 00273 #define CW_CHR_AR b'00101010' ; 'AR' (.-.-.) 0000 00274 #define CW_CHR_SK b'01000101' ; 'SK' (...-.-) 0000 00275 #define CW_CHR_KA b'00110101' ; 'KA' (-.-.-) 0000 00276 #define CW_CHR_KN b'00110110' ; 'KN' (-.--.) 0000 00277 #define CW_CHR_EOM b'01011111' ; 'EOM' (.-----) used for "partitions" of msg 0000 00278 #define CW_CHR_NNN b'01101010' ; 'NNN' (-.-.-.) replaced by serial number 0000 00279 #define CW_CHR_ANN b'01011010' ; 'ANN' (.--.-.) advance to next number 0000 00280 #define CW_CHR_SPACE b'10000000' ; ' ' (pause length in "dots" will be added) 00281 00282 00283 ;***** VARIABLE DEFINITIONS **************************************** 00284 ; EEPROM memory ... 00285 ; for PIC16F84: 0x00..0x3F were valid EEPROM locations (64 byte) 00286 ; for PIC16F628: 0x00..0x7F are valid EEPROM locations (128 byte) 0000 00287 #define EEPROM_ADR_CW_SPEED 0x7F ; EEPROM location for "speed" (16F84: 0x3F) 0000 00288 #define EEPROM_ADR_MSG1_START 0x7E ; Start of recorded message (16F84: 0x3E) 00289 ; (used as index, runs DOWN to zero) 00290 00291 ; RAM memory (general purpose registers, unfortunately not the same for PIC16F84 & PIC16F628) 00292 ; old: PIC16F84: RAM from 0x0C..0x4F 00293 ; new: PIC16F628: RAM from 0x20..0x7F (96 bytes, 0x20.. only accessable in Bank0) 00294 ; 0xA0..0xEF (another 80 bytes in Bank1) 00295 ; 0x120..0x14F (another 48 bytes in Bank2) 00296 ; 0x0F0..0x0FF, 0x170..0x17F , 0x1F0..0x1FF are mapped to 0x70..0x7F (same in all banks) 00297 ; So use 0x70..0x7F for context saving in the PIC16F628 and forget 0x0F0.. 0xNNN ! 00298 00000070 00299 w_temp EQU 0x70 ; variable used for context saving (16F84: 0x0C) 00000071 00300 status_temp EQU 0x71 ; variable used for context saving (16F84: 0x0D) 00301 00302 ; Keyer Variables 0000002E 00303 KY_state EQU 0x2E ; keyer state (16F84: 0x0E.. nn) 0000002F 00304 CW_timing EQU 0x2F ; duration of a "dot" (for keyer+generator etc) 00000030 00305 CW_t_cnt EQU 0x30 ; CW (keyer-) timer 00000031 00306 KY_mem_index EQU 0x31 ; Keyer memory index for record + replay 00000032 00307 KY_flags EQU 0x32 ; Keyer flags... etc 0000 00308 #define ky_dot 0 ; flag "dot in memory" for squeezing 0000 00309 #define ky_dash 1 ; flag "dash in memory" for squeezing 0000 00310 #define ky_recording 2 ; flag "keyer is recording into eeprom" 0000 00311 #define ky_playing 3 ; flag "keyer is playing back from eeprom" 0000 00312 #define ky_message2 4 ; flag "using message number 2" (in RAM) 0000 00313 #define ky_msg_full 5 ; flag "message buffer full" (during record) 0000 00314 #define ky_beep_cpl 6 ; flag "MessageBeep complete" 0000 00315 #define ky_wait_cmd 7 ; flag "Waiting for command" 00316 00000033 00317 KY_char_latch EQU 0x33 ; Buffer for decoding the SENT character 00000034 00318 KY_decoded_char EQU 0x34 ; output of the CW decoder (ready chars) 00000035 00319 KY_count_elements EQU 0x35 ; Counter for dashes+dots in a character gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 7 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00000036 00320 KY_dot_counter EQU 0x36 ; counts number of "dot times" for long delays 00321 00000038 00322 NoActivityTimer EQU 0x38 ; timer for "no activity" detection 00323 ; (in "WAIT"-mode for power-down, 00324 ; in "endless-loop-replay" used to limit the max. repeat number, 00325 ; and as "timeout" after message-buttons are pressed. 00326 ; ) 00327 00328 00000039 00329 OP_flags EQU 0x39 ; option flags (saved in EEPROM).. 0000 00330 #define op_dot_memory_off 0 ; flag "dot memory disabled" 0000 00331 #define op_list_mode 1 ; flag "list mode", macro expansion disabled 0000 00332 #define op_quick_digits 2 ; flag "use quick digits" when sending number 0000 00333 #define op_loop_mode 3 ; flag "endless loop mode" when playing (almost) 0000 00334 #define op_beacon_mode 4 ; flag "beacon mode" (endless TX loop without timeout) 0000 00335 #define NR_flags OP_flags 0000 00336 #define nr_digit1 5 ; digit1 of "three-digit-number" sent/rcvd 0000 00337 #define nr_digit2 6 ; digit2 of "three-digit-number" sent/rcvd 0000 00338 #define nr_digit3 7 ; digit3 of "three-digit-number" sent/rcvd 00339 0000003A 00340 NR_hundreds EQU 0x3A ; three-digit-number (unpacked BCD) 0000003B 00341 NR_tens EQU 0x3B 0000003C 00342 NR_ones EQU 0x3C 00343 0000003D 00344 bStorageData EQU 0x3D ; replaces EEDATA which is in Bank1 of the 16F628 (!) 00345 00000040 00346 Msg2_Start EQU 0x40 ; start of message Nr. 2 (volatile!) 16F84: 0x2D 0000006F 00347 Msg2_End EQU 0x6F ; end of message Nr. 2 00000030 00348 RAM_MSG2_LENGTH EQU (Msg2_End - Msg2_Start + 1) 00349 00350 ;********************************************************************** 00351 ; Initial contents of DATA EEPROM: 00352 ; ex: org (H'2100'+EEPROM_ADR_MSG1_START-14-16-16-4-10-63) 00353 ; When upgrading from an older version, MPLAB 6.40 moaned : 00354 ; > Warning[220] C:\PIC\QRP_KEYER\KEYER628.ASM 347 : 00355 ; > Address exceeds maximum range for this processor. 00356 ; > Reason may be the default radix which seems to be HEX now. 2103 00357 org (H'2100'+EEPROM_ADR_MSG1_START-d'14'-d'16'-d'16'-d'4'-d'10'-d'63') 00358 ; Initialize EEPROM Data with a small partitioned Test Message 00359 ; (this is "Message #1", reverse address order!) 00360 ; PIC16F84: EEPROM_ADR_MSG1_START = 0x3E 00361 ; PIC16F628: EEPROM_ADR_MSG1_START = 0x7E 00362 ; This will be overwritten as soon as the user records his own message. 2103 0000 00363 de 0 ; termination with null byte 00364 00365 ; 6th part of message#1: 14 byte "ur rst 599/" 2104 006A 0032 00366 de CW_CHR_NNN,CW_CHR_SLASH 2106 0085 0006 00367 de CW_CHR_SPACE+5,CW_CHR_N, CW_CHR_N, CW_CHR_5 0006 0020 210A 0085 0003 00368 de CW_CHR_SPACE+5,CW_CHR_T,CW_CHR_S,CW_CHR_R 0008 000A 210E 0085 000A 00369 de CW_CHR_SPACE+5,CW_CHR_R,CW_CHR_U 0009 2111 005F 00370 de CW_CHR_EOM gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 8 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00371 00372 ; 5th part of message#1: 16 byte "test de dl4yhf .-.-." 2112 002A 00373 de CW_CHR_AR 2113 0012 0010 00374 de CW_CHR_F, CW_CHR_H, CW_CHR_Y 001B 2116 0021 0014 00375 de CW_CHR_4, CW_CHR_L, CW_CHR_D 000C 2119 0088 0002 00376 de CW_CHR_SPACE+8,CW_CHR_E,CW_CHR_D,CW_CHR_SPACE+5 000C 0085 211D 0003 0008 00377 de CW_CHR_T, CW_CHR_S, CW_CHR_E, CW_CHR_T 0002 0003 2121 005F 00378 de CW_CHR_EOM 00379 00380 ; 4th part of message#1: 16 byte "de dl4yhf pse k" 2122 000D 00381 de CW_CHR_K 2123 0090 00382 de CW_CHR_SPACE+10 2124 0002 0008 00383 de CW_CHR_E, CW_CHR_S, CW_CHR_P 0016 2127 0085 00384 de CW_CHR_SPACE+5 2128 0012 0010 00385 de CW_CHR_F, CW_CHR_H, CW_CHR_Y 001B 212B 0021 0014 00386 de CW_CHR_4, CW_CHR_L, CW_CHR_D 000C 212E 0085 00387 de CW_CHR_SPACE+5 212F 0002 000C 00388 de CW_CHR_E, CW_CHR_D 2131 005F 00389 de CW_CHR_EOM 00390 00391 ; 3rd part of message#1: 4 byte "73 " 2132 005A 00392 de CW_CHR_ANN 2133 0023 0038 00393 de CW_CHR_3,CW_CHR_7 2135 005F 00394 de CW_CHR_EOM 00395 00396 ; 2nd part of message#1: 10 byte "ur nr " 2136 006A 0088 00397 de CW_CHR_NNN, CW_CHR_SPACE+8 2138 006A 0088 00398 de CW_CHR_NNN, CW_CHR_SPACE+8 213A 000A 0006 00399 de CW_CHR_R, CW_CHR_N, CW_CHR_SPACE+5 0085 213D 000A 0009 00400 de CW_CHR_R, CW_CHR_U 213F 005F 00401 de CW_CHR_EOM 00402 00403 ; 1st part of prerecorded message#1: 00404 ; "QRP PIC keyer by dl4yhf = hold button pressed 1 sec to record = .-.-." 00405 ; 12345678901234567890123456789012345678901234567890123456789012345 00406 ; 1 2 3 4 5 6 2140 002A 0085 00407 de CW_CHR_AR, CW_CHR_SPACE+5 2142 000C 000A 00408 de CW_CHR_D, CW_CHR_R, CW_CHR_O, CW_CHR_C, CW_CHR_E, CW_CHR_R 000F 001A 0002 000A 2148 0085 00409 de CW_CHR_SPACE+5 2149 000F 0003 00410 de CW_CHR_O, CW_CHR_T 214B 0085 00411 de CW_CHR_SPACE+5 214C 001A 0002 00412 de CW_CHR_C, CW_CHR_E, CW_CHR_S, CW_CHR_SPACE+5, CW_CHR_1 0008 0085 002F gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 9 LOC OBJECT CODE LINE SOURCE TEXT VALUE 2151 0085 00413 de CW_CHR_SPACE+5 2152 000C 0002 00414 de CW_CHR_D, CW_CHR_E, CW_CHR_S, CW_CHR_S, CW_CHR_E, CW_CHR_R, CW_CHR_P 0008 0008 0002 000A 0016 2159 0085 00415 de CW_CHR_SPACE+5 215A 0006 000F 00416 de CW_CHR_N, CW_CHR_O, CW_CHR_T, CW_CHR_T, CW_CHR_U, CW_CHR_B 0003 0003 0009 0018 2160 0085 00417 de CW_CHR_SPACE+5 2161 000C 0014 00418 de CW_CHR_D, CW_CHR_L, CW_CHR_O, CW_CHR_H 000F 0010 2165 0085 00419 de CW_CHR_SPACE+5 2166 0031 00420 de CW_CHR_SEPAR 2167 0085 00421 de CW_CHR_SPACE+5 2168 0012 0010 00422 de CW_CHR_F, CW_CHR_H, CW_CHR_Y 001B 216B 0021 0014 00423 de CW_CHR_4, CW_CHR_L, CW_CHR_D 000C 216E 0085 00424 de CW_CHR_SPACE+5 216F 001B 0018 00425 de CW_CHR_Y, CW_CHR_B 2171 0085 00426 de CW_CHR_SPACE+5 2172 000A 0002 00427 de CW_CHR_R, CW_CHR_E, CW_CHR_Y, CW_CHR_E, CW_CHR_K 001B 0002 000D 2177 0085 00428 de CW_CHR_SPACE+5 2178 001A 0004 00429 de CW_CHR_C, CW_CHR_I, CW_CHR_P 0016 217B 0085 00430 de CW_CHR_SPACE+5 217C 0016 000A 00431 de CW_CHR_P, CW_CHR_R, CW_CHR_Q 001D 00432 00433 00434 217F 00435 org (H'2100'+EEPROM_ADR_CW_SPEED) ; Initialize EEPROM Data 217F 0064 00436 de D'100' ; (initial CW-timing) 00437 00438 00439 00440 ;********************************************************************** 0000 00441 ORG 0x000 ; processor reset vector 0000 299E 00442 goto reset ; go to beginning of program 00443 00444 00445 00446 00447 ; the remaining bytes in page0 are used for computed gotos 00448 ; and lookup tables so we dont have to mess around 00449 ; with the ugly "pclath"-Register. See Microchips AppNote556 ! 00450 00451 ;======================================================================= 00452 ; Converts a decimal-digit(w) to morse code(w) 00453 ; - must be located in "page 0" because of "computed goto" 00454 ;======================================================================= gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 10 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0001 00455 DigitToMorse: 0001 390F 00456 andlw d'15' ; a "modulo ten" would be too complicated 0002 0782 00457 addwf PCL,F ; add digit value to Program Counter(low) 0003 343F 00458 retlw CW_CHR_0 0004 342F 00459 retlw CW_CHR_1 0005 3427 00460 retlw CW_CHR_2 0006 3423 00461 retlw CW_CHR_3 0007 3421 00462 retlw CW_CHR_4 0008 3420 00463 retlw CW_CHR_5 0009 3430 00464 retlw CW_CHR_6 000A 3438 00465 retlw CW_CHR_7 000B 343C 00466 retlw CW_CHR_8 000C 343E 00467 retlw CW_CHR_9 000D 3405 00468 retlw CW_CHR_A ; may be used for hexadecimal conversions one fine day 000E 3418 00469 retlw CW_CHR_B 000F 341A 00470 retlw CW_CHR_C 0010 340C 00471 retlw CW_CHR_D 0011 3402 00472 retlw CW_CHR_E 0012 3412 00473 retlw CW_CHR_F 00474 ; end of function DigitToMorse(w) 00475 0013 00476 DigitToMorse_Quick: 0013 390F 00477 andlw d'15' ; a "modulo ten" would be too complicated 0014 0782 00478 addwf PCL,F ; add digit value to Program Counter(low) 0015 3403 00479 retlw CW_CHR_T ; 0 -> "-" 0016 3405 00480 retlw CW_CHR_A ; 1 -> ".-" 0017 3409 00481 retlw CW_CHR_U ; 2 -> "..-" 0018 3411 00482 retlw CW_CHR_V ; 3 -> "...-" 0019 3421 00483 retlw CW_CHR_4 001A 3420 00484 retlw CW_CHR_5 ; 5 , some prefer "e" instead of "5", but I dont--- 001B 3430 00485 retlw CW_CHR_6 001C 3438 00486 retlw CW_CHR_7 ; 7 , sometimes "D" instead of "7"... not logical! 001D 343C 00487 retlw CW_CHR_8 ; 8 , sometimes "B" instead of "8" 001E 3406 00488 retlw CW_CHR_N ; 9 is very common, so we used it here 001F 344C 00489 retlw CW_CHR_? ; this is stupid, but the only "safe" way.. 0020 344C 00490 retlw CW_CHR_? 0021 344C 00491 retlw CW_CHR_? 0022 344C 00492 retlw CW_CHR_? 0023 344C 00493 retlw CW_CHR_? 0024 344C 00494 retlw CW_CHR_? 00495 ; end of function DigitToMorse_Quick(w) 00496 00497 00498 ;======================================================================= 00499 ; Main Loop 00500 ; The execution time of this loop must be CONSTANT 00501 ; as long as the CW sidetone is generated. 00502 ; This allows to use the "main loop" as a "timebase" 00503 ; without using the timer (the timer may be used for future things..) 00504 ;======================================================================= 0025 00505 main_loop: ; Main loop while no CW sidetone has to be generated. 00506 ; Here some "asynchronous" actions may be performed. 00507 ; The average main_loop takes 4 cycles more 00508 ; than main_loop_sync . gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 11 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00509 ; The keyer state machine takes care of this !!! 00510 0025 00511 main_loop_sync: ; main loop while CW sidetone "on" 00512 00513 00514 ;======================================================================= 00515 ; Check if any "message"-button is pressed 00516 ;======================================================================= 0025 1F86 00517 btfss IOP_KEY_MSG1 ; "Message1"-Button pressed ? 0026 29C6 00518 goto msg1_pressed 0027 1F06 00519 btfss IOP_KEY_MSG2 ; "Message2"-Button pressed ? 0028 2A2D 00520 goto msg2_pressed 0029 00521 no_button: 00522 00523 ; at the end of the "main loop": the "keyer state machine".. 00524 00525 ;======================================================================= 00526 ; Keyer-Task 00527 ;======================================================================= 00528 ; 00529 ; States for the keyer state machine: 00530 ; many actions in that do "logically" belong together are split 00531 ; into squences of "substates" 00532 ; to keep the execution time of the keyer task as short as possible. 00533 ; Otherwise the generation of the sidetone would be impossible 00534 ; with a 32kHz crystal. 00535 00536 ; state sequence for WAITING and switching into SLEEP mode 00537 0029 00538 #define KYS_PREPARE_WAIT 0 ; waiting for anything to happen... 0029 00539 #define KYS_WAITING 1 ; ... with "no-activity"-detection 00540 00541 ; state sequence for sending a DOT : 0029 00542 #define KYS_SEND_DOT 2 ; sending a dot 0029 00543 #define KYS_WAIT_DOT_PAUSE 3 ; wait for pause after dot 00544 00545 ; state sequence for sending a DASH: 0029 00546 #define KYS_SEND_DASH 4 ; sending a dash, 1st dot time 0029 00547 #define KYS_SEND_DASH2 5 ; sending a dash, 2nd dot time 0029 00548 #define KYS_SEND_DASH3 6 ; sending a dash, 3rd dot time 0029 00549 #define KYS_START_DASH_PAUSE 7 ; prepare next state.. 0029 00550 #define KYS_WAIT_DASH_PAUSE 8 ; wait for pause after dash 00551 00552 ; state sequence for waiting, detecting and recording characters and spaces 0029 00553 #define KYS_WAIT_LESS_1DOT 9 ; waiting for less than 1 dot times 0029 00554 #define KYS_WAIT_LESS_5DOTS d'10' ; waiting for less than 5 dot times, phase 1 0029 00555 #define KYS_WAIT_LESS_5DOTS2 d'11' ; waiting for less than 5 dot times, phase 2 0029 00556 #define KYS_WAIT_LESS_5DOTS3 d'12' ; waiting for less than 5 dot times, phase 3 0029 00557 #define KYS_SPACE_WAIT_DOT d'13' ; wait for one dot time 0029 00558 #define KYS_SPACE_INCR_DOTS d'14' ; counts up to n "space-dot-times" 00559 00560 ; state sequence for Keyer-Replay 0029 00561 #define KYS_PLAY_GET_NEXT_CHAR d'15' ; read next letter of stored message + analyze 0029 00562 #define KYS_PLAY_WAIT_SPACE d'16' ; wait for a "space" time between WORDS gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 12 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0029 00563 #define KYS_PLAY_WAIT_DASH d'17' ; WAIT for end of DASH, 1st phase 0029 00564 #define KYS_PLAY_WAIT_DASH2 d'18' ; " " " " " , 2nd phase 0029 00565 #define KYS_PLAY_WAIT_DOT d'19' ; WAIT for end of DOT or 3rd phase of DASH 0029 00566 #define KYS_PLAY_START_PAUSE1 d'20' ; switch to "one-dot-pause" = WAIT_DOT+1 0029 00567 #define KYS_PLAY_WAIT_PAUSE1 d'21' ; WAIT for "one-dot-pause" 0029 00568 #define KYS_PLAY_WAIT_PAUSE2 d'22' ; WAIT for "two-dot-pause", 1st phase 0029 00569 #define KYS_PLAY_WAIT_PAUSE22 d'23' ; WAIT for "two-dot-pause", 2nd phase 0029 00570 #define KYS_PLAY_CHECK_END_MSG d'24' ; check if more letters follow = WAIT_PAUSE22+1 00571 00572 ; "very special" states: 0029 00573 #define KYS_TUNE d'25' ; "tuning" (continuous carrier) 00574 0029 00575 KeyerTask: ;------- implementation of "elbug state machine" ---------------- 0029 1385 00576 bcf IOP_AUDIO_OUT ;01 sidetone LOW 002A 082E 00577 movf KY_state, W ;02 load current "machine state" 00578 ; the next instruction is a good place to set a breakpoint... "click it right!" 002B 0782 00579 addwf PCL,F ;03 add state to low byte of Program Counter 00580 00581 ; default state, may prepare to start "power down"-timer 002C 2846 00582 goto kyt_prepare_wait ;05 load timer for "no activity"-timeout 002D 2852 00583 goto kyt_waiting ;05 waiting for more than 5 dots 00584 00585 ; state sequence for sending a DOT : 002E 2864 00586 goto kyt_send_dot ;05 sending a dot 002F 2872 00587 goto kyt_wait_dot_pause ;05 wait for pause after a dot 00588 00589 ; state sequence for sending a DASH: 0030 2885 00590 goto kyt_send_dash ;05 sending a dash (1st dot time) 0031 2885 00591 goto kyt_send_dash ;05 sending a dash (2nd dot time) 0032 2885 00592 goto kyt_send_dash ;05 sending a dash (3rd dot time) 0033 2891 00593 goto kyt_start_dash_pause ;05 prepare next state.. 0034 289A 00594 goto kyt_wait_dash_pause ;05 wait for pause after sending a dash 00595 00596 ; state sequence for WAIT phases with no paddle closed 00597 ; (required for the CW TX decoder:) 0035 28AA 00598 goto kyt_wait_less_1dot ;05 waiting for less than 1 dot time 0036 28BF 00599 goto kyt_wait_less_5dots ;05 waiting for less than 5 dot times, phase 1 0037 28C4 00600 goto kyt_wait_less_5dots2 ;05 waiting for less than 5 dot times, phase 2 0038 28C9 00601 goto kyt_wait_less_5dots3 ;05 waiting for less than 5 dot times, phase 3 0039 28D7 00602 goto kyt_space_wait_dot ;05 wait for one dot time 003A 28DF 00603 goto kyt_space_incr_dots ;05 count up to 15 "space-dot-times" 00604 00605 ; state sequence for Keyer-Replay 003B 28EA 00606 goto kyt_play_get_next_char ;05 read next char from message and analyze it 003C 2944 00607 goto kyt_play_wait_space ;05 wait until end of a "long pause" between WORDs 003D 294F 00608 goto kyt_play_wait_elem ;05 WAIT for end of played DASH, 1st phase 003E 294F 00609 goto kyt_play_wait_elem ;05 WAIT for end of played DASH, 2nd phase 003F 294F 00610 goto kyt_play_wait_elem ;05 WAIT for end of played DOT or 3rd phase of DASH 0040 295B 00611 goto kyt_play_start_pause1 ;05 start "one-dot-pause" between dashes and dots 0041 2961 00612 goto kyt_play_wait_pause1 ;05 WAIT for "one-dot-pause" 0042 2971 00613 goto kyt_play_wait_pause2 ;05 WAIT for "two-dot-pause" between letters (add'l) 0043 2971 00614 goto kyt_play_wait_pause2 ;05 " " " " , 2nd phase, same code 0044 297C 00615 goto kyt_play_check_end_msg ;05 check if message over or more letters follow 00616 gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 13 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00617 ; "very special" states: 0045 298B 00618 goto kyt_tune ;05 "tuning" (continuous carrier) 00619 00620 0046 00621 end_of_page0: ; THIS LABEL MUST STILL BE IN PAGE0, OTHERWISE COMPUTED GOTOs FAIL 00622 #if (end_of_page0 > 0xFF) 00623 error "Shit. Computed jumps are outside of page0." 00624 #endif 00625 00626 ;============================================================================ 00627 ; Implementation of the KEYER-states 00628 ;============================================================================ 00629 ; The state-Labels are jumped to via "computed goto" from Page0. 00630 ; "synchroneous" states require a constant main-loop-delay 00631 ; because of the sidetone-generation. 00632 ; "asynchroneous" states can tolerate a little "jitter". 00633 ; They allow the main loop to perform other tasks. 00634 ; 00635 0046 00636 kyt_prepare_wait: ;---------------------------------------------------------- 0046 3001 00637 movlw 1 ; prepare detection of next letter.. 0047 00B3 00638 movwf KY_char_latch ; ..with "start bit" in position 0 0048 01B8 00639 clrf NoActivityTimer ; reload "No Actvity"-Timer 0049 1E86 00640 btfss IOP_DASH ; dash-paddle closed: 004A 287F 00641 goto kyt_start_dash ; start keying a "dash" 004B 1E06 00642 btfss IOP_DOT ; dot-paddle closed: 004C 285C 00643 goto kyt_start_dot ; start keying a "dot" 004D 3001 00644 movlw KYS_WAITING ; next state = "WAITING" 004E 00AE 00645 movwf KY_state ; store new state 004F 1085 00646 bcf IOP_TX_CONTROL ; Transmitter OFF, Receiver ON. 00647 ; because there is no paddle touched, this is a good time 00648 ; to check some error flags and generate warning signals if needed: 0050 22D6 00649 call WarningSignals 0051 2825 00650 goto main_loop ; end task, extremely "async" 00651 00652 0052 00653 kyt_waiting: ;======= main "waiting" state ========================== 00654 ; - waits for "anything" to happen. 00655 ; - enters sleep mode after long time of "No Activity". 00656 ; - tests both paddles and starts "dash" or "dot" if pressed. 0052 3001 00657 movlw KYS_WAITING ;07 default: remain "waiting" 0053 1E86 00658 btfss IOP_DASH ;08 dash-paddle closed: 0054 287F 00659 goto kyt_start_dash ;09 start keying a "dash" 0055 1E06 00660 btfss IOP_DOT ;10 dot-paddle closed: 0056 285C 00661 goto kyt_start_dot ;11 start keying a "dot" 0057 00AE 00662 movwf KY_state ;12 store new(?) state 0058 0BB8 00663 decfsz NoActivityTimer,F ;13 "Nothing happened" for a long time ? 0059 2825 00664 goto main_loop ;14 no: end task, asynchronous 00665 ; Enter SLEEP mode after a long time of no activity: 005A 22A4 00666 call PowerDown ; supply current about 1uA 005B 2846 00667 goto kyt_prepare_wait ; resume normal operation. 00668 005C 00669 kyt_start_dot: ; start sending a DOT 005C 1485 00670 bsf IOP_TX_CONTROL ; transmitter on, receiver off gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 14 LOC OBJECT CODE LINE SOURCE TEXT VALUE 005D 082F 00671 movf CW_timing,w ; load timer w. dot time 005E 00B0 00672 movwf CW_t_cnt ; 005F 3002 00673 movlw KYS_SEND_DOT ; new state 0060 00AE 00674 movwf KY_state ; 0061 1705 00675 bsf IOP_KEY_OUTPUT ; carrier on (Dot) 0062 00676 main_loop_sync12: 0062 0000 00677 nop ;14 0063 2825 00678 goto main_loop_sync ;15 end task, synchronous 00679 0064 00680 kyt_send_dot: ;======== send dot (WAIT) ===================== 0064 1E86 00681 btfss IOP_DASH ;07 check DASH-contact 0065 14B2 00682 bsf KY_flags, ky_dash ;08 .. save in "dash memory" 0066 1785 00683 bsf IOP_AUDIO_OUT ;09 sidetone HIGH (at t=09!) 0067 1705 00684 bsf IOP_KEY_OUTPUT ;10 carrier on (Dot) 0068 0BB0 00685 decfsz CW_t_cnt,F ;11 decrement, Timer still running? 0069 2862 00686 goto main_loop_sync12 ;12 yes -> end task, synchronous 00687 ; else: "start pause after dot"... 006A 1305 00688 bcf IOP_KEY_OUTPUT ; carrier off (TX remains "on") 006B 3003 00689 movlw KYS_WAIT_DOT_PAUSE ; load new state 006C 00AE 00690 movwf KY_state ; 006D 082F 00691 movf CW_timing,w ; set pause-time 006E 00B0 00692 movwf CW_t_cnt ; 006F 0DB3 00693 rlf KY_char_latch,f ; shift the SENT letter left 0070 13B3 00694 bcf KY_char_latch,7 ; never shift a "1" into MSB 0071 1033 00695 bcf KY_char_latch,0 ; LSB=0 means "append DOT" 00696 ; continue with "wait_dot_pause"... 00697 0072 00698 kyt_wait_dot_pause: ;====== pause after dot (WAIT) ======== 00699 ; (register DASHES during this time !) 0072 1305 00700 bcf IOP_KEY_OUTPUT ;07 carrier off 0073 1E86 00701 btfss IOP_DASH ;08 check "dash" contact 0074 14B2 00702 bsf KY_flags, ky_dash ;09 store "dash" in memory 0075 0BB0 00703 decfsz CW_t_cnt,F ;10 decrement, Timer still running? 0076 2825 00704 goto main_loop ;11 yes -> end task, async 00705 ; else "waiting for the pause after dot" is over, 00706 ; check if there is a DASH in memory: 00707 ; if yes, start sending a dash; 00708 ; else wait until "end-of-letter" has been detected. 0077 1032 00709 bcf KY_flags,ky_dot ; erase "dot" from memory 0078 1839 00710 btfsc OP_flags,op_dot_memory_off ; for "old style keyer" : 0079 10B2 00711 bcf KY_flags,ky_dash ; erase "dash" from memory, too 007A 18B2 00712 btfsc KY_flags, ky_dash ; "dash" in memory ? 007B 287F 00713 goto kyt_start_dash ; yes, "start dash" 00714 ; required for "squeezing" without dash/dot - memory ("old style"): 007C 1E86 00715 btfss IOP_DASH ; "dash" currently pressed ? 007D 287F 00716 goto kyt_start_dash ; yes, "start dash" 007E 28A6 00717 goto kyt_prepare_wait_1dot ; default: prepare to wait.. 00718 00719 ; 00720 ; sequence when keying a DASH: 00721 ; 007F 00722 kyt_start_dash: ; start DASH 007F 1485 00723 bsf IOP_TX_CONTROL ; transmitter on, receiver off 0080 082F 00724 movf CW_timing,w ; load timer w. dash time gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 15 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0081 00B0 00725 movwf CW_t_cnt ; (for 1st 1/3 phase) 0082 3004 00726 movlw KYS_SEND_DASH ; new state "Send Dash" 0083 00AE 00727 movwf KY_state 0084 1705 00728 bsf IOP_KEY_OUTPUT ; carrier on (Dash) 00729 ; continue with "send_dash"... 00730 0085 00731 kyt_send_dash: ;======== send DASH (WAIT, 3 phases) ========== 00732 ; and register DOTS in memory while waiting 0085 1E06 00733 btfss IOP_DOT ;07 check DOT-input 0086 1432 00734 bsf KY_flags, ky_dot ;08 save DOT in memory 0087 1785 00735 bsf IOP_AUDIO_OUT ;09 sidetone HIGH (at t=09!) 0088 0BB0 00736 decfsz CW_t_cnt,F ;10 decrement, Timer still running? 0089 288E 00737 goto kyt_send_dash2 ;11 yes, stay in this state & phase. 008A 0AAE 00738 incf KY_state,F ;12 no, next state (or 1/3 dash time) 008B 082F 00739 movf CW_timing,w ;13 (kyt_send_dash has "3 phases"!) 008C 00B0 00740 movwf CW_t_cnt ;14 start timer for next 1/3 dash 008D 2825 00741 goto main_loop_sync ;15 end task, synchronous 008E 00742 kyt_send_dash2: 008E 0000 00743 nop ;13 remain in "this" state. 008F 0000 00744 nop ;14 0090 2825 00745 goto main_loop_sync ;15 end task, synchronous 00746 00747 0091 00748 kyt_start_dash_pause: ;---start pause after DASH (switching state)--- 0091 1305 00749 bcf IOP_KEY_OUTPUT ;07 carrier off (after Dash) 0092 3008 00750 movlw KYS_WAIT_DASH_PAUSE ;08 load new state 0093 00AE 00751 movwf KY_state ;09 0094 082F 00752 movf CW_timing,w ;10 setzten "pause" time 0095 00B0 00753 movwf CW_t_cnt ;11 0096 0DB3 00754 rlf KY_char_latch,f ;12 shift the SENT letter left 0097 13B3 00755 bcf KY_char_latch,7 ;13 never shift a "1" into MSB 0098 1433 00756 bsf KY_char_latch,0 ;14 LSB=1 means "append DASH" 0099 2825 00757 goto main_loop ;15 end task, async 00758 009A 00759 kyt_wait_dash_pause: ;====== pause after dash (WAIT) ======= 00760 ; and register DOTS while waiting 009A 1305 00761 bcf IOP_KEY_OUTPUT ;07 carrier off 009B 1E06 00762 btfss IOP_DOT ;08 check "dot" contact 009C 1432 00763 bsf KY_flags, ky_dot ;09 store "dot" in memory 009D 0BB0 00764 decfsz CW_t_cnt,F ;10 decrement, Timer still running? 009E 2825 00765 goto main_loop ;11 yes -> end task, async 00766 ; else "waiting for the pause after dash" is over, 00767 ; check if there is a DOT in memory: 00768 ; if yes, start sending a dot; 00769 ; else wait until "end-of-letter" has been detected. 009F 10B2 00770 bcf KY_flags,ky_dash ; erase "dash" from memory 00A0 1839 00771 btfsc OP_flags,op_dot_memory_off ; for "old style keyer": 00A1 1032 00772 bcf KY_flags,ky_dot ; erase "dot" from memory, too 00A2 1832 00773 btfsc KY_flags, ky_dot ; "dot" in memory ? 00A3 285C 00774 goto kyt_start_dot ; yes, "start dot" 00A4 1E06 00775 btfss IOP_DOT ; "dot" currently pressed ? 00A5 285C 00776 goto kyt_start_dot ; yes, "start dot" 00777 ; else prepare to wait.. 00A6 00778 kyt_prepare_wait_1dot: ; prepare waiting for 1 dot time gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 16 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00779 ; (if less than 2 dots "total" pause, the "current" letter continues) 00A6 082F 00780 movf CW_timing,w ; load timer with one dot time 00A7 00B0 00781 movwf CW_t_cnt ; ... as "threshold" for new char. 00A8 3009 00782 movlw KYS_WAIT_LESS_1DOT ; next "WAITING" state 00A9 00AE 00783 movwf KY_state ; store new state 00784 ; continue with "wait_less_1dot" 00785 00786 00787 ; 00788 ; states for WAIT phases with no paddle closed 00789 ; (required for the CW TX decoder, 00790 ; ONE dot-time pause has already passed) 00791 ; 00792 00AA 00793 kyt_wait_less_1dot: ;====== WAIT for less than 1 dot time ================ 00794 ; A new letter is detected after a TOTAL pause of 2 dot-times has expired. 00795 ; The old letter continues if time not expired and any paddle pressed. 00796 ; Note: one "dot-time" pause is already over 00797 ; since the end of last DASH or DOT! 00AA 1E86 00798 btfss IOP_DASH ;07 dash-paddle closed: 00AB 287F 00799 goto kyt_start_dash ;08 start keying a "dash" 00AC 1E06 00800 btfss IOP_DOT ;09 dot-paddle closed: 00AD 285C 00801 goto kyt_start_dot ;10 start keying a "dot" 00AE 0BB0 00802 decfsz CW_t_cnt,F ;11 decrement, Timer still running? 00AF 2825 00803 goto main_loop ;12 yes -> end task, async 00804 ; else: new char detected after 2 dots 00805 ; since the end of the last DOT or DASH. 00B0 1085 00806 bcf IOP_TX_CONTROL ; Transmitter OFF, Receiver ON. 00807 ; The decoded char is appended to the message memory, 00808 ; if "recording" is active. 00B1 300A 00809 movlw KYS_WAIT_LESS_5DOTS ; next "WAITING" state 00B2 00AE 00810 movwf KY_state ; store new state 00B3 082F 00811 movf CW_timing,w ; load timer w. 1 dot time 00B4 00B0 00812 movwf CW_t_cnt ; will be used in "wait_less_5dots" 00B5 0833 00813 movf KY_char_latch,w ; load decoded letter 00B6 00B4 00814 movwf KY_decoded_char ; ..into the decoder output "latch" 00B7 1BB2 00815 btfsc KY_flags,ky_wait_cmd ; "waiting for command" ? 00B8 2AF6 00816 goto CommandDispatcher ; yes, handle input char as "command" 00B9 1932 00817 btfsc KY_flags,ky_recording ; is "RECORDING" active ? 00BA 227E 00818 kyt_append: call AppendToMessage ; save (w) in buffer[KY_mem_index--] 00BB 22D6 00819 call WarningSignals ; generate warning signals (?) 00BC 3001 00820 movlw 1 ; prepare detection of next letter.. 00BD 00B3 00821 movwf KY_char_latch ; ..with "start bit" in position 0 00BE 2825 00822 goto main_loop ; no, all ok, end task 00823 00BF 00824 kyt_wait_less_5dots: ;====== WAIT less than 5 dot times (1st phase) ====== 00825 ; This "3 dot waiting state" is split into three phases 00826 ; to avoid the calculation of "3 times CW_timing". 00827 ; It is necessary to detect SPACES between WORDS. 00BF 300B 00828 movlw KYS_WAIT_LESS_5DOTS2 ;07 next WAITING phase 00C0 1E06 00829 btfss IOP_DOT ;08 dot-paddle closed: 00C1 285C 00830 goto kyt_start_dot ;09 no space, start keying a "dot" 00C2 00AE 00831 movwf KY_state ;10 store new(?) state 00C3 2825 00832 goto main_loop ;11 end task, "async", timing ok. gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 17 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00833 ; The exit to "main_loop" should be at t=11, 00834 ; because exiting to "main_loop" takes 4 cycles more 00835 ; than exiting to "main_loop_sync". 00836 00C4 00837 kyt_wait_less_5dots2: ;====== WAIT less than 5 dot times (2nd phase) ======= 00C4 300C 00838 movlw KYS_WAIT_LESS_5DOTS3 ;07 next WAITING phase 00C5 1E86 00839 btfss IOP_DASH ;08 dash-paddle closed: 00C6 287F 00840 goto kyt_start_dash ;09 no space, start keying a "dash" 00C7 00AE 00841 movwf KY_state ;10 store new(?) state 00C8 2825 00842 goto main_loop ;11 end task, async 00843 00C9 00844 kyt_wait_less_5dots3: ;====== WAIT less than 5 dot times (3rd phase) ======= 00C9 300A 00845 movlw KYS_WAIT_LESS_5DOTS ;07 keep state, 1st phase 00CA 00AE 00846 movwf KY_state ;08 store new(?) state 00CB 0BB0 00847 decfsz CW_t_cnt,F ;09 decrement, Timer still running? 00CC 2825 00848 goto main_loop ;10 yes, end task, async 00849 ; 5 dots over: measure length of WORD separation... 00850 ; (in "dot times") and emit one of the 31 possible "space" 00851 ; characters. 00CD 3082 00852 movlw H'82' ; prepare "SPACE" code with 2 dots... 00CE 00B3 00853 movwf KY_char_latch ; because of replay-task ! 00CF 1D32 00854 btfss KY_flags,ky_recording ; is "RECORDING" active ? 00D0 2846 00855 goto kyt_prepare_wait ; no, don't count SPACE length 00D1 082F 00856 movf CW_timing,w ; load timer with dot time.. 00D2 00B0 00857 movwf CW_t_cnt ; ... as "timebase" for next state 00D3 303C 00858 movlw D'60' ; set "maximum pause length"... 00D4 00B6 00859 movwf KY_dot_counter ; ... measured in "dot-times" 00D5 300D 00860 movlw KYS_SPACE_WAIT_DOT ; next state 00D6 00AE 00861 movwf KY_state ; 00862 ; continue with "space_wait_dot" 00863 00D7 00864 kyt_space_wait_dot: ;======= WAIT for one dot time ================== 00865 ; (inner loop for measuring the length of a pause between WORDs) 00866 ; Exit from this state if paddle touched 00867 ; or "dot timer" runs off. 00868 ; In both "Exit"-cases a "SPACE"-code is appended to the message 00D7 1E86 00869 btfss IOP_DASH ;07 dash-paddle closed: 00D8 28E6 00870 goto kyt_space_save ;08 end of pause, save! 00D9 1E06 00871 btfss IOP_DOT ;09 dot-paddle closed: 00DA 28E6 00872 goto kyt_space_save ;10 end of pause, save! 00DB 0BB0 00873 decfsz CW_t_cnt,F ;11 decrement, Timer still running? 00DC 2825 00874 goto main_loop ;12 still runs -> keep state! 00DD 0AAE 00875 incf KY_state,F ;13 dot time over-> SPACE_INCR_DOTS 00DE 2825 00876 goto main_loop ;14 end task, async 00877 00DF 00878 kyt_space_incr_dots: ;======= count "space-dot-times" ================ 00879 ; (outer loop for measuring the length of a pause between WORDs) 00880 ; Exit from this loop, if the "maximum acceptable time" for 00881 ; a pause between WORDs is exceeded. 00DF 082F 00882 movf CW_timing,w ;07 load timer with dot time.. 00E0 00B0 00883 movwf CW_t_cnt ;08 ... for next "SPACE_WAIT_DOT". 00E1 300D 00884 movlw KYS_SPACE_WAIT_DOT ;09 next state: "continue waiting" 00E2 00AE 00885 movwf KY_state ;10 00E3 0AB3 00886 incf KY_char_latch,F ;11 increment SPACE code (max. 60 counts) gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 18 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00E4 0BB6 00887 decfsz KY_dot_counter,F ;12 "maximum acceptable pause" exceeded? 00E5 2825 00888 goto main_loop ;13 not exceeded -> "SPACE_WAIT_DOT" 00889 ; else: "maximum pause exceeded" -> 00E6 00890 kyt_space_save: ; append "SPACE" character to message 00891 ; (the "space code" is appended to the the recorded message string, 00892 ; if there is enough EEPROM memory left.) 00E6 3000 00893 movlw KYS_PREPARE_WAIT ;14 next "WAITING" state 00E7 00AE 00894 movwf KY_state ;15 store new state 00E8 0833 00895 movf KY_char_latch,w ;16 load "pause" code... 00E9 28BA 00896 goto kyt_append ;17 ..and append to message buffer 00897 ;======= end of CW DECODER states ============================================ 00898 00899 00900 00901 ;======= states for Keyer-Replay ============================================ 00902 00903 00EA 00904 kyt_play_get_next_char: ;----------------------------------------------------- 00905 ; Reads the next letter for REPLAY from the current message buffer, 00906 ; and analyzes code: 00907 ; Check if its a "space" or "control character" (bit7=1) 00908 ; or a "transmittable letter" (bit7=0) 00909 ; Also check if the end of the message is reached (code=0) 00EA 00910 kyt_play_next2: 00EA 2271 00911 call ReadFromMessage ; read byte(w) from message[KY_mem_index--] 00EB 00B3 00912 movwf KY_char_latch ; store in tx-"shift register" 00EC 1FB3 00913 btfss KY_char_latch,7 ; bit7 is space/control flag 00ED 28FC 00914 goto kyt_play_normal_letter; bit7=0, start "normal" letter 00EE 13B3 00915 bcf KY_char_latch,7 ; reset space/control flag 00EF 1F33 00916 btfss KY_char_latch,6 ; bit6 of letter is control flag 00F0 28F5 00917 goto kyt_play_pause ; bit6=0, start "pause" time 00F1 1333 00918 bcf KY_char_latch,6 ; 6-bit-"control code" remains.. 00F2 00919 kyt_play_control_code: ; analyze 6-bit "control" code (not implemented) 00F2 297C 00920 goto kyt_play_check_end_msg; continue with next letter 00921 00F3 00AE 00922 kyt_ns: movwf KY_state ; set new state 00F4 2825 00923 goto main_loop ; end task, extremely "async" 00924 00F5 00925 kyt_play_pause: ; analyze 6-bit "pause" code (variable length) 00F5 1085 00926 bcf IOP_TX_CONTROL ; Transmitter OFF, Receiver ON. 00F6 082F 00927 movf CW_timing,w ; load timer w. dot time.. 00F7 00B0 00928 movwf CW_t_cnt ; ..to prepare "PLAY_WAIT_SPACE" 00F8 0833 00929 movf KY_char_latch,w ; load bits0..5 of pause code.. 00F9 00B6 00930 movwf KY_dot_counter ; into "dot counter" for pause 00FA 3010 00931 movlw KYS_PLAY_WAIT_SPACE ; next state 00FB 28F3 00932 goto kyt_ns ; set state, end task. 00FC 00933 kyt_play_normal_letter: ; analyze 7-bit "letter" code (maybe zero-byte) 00FC 1485 00934 bsf IOP_TX_CONTROL ; Transmitter ON, Receiver OFF. 00935 00936 ;-- Is the letter a zero-byte (end-of-string) ? 00FD 08B3 00937 movf KY_char_latch,f ; set "ZERO" flag if zero byte. 00FE 1903 00938 btfsc STATUS,Z ; skip next instruction if NOT ZERO 00FF 2915 00939 goto kyt_play_chk_loop ; no zero byte... 00940 gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 19 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00941 ;--- no "control" but a "possibly transmittable" letter or "macro": 0100 18B9 00942 btfsc OP_flags,op_list_mode ; in "list mode"... 0101 2927 00943 goto kyt_play_init_char ; ...no "special chars" are analyzed 00944 ;-- Is the letter an EOM-code (end-of-messagem, end partition) ? 0102 305F 00945 movlw CW_CHR_EOM 0103 0233 00946 subwf KY_char_latch,w 0104 1903 00947 btfsc STATUS,Z 0105 2915 00948 goto kyt_play_chk_loop 00949 ;-- Is the letter a "play 3-digit-number" instruction ? 0106 306A 00950 movlw CW_CHR_NNN 0107 0233 00951 subwf KY_char_latch,w 0108 1903 00952 btfsc STATUS,Z 0109 2920 00953 goto kyt_play_digit1 00954 ;-- Is the letter an "increment contest number"-command ? 010A 305A 00955 movlw CW_CHR_ANN 010B 0233 00956 subwf KY_char_latch,w 010C 1903 00957 btfsc STATUS,Z 010D 291E 00958 goto kyt_play_inc_nnn 010E 2927 00959 goto kyt_play_init_char 00960 010F 00961 kyt_play_next_loop: ; at the end of a recorded message: 010F 1E32 00962 btfss KY_flags,ky_message2 ; playing loop from message #1 or #2 ? 0110 307E 00963 movlw EEPROM_ADR_MSG1_START ; #1: Startindex in message-EEPROM 0111 1A32 00964 btfsc KY_flags,ky_message2 ; else.. 0112 302F 00965 movlw RAM_MSG2_LENGTH-1 ; #2: Startindex in message-RAM 0113 00B1 00966 movwf KY_mem_index ; this index will be DECREMENTED! 0114 2825 00967 goto main_loop ; end task, async. 00968 0115 00969 kyt_play_chk_loop: ; check if "endless loop" is active; if not, stop playing. 0115 1DB9 00970 btfss OP_flags, op_loop_mode ; Is "LOOP MODE" active ? 0116 2919 00971 goto kyt_play_beacon ; no, check "beacon mode", then stop. 0117 0BB8 00972 decfsz NoActivityTimer,F ; limit the number of replay loops 0118 290F 00973 goto kyt_play_next_loop ; play again from start of 1st partition 0119 00974 kyt_play_beacon: ; check if "BEACON MODE" is active ? 0119 1E39 00975 btfss OP_flags,op_beacon_mode ; Is "BEACON MODE" active ? 011A 291C 00976 goto kyt_play_stop ; no, stop playing. 011B 290F 00977 goto kyt_play_next_loop ; play again from start of 1st partition 011C 00978 kyt_play_stop: ; stored message is over (end-of-string, end-of-message): 011C 11B2 00979 bcf KY_flags, ky_playing ; reset "playing"-Flag 011D 2846 00980 goto kyt_prepare_wait ; enter "main waiting"-state 00981 011E 00982 kyt_play_inc_nnn: ; increment the "contest number" (non-transmitting char!) 011E 2291 00983 call IncrementNumber 011F 297C 00984 goto kyt_play_check_end_msg ; next state: get next char from buffer 0120 00985 kyt_play_digit1: ; prepare playing 1st digit of a 3-digit-number 0120 16B9 00986 bsf NR_flags,nr_digit1 ; "1st digit of three-digit-number" 0121 083A 00987 movf NR_hundreds,w ; load most significant digit 0122 00988 kyt_play_init_digit: 0122 1D39 00989 btfss OP_flags,op_quick_digits 0123 2001 00990 call DigitToMorse ; convert digit(w) to morse code(w) 0124 1939 00991 btfsc OP_flags,op_quick_digits 0125 2013 00992 call DigitToMorse_Quick ; ... optionally use "quick" digits 0126 00B3 00993 movwf KY_char_latch ; store in tx-"shift register" 00994 ; continue with "kyt_play_init_char".. gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 20 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0127 00995 kyt_play_init_char: 00996 ; prepare transmission of next letter (in KY_char_latch): 00997 ; shift left until "start bit" is in LSB 00998 ; and count the number of dots and dashes in the letter. 0127 3006 00999 movlw 6 ; load number of dots+dashes 0128 00B5 01000 movwf KY_count_elements ; ..into "element counter" 0129 1B33 01001 btfsc KY_char_latch,6 ; is it 6-element-char ? 012A 293D 01002 goto kyt_play_init6 ; else.. 012B 1AB3 01003 btfsc KY_char_latch,5 ; is it 5-element-char ? 012C 293B 01004 goto kyt_play_init5 ; else.. 012D 1A33 01005 btfsc KY_char_latch,4 ; is it 4-element-char ? 012E 2939 01006 goto kyt_play_init4 ; else.. 012F 19B3 01007 btfsc KY_char_latch,3 ; is it 3-element-char ? 0130 2937 01008 goto kyt_play_init3 ; else.. 0131 1933 01009 btfsc KY_char_latch,2 ; is it 2-element-char ? 0132 2935 01010 goto kyt_play_init2 ; else must be 1-element-char 0133 01011 kyt_play_init1: ; only 1-element-char, shift bit 0 into bit 5 0133 03B5 01012 decf KY_count_elements,F 0134 0DB3 01013 rlf KY_char_latch,F 0135 01014 kyt_play_init2: ; 2-element-char, shift bit 1 into bit 5 0135 03B5 01015 decf KY_count_elements,F 0136 0DB3 01016 rlf KY_char_latch,F 0137 01017 kyt_play_init3: ; 3-element-char, shift bit 2 into bit 5 0137 03B5 01018 decf KY_count_elements,F 0138 0DB3 01019 rlf KY_char_latch,F 0139 01020 kyt_play_init4: ; 4-element-char, shift bit 3 into bit 5 0139 03B5 01021 decf KY_count_elements,F 013A 0DB3 01022 rlf KY_char_latch,F 013B 01023 kyt_play_init5: ; 5-element-char, shift bit 4 into bit 5 013B 03B5 01024 decf KY_count_elements,F 013C 0DB3 01025 rlf KY_char_latch,F 013D 01026 kyt_play_init6: ; 6-element-char, dont shift, dont decrement 01027 ; continue with "kyt_play_next_elem" 01028 013D 01029 kyt_play_next_elem: 01030 ; check if next element is a DASH or a DOT, 01031 ; load timer with single or triple dot time. 013D 082F 01032 movf CW_timing,w ; time for a DOT... 013E 00B0 01033 movwf CW_t_cnt ; will be tripled BY STATE MACHINE 013F 3013 01034 movlw KYS_PLAY_WAIT_DOT ; state for waiting a DOT 0140 1AB3 01035 btfsc KY_char_latch,5 ; is next element DOT(0) or DASH(1) ? 0141 3011 01036 movlw KYS_PLAY_WAIT_DASH ; it's DASH.. 0142 00AE 01037 movwf KY_state ; set next state 0143 2825 01038 goto main_loop ; end task, async 01039 ; end of "PLAY_GET_NEXT_CHAR" (and label for "next element"). 01040 01041 01042 0144 01043 kyt_play_wait_space: ;----- WAIT for "space" between WORDS ------------ 01044 ; This state waits for a variable time (KY_dot_count) 01045 ; between two WORDs when playing a stored message. 0144 1E86 01046 btfss IOP_DASH ;07 dash-paddle closed: 0145 291C 01047 goto kyt_play_stop ;08 stop replay 0146 1E06 01048 btfss IOP_DOT ;09 dot-paddle closed: gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 21 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0147 291C 01049 goto kyt_play_stop ;10 stop replay 0148 0BB0 01050 decfsz CW_t_cnt,F ;11 next "dot-time" over ? 0149 2825 01051 goto main_loop ;12 no: keep "waiting", end task, async 014A 082F 01052 movf CW_timing,w ;13 yes: reload timer w. dot time.. 014B 00B0 01053 movwf CW_t_cnt ;14 .. for next "dot-time" loop 014C 0BB6 01054 decfsz KY_dot_counter,F ;15 Whole "pause" between WORDS over ? 014D 2825 01055 goto main_loop ;16 no, wait for next "dot-time" 014E 297C 01056 goto kyt_play_check_end_msg ;17 yes, continue with next letter 01057 ; end of keyer state "PLAY_WAIT_SPACE" (gap between WORDS) 01058 01059 014F 01060 kyt_play_wait_elem: ;---- Wait for end of played DASH or DOT ---- 01061 ; this "state" has been split into 3 "phases" 01062 ; to get a total "waiting" time of 3 dot lengths 01063 ; which is the "additional pause" between two WORDS. 01064 ; The corresponding states are: 01065 ; KYS_PLAY_WAIT_DASH, KYS_PLAY_WAIT_DASH2, KYS_PLAY_WAIT_DOT. 01066 ; By incrementing the state number, 01067 ; also KYS_PLAY_START_PAUSE1 will be entered "automatically". 014F 1705 01068 bsf IOP_KEY_OUTPUT ;07 carrier on 0150 0000 01069 nop ;08 0151 1785 01070 bsf IOP_AUDIO_OUT ;09 sidetone HIGH (at t=09!) 0152 0BB0 01071 decfsz CW_t_cnt,F ;10 decrement, Timer still running? 0153 2958 01072 goto kyt_play_el_continue ;11 yes, stay in this state. 0154 0AAE 01073 incf KY_state,F ;12 no, next state (or 1/3 dash time) 0155 082F 01074 movf CW_timing,w ;13 (this "state" has "3 phases"!) 0156 00B0 01075 movwf CW_t_cnt ;14 start timer for next dot-time 0157 2825 01076 goto main_loop_sync ;15 end task, synchronous 0158 01077 kyt_play_el_continue: 0158 0000 01078 nop ;13 remain in "this" state. 0159 0000 01079 nop ;14 015A 2825 01080 goto main_loop_sync ;15 end task, synchronous 01081 015B 01082 kyt_play_start_pause1: ;---- switching state to enter "pause" ----- 01083 ; Starts "one-dot-pause" between dahes+dots in one letter. 01084 ; This state is entered after INCREMENTING KYS_PLAY_WAIT_DOT. 015B 1305 01085 bcf IOP_KEY_OUTPUT ; carrier off 015C 082F 01086 movf CW_timing,w ; pause_time := 1 dot 015D 00B0 01087 movwf CW_t_cnt 015E 3015 01088 movlw KYS_PLAY_WAIT_PAUSE1 ; new state = "one dot pause" 015F 00AE 01089 movwf KY_state 0160 2825 01090 goto main_loop ; end task, async 01091 0161 01092 kyt_play_wait_pause1: ;----- WAIT for "one-dot-pause" ------------------ 01093 ; WAITS for pause between "elements" (DASHES or DOTS) in a letter 01094 ; and checks if "playing" is cancelled by the paddle contacts. 0161 1305 01095 bcf IOP_KEY_OUTPUT ;07 carrier off 0162 1E86 01096 btfss IOP_DASH ;08 dash-paddle closed: 0163 291C 01097 goto kyt_play_stop ;09 stop replay 0164 1E06 01098 btfss IOP_DOT ;10 dot-paddle closed: 0165 291C 01099 goto kyt_play_stop ;11 stop replay 0166 0000 01100 nop ;12 0167 0BB0 01101 decfsz CW_t_cnt,F ;13 decrement, Timer still running? 0168 2825 01102 goto main_loop_sync ;14 end task, synchronous gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 22 LOC OBJECT CODE LINE SOURCE TEXT VALUE 01103 ; pause between elements IN ONE letter is over: 01104 ; check if more dashes or dots follow in this letter. 0169 0BB5 01105 decfsz KY_count_elements,F ; Is this the last "element" ? 016A 296F 01106 goto kyt_play_ltr_continues ; no, letter continues. 01107 ; no more dashes or dots in "this" letter: 01108 ; start an additional pause of TWO dots 01109 ; (this gives a total pause of THREE dots) 016B 082F 01110 movf CW_timing,w ; additional pause_time will be.. 016C 00B0 01111 movwf CW_t_cnt ; ..doubled in next state 016D 3016 01112 movlw KYS_PLAY_WAIT_PAUSE2 ; new state: wait 2 dot times 016E 28F3 01113 goto kyt_ns ; set new state, end task, async 016F 01114 kyt_play_ltr_continues: 01115 ; more dashes or dots in "this" letter left... 016F 0DB3 01116 rlf KY_char_latch,F ; shift letter one bit left 0170 293D 01117 goto kyt_play_next_elem ; play next element of letter 01118 0171 01119 kyt_play_wait_pause2: ;----- WAIT for "two-dot-pause" ------------------ 01120 ; WAITS for additional pause between two letters. 0171 0BB0 01121 decfsz CW_t_cnt,F ;07 decrement, Timer still running? 0172 2977 01122 goto kyt_play_wait_continues ;08 yes, stay in this state+phase 0173 0AAE 01123 incf KY_state,F ;09 no, next state (or phase) 0174 082F 01124 movf CW_timing,w ;10 (this "state" has "2 phases"!) 0175 00B0 01125 movwf CW_t_cnt ;11 start timer for next dot-time 0176 2825 01126 goto main_loop ;12 end task, async 0177 01127 kyt_play_wait_continues: 0177 1E86 01128 btfss IOP_DASH ;10 dash-paddle closed: 0178 291C 01129 goto kyt_play_stop ;11 stop replay 0179 1E06 01130 btfss IOP_DOT ;12 dot-paddle closed: 017A 291C 01131 goto kyt_play_stop ;13 stop replay 017B 2825 01132 goto main_loop ;14 end task, async 01133 017C 01134 kyt_play_check_end_msg: ;---- Check "End of played Message" ------------ 01135 ; First check if transmission of a "three-digit-number" is still in progress. 01136 ; If so, send the "next" digit of this number. 01137 ; This state may be entered by incrementing "KY_state" above "WAIT_PAUSE22" 017C 1EB9 01138 btfss NR_flags,nr_digit1 ; 1st digit of three-digit-number sent? 017D 2982 01139 goto kyt_play_nd1 017E 12B9 01140 bcf NR_flags,nr_digit1 ; 1st digit done... 017F 1739 01141 bsf NR_flags,nr_digit2 ; now sending 2nd digit. 0180 083B 01142 movf NR_tens,w ; load "tens" 0181 2922 01143 goto kyt_play_init_digit ; convert to morse code & transmit 0182 01144 kyt_play_nd1: 0182 1F39 01145 btfss NR_flags,nr_digit2 ; 2nd digit of three-digit-number sent? 0183 2987 01146 goto kyt_play_nd2 0184 1339 01147 bcf NR_flags,nr_digit2 ; 2nd digit done... 0185 083C 01148 movf NR_ones,w ; load "ones" 0186 2922 01149 goto kyt_play_init_digit ; convert to morse code & transmit 0187 01150 kyt_play_nd2: ; else: no "number"-transmission in progress... 01151 ; Check if there are more letters to be sent. 01152 ; Maybe "ReadFromMessage" has cleared the "playing"-flag. 0187 1DB2 01153 btfss KY_flags,ky_playing ; "playing message" still active ? 0188 2915 01154 goto kyt_play_chk_loop ; no -> stop play if no "endless loop" 0189 300F 01155 movlw KYS_PLAY_GET_NEXT_CHAR ; new state if playing still active 018A 28F3 01156 goto kyt_ns ; set state, end task, async gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 23 LOC OBJECT CODE LINE SOURCE TEXT VALUE 01157 01158 ;------------- end of Keyer-replay-states --------------------------- 01159 01160 01161 ;------- "very special" Keyer-states ====================================== 01162 018B 01163 kyt_tune: ;======= "tuning" state ========================== 01164 ; - exit from this state by touching any paddle- or button- contact 01165 ; - enters sleep mode after long time of "No Activity". 018B 1485 01166 bsf IOP_TX_CONTROL ;07 Transmitter ON, Receiver OFF. 018C 1E86 01167 btfss IOP_DASH ;08 dash-paddle closed: 018D 299C 01168 goto kyt_tune_stop2 ;09 stop "tuning" 018E 1785 01169 bsf IOP_AUDIO_OUT ;10 sidetone HIGH 018F 1E06 01170 btfss IOP_DOT ;11 dot-paddle closed: 0190 299C 01171 goto kyt_tune_stop2 ;12 stop "tuning" 0191 1F86 01172 btfss IOP_KEY_MSG1 ;13 "Message1"-Button pressed ? 0192 299C 01173 goto kyt_tune_stop2 ;14 0193 1F06 01174 btfss IOP_KEY_MSG2 ;15 "Message2"-Button pressed ? 0194 299C 01175 goto kyt_tune_stop2 ;16 0195 1705 01176 bsf IOP_KEY_OUTPUT ;17 carrier on 0196 0BB0 01177 decfsz CW_t_cnt,F ;18 "inner loop"-time over ? 0197 2999 01178 goto kyt_tu2 ;19 no, end task 0198 0BB8 01179 decfsz NoActivityTimer,F ;20 "outer loop"-time over ? 0199 2825 01180 kyt_tu2: goto main_loop_sync ;21 no, end task 01181 ; Exit "tune"-loop after a long time of no activity: 019A 01182 kyt_tune_stop: 019A 1305 01183 bcf IOP_KEY_OUTPUT ; carrier off (Dot) 019B 2846 01184 goto kyt_prepare_wait ; resume normal operation. 019C 01185 kyt_tune_stop2: 019C 13B2 01186 bcf KY_flags,ky_wait_cmd ; exit from "command"-mode 019D 299A 01187 goto kyt_tune_stop 01188 01189 ;======= End of "Keyer-Task" after abt 16 cycles (incl. jump back) ===== 01190 01191 01192 01193 ;======================================================================= 01194 ; Initialization after RESET or WAKEUP (?) 01195 ;======================================================================= 01196 ; ORG 0x100 019E 01197 reset: ;----- Hardware initialization ----- 019E 138B 01198 bcf INTCON, GIE ; disable all interrupts 01199 01200 ; Switch the internal RC oscillator (in a PIC16F628) to 37 kHz. 01201 ; Even this ridiculously simple task can go wrong if you trust a lousy wrong datasheet. 019F 1683 01202 bsf STATUS, RP0 ;! set RP0 enables access to PCON register ... baaah Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 01A0 118E 01203 bcf PCON, OSCF ;! clear bit "OSCF" in "PCON" register for 37 kHz oscillator 01A1 1283 01204 bcf STATUS, RP0 ;! reset RP0 for normal operation... ISN'T THIS TERRIBLE ?!? 01205 ; GRUMBLE again about the rotten documentation by Microchip: 01206 ; PCON is not at address 0x0C as they tell you in chapter 3.2.2.6 , 01207 ; instead it is at address 0x8E so be carefull with the f***** register bank ! ! 01208 01209 ; turn off unused function blocks ... gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 24 LOC OBJECT CODE LINE SOURCE TEXT VALUE 01A2 1683 01210 bsf STATUS, RP0 ;! set RP0 enables access to VRCON register ... baaah again Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 01A3 019F 01211 clrf VRCON ;! turn voltage reference module off (16F628, register bank 1 ! !) 01A4 1283 01212 bcf STATUS, RP0 ;! reset RP0 for normal operation... and to access CMCON, holy s*** 01A5 3007 01213 movlw 0x07 ; turn comparators off and (16F628) 01A6 009F 01214 movwf CMCON ; enable pins for digital I/O (16F628) 01215 ; initialize port directions 01A7 1303 01216 bcf STATUS, RP1 ; default value: use register bank 0+1 only 01A8 1683 01217 bsf STATUS, RP0 ;! ; setting RP0 enables access to TRIS regs 01218 ; Unused RA Ports as input saves power !! 01A9 1405 01219 bsf IOP_UNUSED_RA0 01AA 1505 01220 bsf IOP_UNUSED_RA2 01AB 1585 01221 bsf IOP_UNUSED_RA3 01AC 1605 01222 bsf IOP_UNUSED_RA4 01AD 1685 01223 bsf IOP_UNUSED_RA5 01224 01AE 1305 01225 bcf IOP_KEY_OUTPUT ;! ; output 01AF 1085 01226 bcf IOP_TX_CONTROL ;! ; output 01B0 1385 01227 bcf IOP_AUDIO_OUT ;! ; output 01B1 1106 01228 bcf IOP_SIGNAL_LED ;! ; output 01229 ; bsf IOP_COUNTER ;! ; input (attention: PORTA has no internal pull-up) 01B2 1205 01230 bcf IOP_I2C_CLK ;! ; output Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 01B3 1381 01231 bcf OPTION_REG, NOT_RBPU ; enable PORTB pull-ups 01232 ; option register is in bank1. i know. thanks for the warning. 01B4 1606 01233 bsf IOP_DOT ;! ; input (with pullup) 01B5 1686 01234 bsf IOP_DASH ;! ; input (with pullup) 01B6 1706 01235 bsf IOP_KEY_MSG2 ;! ; input (with pullup) 01B7 1786 01236 bsf IOP_KEY_MSG1 ;! ; input (with pullup) 01237 01B8 1283 01238 bcf STATUS, RP0 ;! ; clearing RP0 enables access to PORTs 01B9 1305 01239 bcf IOP_KEY_OUTPUT ; key output low 01BA 1085 01240 bcf IOP_TX_CONTROL ; Transmitter off, receiver on 01BB 1385 01241 bcf IOP_AUDIO_OUT ; audio sidetone low 01242 01243 ;----- Software Initialization ----- 01BC 01AE 01244 clrf KY_state ; KY_state := 0 01BD 01B2 01245 clrf KY_flags ; KY_flags := 0 01BE 01B0 01246 clrf CW_t_cnt 01BF 3036 01247 movlw d'054' ; initial CW speed approx. 15 WPM 01C0 00AF 01248 movwf CW_timing ; CW_timing := 60 letters per minute 01249 ; (default value if poti fails...) 01C1 01B9 01250 clrf OP_flags ; set all option bits to "standard" (0) 01C2 01BA 01251 clrf NR_hundreds ; set three-digit-number.. 01C3 01BB 01252 clrf NR_tens ; ... to "ZERO" 01C4 01BC 01253 clrf NR_ones ; ("unpacked" BCD format) 01254 01255 #if SWI_TEST_QRQ ; Test with MPSIM ? 01256 movlw 3 01257 movwf CW_timing ; (QRQ for simulator) 01258 #endif ; SWI_TEST_.. 01259 01C5 2825 01260 goto main_loop ; 01261 gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 25 LOC OBJECT CODE LINE SOURCE TEXT VALUE 01262 01263 01264 ;======================================================================= 01265 ; Actions if control buttons are pressed 01266 ;======================================================================= 01267 ; A short touch of a "message" button starts playing a message 01268 ; (and may also terminate recording). 01269 ; A long touch of a "message" button starts recording a message 01270 ; (this will be indicated by a signal letter "R"). 01271 ; A combination of both buttons 01272 ; may be used to enter a "configuration menu" 01273 ; in later versions of this firmware. 01274 ; Stop playing a message before it terminates "itself" 01275 ; is also possible by touching a paddle. 01276 ; 01C6 01277 msg1_pressed: ; Message #1 has just been pressed. 01C6 1305 01278 bcf IOP_KEY_OUTPUT ; carrier off 01C7 01B8 01279 clrf NoActivityTimer ; reload "key-down"-Timer 01C8 1932 01280 btfsc KY_flags, ky_recording ; recording active ? 01C9 2A12 01281 goto msg_stop_recording ; yes, stop recording & return 01CA 1232 01282 bcf KY_flags, ky_message2 ; else use "message 1" NOW.. 01283 ; ( if this flag had been cleared earlier, 01284 ; the wrong "recorded" message could have been stopped) 01CB 01285 msg1_wait_release1: 01CB 22AE 01286 call Delay10 ; min. 10*100us = 1ms per loop 01CC 1B86 01287 btfsc IOP_KEY_MSG1 ; "message" key still pressed ? 01CD 29DF 01288 goto msg1_play ; no, only short press -> play ! 01CE 1F06 01289 btfss IOP_KEY_MSG2 ; check "combination" of buttons 01CF 2A1F 01290 goto msg1_then_2 ; msg1 pressed, then msg2 01D0 0BB8 01291 decfsz NoActivityTimer,F ; "short" time over ? 01D1 29CB 01292 goto msg1_wait_release1 ; no, still pressed -> wait 01293 ; now the message button has been pressed "quite long" 01D2 30EE 01294 movlw b'11101110' ; Beep "M" for "message record" 01D3 22B9 01295 call MessageBeeps ; ... means "Recording on" 01296 ; still have to wait until the button is released ? 01D4 01297 msg1_wait_release2: 01D4 1B86 01298 btfsc IOP_KEY_MSG1 ; "message" key released ? 01D5 29DA 01299 goto msg1_record ; released now -> start record. 01D6 1F06 01300 btfss IOP_KEY_MSG2 ; check "combination" of buttons 01D7 2A1F 01301 goto msg1_then_2 ; msg1 pressed, then msg2 01D8 22A4 01302 call PowerDown ; not released ... save power! 01D9 29D4 01303 goto msg1_wait_release2 ; check again if msg.button released 01DA 01304 msg1_record: ; now the message button is released, 01305 ; start recording of a message. 01DA 307E 01306 movlw EEPROM_ADR_MSG1_START ; Start address in message EEPROM 01DB 00B1 01307 movwf KY_mem_index ; this index will be DECREMENTED! 01DC 01308 msg_record_i: ; start recording, beginning at current index. 01DC 1532 01309 bsf KY_flags, ky_recording ; set "recording" flag 01DD 11B2 01310 bcf KY_flags, ky_playing ; reset "playing" flag for safety 01DE 2A17 01311 goto msg_release_both_buttons 01312 01DF 01313 msg1_play: ; start playing recorded message #1 01DF 307E 01314 movlw EEPROM_ADR_MSG1_START ; Start address in message EEPROM 01E0 01315 msg_play: gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 26 LOC OBJECT CODE LINE SOURCE TEXT VALUE 01E0 00B1 01316 movwf KY_mem_index ; this index will be DECREMENTED! 01E1 00B3 01317 movwf KY_char_latch ; temporary save start-index 01318 ; Check if the message is "partitioned". 01319 ; If yes, user may choose partition by multiple "button clicks". 01320 ; With every "button clicks" the index is advanced 01321 ; beyond the next "EOM"-character. 01322 ; If no, we don't have to wait if the button is pressed 01323 ; more times (saves time in contests and pileups) 01E2 15B2 01324 bsf KY_flags, ky_playing ; set "playing"-flag for "ReadFromMessage" 01E3 01325 msg_play_skip_eom: 01E3 2271 01326 call ReadFromMessage ; read Message[KY_mem_index--] ->w 01E4 1903 01327 btfsc STATUS,Z ; skip next instruction if NOT ZERO 01E5 29EB 01328 goto msg_play_no_partition ; end-of-string, no EOM-code found! 01E6 3C5F 01329 sublw CW_CHR_EOM ; check if character is EOM-code.. 01E7 1903 01330 btfsc STATUS,Z ; skip next instruction if NOT EQUAL 01E8 29EF 01331 goto msg_play_partitioned ; message is partitioned... 01E9 19B2 01332 btfsc KY_flags, ky_playing ; end of message reached ? 01EA 29E3 01333 goto msg_play_skip_eom ; no, continue until index==0 01334 ; else continue with "msg_play_no_partition". 01EB 01335 msg_play_no_partition: 01336 ; no partition in the message buffer, 01337 ; start playing the complete message without any further delay. 01EB 0833 01338 movf KY_char_latch,w ; restore 1st index of message 01EC 00B1 01339 movwf KY_mem_index 01ED 15B2 01340 bsf KY_flags, ky_playing ; set "playing"-flag for "ReadFromMessage" 01EE 2A0D 01341 goto msg_play_i ; play message from the start 01EF 01342 msg_play_partitioned: 01343 ; start playing a "partitioned" message: 01344 ; first wait some time to see if there are more 01345 ; short "clicks" of the message button. 01346 ; - if no more "button clicks": 01347 ; start message from the current messag-buffer-index ! 01348 ; - for every "click" advance the message index to the next 01349 ; "EOM-code" (which is the "partition separator"). 01EF 0833 01350 movf KY_char_latch,w ; restore 1st index of message 01F0 00B1 01351 movwf KY_mem_index 01F1 15B2 01352 bsf KY_flags, ky_playing ; set "playing"-flag for "ReadFromMessage" 01F2 01B8 01353 msg_pp0: clrf NoActivityTimer ; reload "key-down"-Timer 01F3 22AE 01354 msg_pp1: call Delay10 ; wait a little bit.. 01F4 1F86 01355 btfss IOP_KEY_MSG1 01F5 29FB 01356 goto msg_pp3 ; ...to see if more.. 01F6 1F06 01357 btfss IOP_KEY_MSG2 ; ... "button clicks" follow ! 01F7 29FB 01358 goto msg_pp3 ; 01F8 0BB8 01359 decfsz NoActivityTimer,F ; max. "wait"-time over ? 01F9 29F3 01360 goto msg_pp1 ; no, not yet -> loop 01361 ; The message button has not been pressed for quite a long time. 01362 ; Start playing from the "current" position. 01FA 2A0D 01363 msg_pp2: goto msg_play_i ; start playing from current index 01FB 01364 msg_pp3: ; message button is pressed to "skip" message to next "EOM-code". 01FB 2271 01365 call ReadFromMessage ; read Message[KY_mem_index--] 01FC 1903 01366 btfsc STATUS,Z ; skip next instruction if NOT ZERO 01FD 2A03 01367 goto msg_pp5 ; end-of-string, no EOM-code found! 01FE 3C5F 01368 sublw CW_CHR_EOM ; check if character is EOM-code.. 01FF 1903 01369 btfsc STATUS,Z ; skip next instruction if NOT EQUAL gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 27 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0200 2A03 01370 goto msg_pp5 ; message is partitioned... 0201 19B2 01371 btfsc KY_flags,ky_playing ; end of message memory reached ? 0202 29FB 01372 goto msg_pp3 ; no, continue until end of memory 0203 01373 msg_pp5: ; "skipping EOM" finished. Now wait for release of message button. 0203 01B8 01374 clrf NoActivityTimer ; reload "key-down"-Timer 0204 22AE 01375 msg_pp6: call Delay10 ; wait a little bit.. 0205 0BB8 01376 decfsz NoActivityTimer,F ; max. "wait"-time over ? 0206 2A08 01377 goto msg_pp7 ; no : continue waiting 0207 29DC 01378 goto msg_record_i ; yes: RECORD from current position 0208 1F86 01379 msg_pp7: btfss IOP_KEY_MSG1 0209 2A04 01380 goto msg_pp6 ; button still pressed, loop 020A 1F06 01381 btfss IOP_KEY_MSG2 020B 2A04 01382 goto msg_pp6 01383 ; message buttons have been released after a "short" time. 01384 ; check if more short "button clicks" follow. 020C 29F2 01385 goto msg_pp0 01386 020D 01387 msg_play_i: ;start playing recorded message at current index 020D 300F 01388 movlw KYS_PLAY_GET_NEXT_CHAR 020E 00AE 01389 movwf KY_state ; initialize keyer state 020F 15B2 01390 bsf KY_flags, ky_playing ; set "playing"-flag 0210 01B8 01391 clrf NoActivityTimer ; reload "No Activity"-Timer 01392 ; (used to limit "endless" play-loop to 255 times) 0211 2829 01393 goto no_button ; continue main loop 01394 0212 01395 msg_stop_recording: ; if any message button pressed while "recording": 01396 ; stop recording, wait until button is released 01397 ; and return to main loop 0212 2267 01398 call StopRecording ; stop recording 0213 30A8 01399 movlw b'10101000' ; Message-Beep "s"... 0214 22B9 01400 call MessageBeeps ; ... means "recording Stopped" 0215 2A17 01401 goto msg_release_both_buttons 01402 0216 01403 msg_release_btn_pdown: 0216 22A4 01404 call PowerDown ; save a little bit of battery power 0217 01405 msg_release_both_buttons: 01406 ; "normal" exit to ensure both buttons are released 01407 ; before main loop continues 01408 ; + save power if someone puts a brick on any button.. 0217 1F86 01409 btfss IOP_KEY_MSG1 0218 2A16 01410 goto msg_release_btn_pdown ; msg1 still pressed, wait... 0219 1F06 01411 btfss IOP_KEY_MSG2 021A 2A16 01412 goto msg_release_btn_pdown ; msg2 still pressed, wait... 021B 3000 01413 movlw KYS_PREPARE_WAIT ; else "wait" in main loop 021C 00AE 01414 movwf KY_state ; initialize keyer state 021D 01B8 01415 clrf NoActivityTimer ; reload "No Activity"-Timer 021E 2829 01416 goto no_button ; continue main loop 01417 021F 01418 msg1_then_2: ; message1 and message2 - buttons combined: 021F 01419 msg2_then_1: ; Enter "command mode". 021F 12B9 01420 bcf NR_flags,nr_digit1 ; no "1st digit" 0220 1339 01421 bcf NR_flags,nr_digit2 ; no "2nd digit" 0221 1339 01422 bcf NR_flags,nr_digit2 ; no "3rd digit" 0222 1BB2 01423 btfsc KY_flags,ky_wait_cmd ; already "waiting for command" ? gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 28 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0223 2A2A 01424 goto msg_done_command ; yes -> leave command mode. 0224 17B2 01425 bsf KY_flags,ky_wait_cmd ; set "waiting for command" - flag 0225 30EB 01426 movlw b'11101011' ; Beep "C" for "Command" 0226 22B9 01427 call MessageBeeps 0227 30A0 01428 movlw b'10100000' 0228 22B9 01429 msg_br: call MessageBeeps 0229 2A17 01430 goto msg_release_both_buttons 022A 01431 msg_done_command: 022A 13B2 01432 bcf KY_flags,ky_wait_cmd ; clear "waiting for command"-flag 022B 30EA 01433 movlw b'11101010' ; Beep "D" for "Done" 022C 2A28 01434 goto msg_br 01435 01436 022D 01437 msg2_pressed: ; Message #2 has just been pressed. 022D 1305 01438 bcf IOP_KEY_OUTPUT ; carrier off 022E 01B8 01439 clrf NoActivityTimer ; reload "key-down"-Timer 022F 1932 01440 btfsc KY_flags, ky_recording ; recording active ? 0230 2A12 01441 goto msg_stop_recording ; yes, stop recording & return 0231 1632 01442 bsf KY_flags, ky_message2 ; else use "message 2" NOW 0232 01443 msg2_wait_release1: 0232 22AE 01444 call Delay10 ; min. 10*100us = 1ms per loop 0233 1B06 01445 btfsc IOP_KEY_MSG2 ; "message" key still pressed ? 0234 2A46 01446 goto msg2_play ; no, only short press -> play ! 0235 1F86 01447 btfss IOP_KEY_MSG1 ; check "combination" of buttons 0236 2A1F 01448 goto msg2_then_1 ; msg2 pressed, then msg1 0237 0BB8 01449 decfsz NoActivityTimer,F ; "short" time over ? 0238 2A32 01450 goto msg2_wait_release1 ; no, still pressed -> wait 01451 ; now the message button has been pressed "quite long" 0239 30EE 01452 movlw b'11101110' ; Beep "M" for "message record" 023A 22B9 01453 call MessageBeeps ; ... means "Recording on" 01454 ; still have to wait until the button is released ? 023B 01455 msg2_wait_release2: 023B 1B06 01456 btfsc IOP_KEY_MSG2 ; "message" key released ? 023C 2A41 01457 goto msg2_record ; released now -> start record. 023D 1F86 01458 btfss IOP_KEY_MSG1 ; check "combination" of buttons 023E 2A1F 01459 goto msg2_then_1 ; msg2 pressed, then msg1 023F 22A4 01460 call PowerDown ; not released ... save power! 0240 2A3B 01461 goto msg2_wait_release2 ; check again if msg.button released 0241 01462 msg2_record: ; now the message button is released, 01463 ; start recording message2 (in RAM, not EEPROM). 0241 302F 01464 movlw RAM_MSG2_LENGTH-1 ; Start INDEX in message RAM 0242 00B1 01465 movwf KY_mem_index ; this index will be DECREMENTED! 0243 1532 01466 bsf KY_flags, ky_recording ; set "recording" flag 0244 11B2 01467 bcf KY_flags, ky_playing ; reset "playing" flag for safety 0245 2A17 01468 goto msg_release_both_buttons 01469 0246 01470 msg2_play: ; start playing recorded message #2 0246 302F 01471 movlw RAM_MSG2_LENGTH-1 ; Start address in message RAM 0247 29E0 01472 goto msg_play ; initialize state machine & return 01473 01474 ;======================================================================= 01475 ; Save a single Byte in the PIC's Data-EEPROM. 01476 ; Input parameters: 01477 ; bStorageData contains byte to be written (was once EEDATA) gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 29 LOC OBJECT CODE LINE SOURCE TEXT VALUE 01478 ; w contains byte address (i.e. "index") 01479 ; 01480 ; Notes: 01481 ; - This routine will wait for completion of "eeprom write ready" 01482 ; **before** writing to EEPROM. 01483 ; (improves performance during message recording, max. 10ms) 01484 ; Side effects: 01485 ; KY_char_latch will be overwritten 01486 ;======================================================================= 0248 01487 #define L_save_eep_timer KY_char_latch 01488 01489 ; write to EEPROM data memory as explained in PIC16F84 + 16F628 data sheet 01490 ; EEDATA and EEADR must have been set before calling this subroutine 01491 ; (optimized for the keyer-state-machine). 01492 ; CAUTION CAUTION CAUTION: What the lousy datasheet DS40300B wont tell you: 01493 ; The example given there for the 16F628 is WRONG ! 01494 ; All EEPROM regs are in BANK1 for the 16F628. 01495 ; In the PIC16F84, some were in BANK0 others in BANK1.. 01496 #ifdef __16F84 01497 01498 SaveInEEPROM: 01499 movwf EEADR ; write into EEPROM address register (BANK0 ONLY FOR 16F84) 01500 bcf INTCON, GIE ; disable INTs 01501 movf bStorageData,w ; w := bStorageData 01502 movwf EEDATA ; EEDATA(in BANK0) := w (ONLY WORKS FOR 16F84, NOT F628 !) 01503 bsf STATUS, RP0 ;!; Bank1 for "EECON" access 01504 bsf EECON1, WREN ;!; set WRite ENable 01505 movlw 055h ;!; 01506 movwf EECON2 ;!; write 55h 01507 movlw 0AAh ;!; 01508 movwf EECON2 ;!; write AAh 01509 bsf EECON1, WR ;!; set WR bit, begin write 01510 ; wait until write access to the EEPROM is complete 01511 clrf L_save_eep_timer ;!; preset "timeout"-counter 01512 SaveEW: btfss EECON1, WR ;!; WR is cleared after completion of write 01513 goto SaveRdy ;!; WR=0, "old" write access complete 01514 decfsz L_save_eep_timer,F ;!; 01515 goto SaveEW ;!; not ready,no timeout,continue waiting 01516 SaveRdy: ; now the EEPROM is ready to accept "new" write data 01517 bcf EECON1, WREN ;!; disable further WRites 01518 bcf STATUS, RP0 ;!; Bank0 for normal access 01519 bsf INTCON, GIE ; enable INTs 01520 return 01521 #endif ; __16F84 01522 01523 01524 #ifdef __16F628A 01525 ; In the PIC16F628, things are much different... all EEPROM regs are in BANK1 !!!! 0248 01526 SaveInEEPROM: ; save in EEPROM[] 0248 138B 01527 bcf INTCON, GIE ; disable INTs 0249 1683 01528 bsf STATUS, RP0 ;!; Bank1 for "EEADR" access, PIC16F628 ONLY (not F84) Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 024A 009B 01529 movwf EEADR ;!; write into EEPROM address register (BANK1 !!!!!) 024B 1283 01530 bcf STATUS, RP0 ;!; Bank0 to read "bStorageData" gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 30 LOC OBJECT CODE LINE SOURCE TEXT VALUE 024C 083D 01531 movf bStorageData,w ; ; w := bStorageData 024D 1683 01532 bsf STATUS, RP0 ;!; Bank1 for "EEDATA" access, PIC16F628 ONLY (not F84) Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 024E 009A 01533 movwf EEDATA ;!; EEDATA(in BANK1) := w (BANK1; F628 only, NOT F84 !!!) Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 024F 151C 01534 bsf EECON1, WREN ;!; set WRite ENable 0250 138B 01535 bcf INTCON, GIE ;!; Is this REALLY required as in DS40300B Example 13-2 0251 3055 01536 movlw 055h ;!; Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 0252 009D 01537 movwf EECON2 ;!; write 55h 0253 30AA 01538 movlw 0AAh ;!; Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 0254 009D 01539 movwf EECON2 ;!; write AAh Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 0255 149C 01540 bsf EECON1, WR ;!; set WR bit, begin write 01541 ; wait until write access to the EEPROM is complete 0256 01B3 01542 clrf L_save_eep_timer ;!; preset "timeout"-counter Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 0257 1C9C 01543 SaveEW: btfss EECON1, WR ;!; WR is cleared after completion of write 0258 2A5B 01544 goto SaveRdy ;!; WR=0, "old" write access complete 0259 0BB3 01545 decfsz L_save_eep_timer,F ;!; 025A 2A57 01546 goto SaveEW ;!; not ready,no timeout,continue waiting 025B 01547 SaveRdy: ; now the EEPROM is ready to accept "new" write data Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 025B 111C 01548 bcf EECON1, WREN ;!; disable further WRites 025C 1283 01549 bcf STATUS, RP0 ;!; Bank0 for normal access 025D 178B 01550 bsf INTCON, GIE ; enable INTs 025E 0008 01551 return 01552 #endif ; __16F628A 01553 01554 ;======================================================================= 01555 ; Read a single Byte from the PIC's Data-EEPROM. 01556 ; Input parameters: 01557 ; w contains byte address 01558 ; 01559 ; Result: 01560 ; w returns the read byte 01561 ;======================================================================= 01562 #ifdef __16F84 01563 ReadFromEEPROM: 01564 movwf EEADR ;01 write into EEPROM address register 01565 bcf INTCON, GIE ;02 disable INTs 01566 bsf STATUS, RP0 ;03 Bank1 for "EECON" access 01567 bsf EECON1, RD ;04 set "Read"-Flag for EEPROM 01568 bcf STATUS, RP0 ;05 normal access to Bank0 01569 bsf INTCON, GIE ;06 re-enable interrupts 01570 movf EEDATA, w ;07 read byte from EEPROM latch 01571 return ;08+09 back to caller 01572 #endif ; __16F84 01573 #ifdef __16F628A 01574 ; grrrrrrr ... EEDATA and EEADR have been moved from Bank0(16F84) to Bank1(16F628), 01575 ; but the rotten example from the datasheet telling you to switch to 01576 ; bank0 to access EEDATA which is rubbish (DS40300B page 93 example 13-1). 01577 ; Caution: Under MPLAB 5.50, the EEPROM in the PIC16F628 is not emulated properly. gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 31 LOC OBJECT CODE LINE SOURCE TEXT VALUE 025F 01578 ReadFromEEPROM: 025F 138B 01579 bcf INTCON, GIE ;01 disable INTs 0260 1683 01580 bsf STATUS, RP0 ;02 Bank1 for ***ALL*** EEPROM registers in 16F628 (!!!) Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 0261 009B 01581 movwf EEADR ;03 write into EEPROM address register Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 0262 141C 01582 bsf EECON1, RD ;04 set "Read"-Flag for EEPROM 01583 ; why is EECON1.RD not cleared in MPLAB-sim ?!? Message [302] : Register in operand not in bank 0. Ensure bank bits are correct. 0263 081A 01584 movf EEDATA, w ;05 read byte from EEPROM latch 0264 1283 01585 bcf STATUS, RP0 ;06 normal access to Bank0 0265 178B 01586 bsf INTCON, GIE ;07 re-enable interrupts 0266 0008 01587 return ;08+09 back to caller 01588 #endif ; __16F628A 01589 ; end ReadFromEEPROM 01590 01591 01592 ;======================================================================= 01593 ; Stop recording a message 01594 ; - finish last "PAUSE"-code 01595 ; - append ZERO byte if there is enough memory left 01596 ; in the "current" message buffer. 01597 ; Input parameters: 01598 ; KY_mem_index contains current index of recorded message string 01599 ; Side effects: 01600 ; KY_char_latch will be overwritten 01601 ;======================================================================= 0267 01602 StopRecording: 0267 1FB3 01603 btfss KY_char_latch,7 ; "PAUSE-code" in progress ? 0268 2A6B 01604 goto StopR2 ; no -> don't append pause-code 0269 0833 01605 movf KY_char_latch,w ; yes-> append "current" pause: 026A 227E 01606 call AppendToMessage ; message[KY_mem_index--] = w; 026B 3000 01607 StopR2: movlw 0 ; data to be written = ZERO byte 026C 227E 01608 call AppendToMessage ; message[KY_mem_index--] = w; 026D 1132 01609 bcf KY_flags,ky_recording ; stop "RECORDING" now 026E 3001 01610 movlw 1 ; prepare detection of next letter.. 026F 00B3 01611 movwf KY_char_latch ; ..with "start bit" in position 0 0270 0008 01612 return 01613 01614 01615 ;======================================================================= 01616 ; Reads the "current" message byte 01617 ; Input parameters: 01618 ; KY_mem_index: contains the message buffer INDEX to read from. 01619 ; KY_flags.ky_message2: 0="use Message #1 (EEPROM) 01620 ; 1="use Message #2 (RAM) 01621 ; Output, changed variables: 01622 ; w : returns the read byte 01623 ; ZERO-flag : is set if the result is ZERO (end-of-string) 01624 ; KY_mem_index : will be decremented (down to zero, not further) 01625 ; KY_flags.ky_playing: will be cleared if index ZERO reached 01626 ;======================================================================= 0271 01627 ReadFromMessage: 0271 0831 01628 movf KY_mem_index,w ; load current message-index gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 32 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0272 1903 01629 btfsc STATUS, Z ; Is message-index already ZERO ? 0273 2A76 01630 goto ReadFM1 ; index already zero-> dont decrement 0274 0BB1 01631 decfsz KY_mem_index,F ; decrement message-index 0275 2A77 01632 goto ReadFM2 ; not zero 0276 01633 ReadFM1: ; end of message buffer reached, reset "playing" flag 0276 11B2 01634 bcf KY_flags, ky_playing 0277 01635 ReadFM2: ; note that still contains the not-decremented index. 0277 1E32 01636 btfss KY_flags, ky_message2 ; "message1" or "message2" ? 0278 2A5F 01637 goto ReadFromEEPROM ; "message1" (EEPROM) 01638 ; else: "message2" (RAM) will be read with "indexed addressing" 01639 ; For PIC16F628, be careful with FSR indexed addresses 01640 ; to take STATUS.IRP into account . 0279 1383 01641 bcf STATUS, IRP ; indirect access 0x00..0xFF via FSR 027A 3E40 01642 addlw Msg2_Start ; add base address of buffer in RAM 027B 0084 01643 movwf FSR ; store in "data memory pointer" 027C 0800 01644 movf INDF,w ; read data from INDF = *(FSR) 027D 0008 01645 return ; that's all 01646 01647 01648 ;======================================================================= 01649 ; Append a Byte to the recorded message (only if recording is active), 01650 ; turn recording "off" if there's no "recording-memory" left. 01651 ; Input parameters: 01652 ; w contains the byte to be appended 01653 ; KY_mem_index contains current index of recorded message string 01654 ; KY_flags.ky_message2: 0="use Message #1 (EEPROM) 01655 ; 1="use Message #2 (RAM) 01656 ; Output parameters, changed variables: 01657 ; KY_mem_index will be decremented 01658 ; KY_flags.ky_recording may be reset here if running out of memory 01659 ; KY_char_latch will be overwritten with "1" 01660 ; 01661 ;======================================================================= 027E 01662 AppendToMessage: 027E 1D32 01663 btfss KY_flags,ky_recording ; "RECORDING" still active ? 027F 0008 01664 return ; no, no action allowed. 0280 00BD 01665 movwf bStorageData ; data to be written -> bStorageData (not EEDATA, may be bank1 !!) 0281 1A32 01666 btfsc KY_flags, ky_message2 ; is "message 2" used ? 0282 2A8A 01667 goto Append_msg2 ; yes, message2 -> other part 01668 ; Append to "Message1" (that's the one in EEPROM) 0283 0831 01669 movf KY_mem_index,w ; load current "saving" address 0284 2248 01670 call SaveInEEPROM ; save in 0285 0BB1 01671 App_di: decfsz KY_mem_index,F ; address for next recorded letter 0286 0008 01672 return ; enough memory, don't stop recording 01673 ; else: ran out of message memory, stop recording, set "full"-flag 0287 1132 01674 bcf KY_flags,ky_recording ; stop "RECORDING" now 0288 16B2 01675 bsf KY_flags,ky_msg_full ; set "message buffer full" - flag 01676 ; (will generate "f" on pizeo with system message pitch) 0289 0008 01677 return ; back to caller 028A 01678 Append_msg2 ; if "Message2" is used instead of "Message1". 01679 ; Message2 is stored in RAM, not in EEPROM. 01680 ; Add the base address of the RAM-Buffer to the index 01681 ; and use indexed addressing to write the byte into the buffer. 028A 3040 01682 movlw Msg2_Start ; Base address of RAM-Message gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 33 LOC OBJECT CODE LINE SOURCE TEXT VALUE 028B 0731 01683 addwf KY_mem_index,w ; ..plus "index".. 028C 1383 01684 bcf STATUS, IRP ; indirect access 0x00..0xFF via FSR 028D 0084 01685 movwf FSR ; store in "data memory pointer" 028E 083D 01686 movf bStorageData,w ; get write data from temporary var (to use EEDATA is impossible for F628 !) 028F 0080 01687 movwf INDF ; write to INDF = *(FSR) 0290 2A85 01688 goto App_di ; continue with decrementing index 01689 01690 01691 ;======================================================================= 01692 ; Increment serial number (three-digit bcd) 01693 ; NR_ones, NR_tens, NR_hundreds. 01694 ;======================================================================= 0291 01695 IncrementNumber: 0291 0ABC 01696 incf NR_ones,F 0292 300A 01697 movlw d'10' 0293 023C 01698 subwf NR_ones,w 0294 1D03 01699 btfss STATUS,Z 0295 0008 01700 return 0296 01BC 01701 clrf NR_ones 0297 0ABB 01702 incf NR_tens,F 0298 300A 01703 movlw d'10' 0299 023B 01704 subwf NR_tens,w 029A 1D03 01705 btfss STATUS,Z 029B 0008 01706 return 029C 01BB 01707 clrf NR_tens 029D 0ABA 01708 incf NR_hundreds,F 029E 300A 01709 movlw d'10' 029F 023A 01710 subwf NR_hundreds,w 02A0 1D03 01711 btfss STATUS,Z 02A1 0008 01712 return 02A2 01BA 01713 clrf NR_hundreds 02A3 0008 01714 return 01715 01716 01717 ;======================================================================= 01718 ; Switch to 'Power Down' state (using sleep instruction) 01719 ;======================================================================= 01720 ; This subroutine is called after a certain time of "no activity". 01721 ; Caller is the "keyer state machine". 01722 ; Returns to caller as soon as "something happens" on Port B. 02A4 01723 PowerDown: 01724 ; prepare on-chip peripherals for SLEEP mode. 02A4 1305 01725 bcf IOP_KEY_OUTPUT ; carrier off 02A5 1385 01726 bcf IOP_AUDIO_OUT ; sidetone off 02A6 1085 01727 bcf IOP_TX_CONTROL ; transmitter off, receiver on 02A7 1106 01728 bcf IOP_SIGNAL_LED ; signal-LED off 01729 01730 ; set "wakeup" interrupt source to "Change on Port B" only 02A8 3008 01731 movlw b'00001000' ; new INTCON value: only RB0 Interrupt 01732 ; |||||||| 01733 ; |||||||+--RBIF: RB Port Change Interrupt Flag 01734 ; ||||||+---INTF: External Interrupt Flag 01735 ; |||||+----T0IF: Timer0 Overflow Interrupt Flag 01736 ; ||||+-----RBIE: Port Change Interrupt Enable gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 34 LOC OBJECT CODE LINE SOURCE TEXT VALUE 01737 ; |||+------INTE: INT Interrupt Enable 01738 ; ||+-------T0IE: T0IF Interupt Enable 01739 ; |+--------EEIE: EE Write Complete Interrupt Enable 01740 ; +---------GIE: Global Interrupt Enable 02A9 008B 01741 movwf INTCON 02AA 0063 01742 sleep ; supply current less 1uA now.. 02AB 0000 01743 nop 02AC 018B 01744 clrf INTCON ; disable interrupt on "Port B change" 02AD 0008 01745 return 01746 ;------ end of subroutine 'PowerDown' ----------------- 01747 01748 01749 ;========================================================================== 01750 ; Short Delay Routines (n NOPs + call&return time) 01751 ;========================================================================== 02AE 0000 01752 Delay10: nop 02AF 0000 01753 Delay9: nop 02B0 0000 01754 Delay8: nop 02B1 0000 01755 Delay7: nop 02B2 0000 01756 Delay6: nop 02B3 0000 01757 Delay5: nop 02B4 0000 01758 Delay4: nop 02B5 0000 01759 Delay3: nop 02B6 0000 01760 Delay2: nop 02B7 0000 01761 Delay1: nop 02B8 0008 01762 return 01763 01764 01765 01766 ;========================================================================== 01767 ; Generates a "message beep sequence" for feedback after special key-inputs. 01768 ; This "message" may be cancelled by any paddle contact... 01769 ; it does *NOT* disturb normal keying operation ! 01770 ; (only audible if sidetone-output is used) 01771 ; Input parameters: 01772 ; w contains an 8-bit message pattern, 01773 ; "1"-Bit = Signal on, "0"-Bit = Signal off 01774 ; Output parameters: 01775 ; KY_flags.beep_cpl: 1="Beep completed" 0="Beep cancelled" 01776 ; 01777 ; Side effects: 01778 ; destroys the contents of 01779 ; - KY_char_latch 01780 ; - KY_count_elements 01781 ; - KY_dot_counter 01782 ; 01783 ;========================================================================== 02B9 01784 #define L_timer KY_decoded_char 01785 02B9 01786 MessageBeeps: 02B9 1332 01787 bcf KY_flags,ky_beep_cpl ; "Beep not completed" 02BA 00B3 01788 movwf KY_char_latch ; store pattern in "shift register" 02BB 3008 01789 movlw 8 ; number of "bits" in message pattern 02BC 00B5 01790 movwf KY_count_elements gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 35 LOC OBJECT CODE LINE SOURCE TEXT VALUE 02BD 3028 01791 MsgB_1: movlw d'040' ; number of tone periods per signal element 02BE 00B6 01792 movwf KY_dot_counter 02BF 1BB3 01793 btfsc KY_char_latch,7 02C0 1506 01794 bsf IOP_SIGNAL_LED ; activate signal-LED if pattern bit "1" 02C1 1FB3 01795 btfss KY_char_latch,7 02C2 1106 01796 bcf IOP_SIGNAL_LED 02C3 1BB3 01797 MsgB_2: btfsc KY_char_latch,7 02C4 1785 01798 bsf IOP_AUDIO_OUT ; sidetone "high" if next pattern bit "1" 02C5 22B2 01799 call Delay6 02C6 1385 01800 bcf IOP_AUDIO_OUT ; sidetone "low" 02C7 22B7 01801 call Delay1 02C8 1E06 01802 btfss IOP_DOT 02C9 2AD2 01803 goto MsgB_3 ; "dot"-contact closed -> cancel 02CA 1E86 01804 btfss IOP_DASH 02CB 2AD2 01805 goto MsgB_3 ; "dash"-contact closed -> cancel 02CC 0BB6 01806 decfsz KY_dot_counter,F ; more tone periods ? 02CD 2AC3 01807 goto MsgB_2 ; yes, next period 02CE 0DB3 01808 rlf KY_char_latch,F ; shift signal pattern 02CF 0BB5 01809 decfsz KY_count_elements,F ; more bits in pattern ? 02D0 2ABD 01810 goto MsgB_1 ; yes, next bit of pattern 02D1 1732 01811 bsf KY_flags,ky_beep_cpl ; "Beep Completed" 02D2 1106 01812 MsgB_3: bcf IOP_SIGNAL_LED ; signal-LED off 02D3 3001 01813 movlw 1 ; set "default" contents... 02D4 00B3 01814 movwf KY_char_latch ; ..with "start bit" in position 0 02D5 0008 01815 return 01816 ;------ end of subroutine 'Message Beeps' ----------------- 01817 01818 01819 01820 ;========================================================================== 01821 ; Generate warning signals if any warn/error-flags are pending 01822 ;========================================================================== 02D6 01823 WarningSignals: 01824 ; Has message recording been stopped because memory is full ? 02D6 1EB2 01825 btfss KY_flags,ky_msg_full 02D7 2ADE 01826 goto warn_sig_nfull 02D8 30AE 01827 movlw b'10101110' ; Message-Beep: "f"... 02D9 22B9 01828 call MessageBeeps ; ... means "recording memory Full" 02DA 3080 01829 movlw b'10000000' 02DB 22B9 01830 call MessageBeeps 02DC 1B32 01831 btfsc KY_flags,ky_beep_cpl ; only if beep signal "completed": 02DD 12B2 01832 bcf KY_flags,ky_msg_full ; reset warn flag 02DE 01833 warn_sig_nfull: 02DE 0008 01834 return 01835 01836 01837 ;======================================================================= 01838 ; Convert a morse-code-digit(KY_decoded_char) into a BCD value (w) 01839 ; input parameters: 01840 ; KY_decoded_char: contains the morse code of a numeric digit (hopefully) 01841 ; output parameters: 01842 ; STATUS.DC: 0 = all ok, 1 = error occured (not a digit) 01843 ; w : returns the decimal value if no error 01844 ; Side effects: gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 36 LOC OBJECT CODE LINE SOURCE TEXT VALUE 01845 ; destroys the contents of 01846 ; - KY_char_latch 01847 ;======================================================================= 02DF 01848 MorseToDigit: 01849 ; - used by command handler if a number is entered in morse code. 01850 ; - cannot be implemented via "table" because of low memory. 01851 ; - instead we call the "inverse" function DigitToMorse to "find" 01852 ; the binary value. 02DF 300A 01853 movlw d'10' ; load max. bcd value 02E0 00B3 01854 movwf KY_char_latch ; ..also as "loop counter" 02E1 0333 01855 MorseD1: decf KY_char_latch,w ; load (value-1) into w 02E2 2001 01856 call DigitToMorse ; decimal-digit(w) to morse code(w) 02E3 0234 01857 subwf KY_decoded_char,w ; found the number ? 02E4 1903 01858 btfsc STATUS,Z 02E5 2AF3 01859 goto MorseD3 ; yes, got the number ! 02E6 0BB3 01860 decfsz KY_char_latch,F ; no, test next BCD number 02E7 2AE1 01861 goto MorseD1 01862 ; Morse character not found in the "standard set"... 01863 ; maybe it was a "quick digit" like "N" instead of "9": 02E8 300A 01864 movlw d'10' ; load max. bcd value 02E9 00B3 01865 movwf KY_char_latch ; ..also as "loop counter" 02EA 0333 01866 MorseD2: decf KY_char_latch,w ; load (value-1) into w 02EB 2013 01867 call DigitToMorse_Quick ; decimal-digit(w) to morse code(w) 02EC 0234 01868 subwf KY_decoded_char,w ; found the number ? 02ED 1903 01869 btfsc STATUS,Z 02EE 2AF3 01870 goto MorseD3 ; yes, got the number ! 02EF 0BB3 01871 decfsz KY_char_latch,F ; no, test next BCD number 02F0 2AEA 01872 goto MorseD2 01873 ; seems we're out of luck, number not found, digit cannot be decoded. 02F1 1483 01874 bsf STATUS,DC ; error flag for "return value" 02F2 3400 01875 retlw 0 02F3 01876 MorseD3: ; found the number, return its value. 02F3 0333 01877 decf KY_char_latch,w ; w := KY_char_latch-1 02F4 1083 01878 bcf STATUS,DC ; no error 02F5 0008 01879 return ; return with BCD value in w 01880 ; end of function MorseToDigit(w) 01881 01882 01883 01884 01885 ;========================================================================== 01886 ; Handle Command Code (KY_decoded_char) 01887 ; - will be called by morse decoder after completion of a decoded letter, 01888 ; if "command mode" is active. 01889 ;========================================================================== 02F6 01890 CommandDispatcher: 01891 ; first check if we are just waiting for a numeric input (serial) 02F6 1EB9 01892 btfss NR_flags,nr_digit1 ; 1st digit of three-digit-number ? 02F7 2AFF 01893 goto cmd_di1 02F8 22DF 01894 call MorseToDigit ; convert entered code to BCD 02F9 1883 01895 btfsc STATUS,DC ; Conversion ok ? 02FA 2B80 01896 goto cmd_nr_error ; error, probably a "bad digit" 02FB 12B9 01897 bcf NR_flags,nr_digit1 ; ok, 1st digit done... 02FC 1739 01898 bsf NR_flags,nr_digit2 ; now wait for 2nd digit gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 37 LOC OBJECT CODE LINE SOURCE TEXT VALUE 02FD 00BA 01899 movwf NR_hundreds ; set "hundreds" of serial 02FE 2825 01900 goto main_loop ; don't say "roger" until number ready! 02FF 1F39 01901 cmd_di1: btfss NR_flags,nr_digit2 ; 2nd digit of three-digit-number sent? 0300 2B08 01902 goto cmd_di2 0301 22DF 01903 call MorseToDigit ; convert entered code to BCD 0302 1883 01904 btfsc STATUS,DC ; Conversion ok ? 0303 2B80 01905 goto cmd_nr_error ; error, probably a "bad digit" 0304 1339 01906 bcf NR_flags,nr_digit2 ; ok, 2nd digit done... 0305 17B9 01907 bsf NR_flags,nr_digit3 ; now wait for 3rd digit 0306 00BB 01908 movwf NR_tens ; set "tens" of serial 0307 2825 01909 goto main_loop ; don't say "roger" until number ready! 0308 1FB9 01910 cmd_di2: btfss NR_flags,nr_digit3 ; 3rd digit of three-digit-number sent? 0309 2B10 01911 goto cmd_di3 030A 22DF 01912 call MorseToDigit ; convert entered code to BCD 030B 1883 01913 btfsc STATUS,DC ; Conversion ok ? 030C 2B80 01914 goto cmd_nr_error ; error, probably a "bad digit" 030D 13B9 01915 bcf NR_flags,nr_digit3 ; ok, 3rd digit done... 030E 00BC 01916 movwf NR_ones ; set "ones" of serial 030F 2B83 01917 goto cmd_ok ; now say "roger", number is "ready"! 0310 01918 cmd_di3: 01919 ; else: no "number"-transmission in progress. 01920 ; Find out which "Keyer-Command" has been entered.. 0310 3005 01921 movlw CW_CHR_A ; switch to "iambic mode A" ? 0311 0234 01922 subwf KY_decoded_char,w 0312 1D03 01923 btfss STATUS,Z 0313 2B16 01924 goto cmd_na 0314 1439 01925 bsf OP_flags,op_dot_memory_off 0315 2B83 01926 goto cmd_ok 0316 3018 01927 cmd_na: movlw CW_CHR_B ; switch to "iambic mode B" ? 0317 0234 01928 subwf KY_decoded_char,w 0318 1D03 01929 btfss STATUS,Z 0319 2B1C 01930 goto cmd_nb 031A 1039 01931 bcf OP_flags,op_dot_memory_off 031B 2B83 01932 goto cmd_ok 031C 301A 01933 cmd_nb: movlw CW_CHR_C ; Activate "beaCon" mode ? 031D 0234 01934 subwf KY_decoded_char,w ; (similar to "endless mode", 031E 1D03 01935 btfss STATUS,Z ; but no "255-loops-timeout) 031F 2B23 01936 goto cmd_nc 0320 1639 01937 bsf OP_flags,op_beacon_mode ; turn BEACON mode on 0321 11B9 01938 bcf OP_flags,op_loop_mode ; but turn LOOP mode off (!) 0322 2B83 01939 goto cmd_ok 0323 300C 01940 cmd_nc: movlw CW_CHR_D ; command entry "Done" ? 0324 0234 01941 subwf KY_decoded_char,w 0325 1D03 01942 btfss STATUS,Z 0326 2B29 01943 goto cmd_nd 0327 13B2 01944 bcf KY_flags,ky_wait_cmd ; clear "waiting for command" - flag 0328 2B83 01945 goto cmd_ok 0329 3002 01946 cmd_nd: movlw CW_CHR_E ; set lower CW speed. 032A 0234 01947 subwf KY_decoded_char,w 032B 1D03 01948 btfss STATUS,Z 032C 2B38 01949 goto cmd_ne 032D 0AAF 01950 incf CW_timing,1 032E 0AAF 01951 incf CW_timing,1 032F 0AAF 01952 incf CW_timing,1 gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 38 LOC OBJECT CODE LINE SOURCE TEXT VALUE 01953 01954 ; If CW period becomes greater than the max allowed (i.e. min speed) 01955 ; wrap around to min period (i.e. max speed). We could get the period 01956 ; as low as d'190' but then it takes too many "E" commands to get there 01957 ; from any reasonable speed, so let's set the floor at d'105', which 01958 ; gives a minimum speed of approx. 6 WPM. 01959 0330 082F 01960 movf CW_timing,0 0331 3C69 01961 sublw d'105' 0332 1803 01962 btfsc STATUS,C ; min speed exceeded if C is cleared 01963 ; goto cmd_ok ; "R" response not needed here 0333 2B36 01964 goto cmd_e2 0334 300C 01965 movlw d'012' ; wrap around to max speed 0335 00AF 01966 movwf CW_timing 0336 0103 01967 cmd_e2: clrw ; mandatory 0337 2B84 01968 goto cmd_mb_quit 0338 3012 01969 cmd_ne: movlw CW_CHR_F ; toggle "Endless loop mode" ? 0339 0234 01970 subwf KY_decoded_char,w ; (use it if your TRX has "QSK" 033A 1D03 01971 btfss STATUS,Z ; ..or at least "SEMI-BK") 033B 2B44 01972 goto cmd_nf 033C 1DB9 01973 btfss OP_flags,op_loop_mode ; if "loop mode" is ON... 033D 2B41 01974 goto cmd_f2 033E 11B9 01975 bcf OP_flags,op_loop_mode ; ...then turn LOOP mode OFF, 033F 1239 01976 bcf OP_flags,op_beacon_mode ; ...also turn the BEACON off 0340 2B83 01977 goto cmd_ok 0341 01978 cmd_f2: ; else: "E"-cmd, "loop mode" was off: 0341 15B9 01979 bsf OP_flags,op_loop_mode ; ...turn LOOP mode on 0342 1239 01980 bcf OP_flags,op_beacon_mode ; ..but turn the BEACON off 0343 2B83 01981 goto cmd_ok 0344 3014 01982 cmd_nf: movlw CW_CHR_L ; switch to "List mode" ? 0345 0234 01983 subwf KY_decoded_char,w ; (used to "list" message memory.. 0346 1D03 01984 btfss STATUS,Z ; ..without expanding the macros) 0347 2B4A 01985 goto cmd_nl 0348 14B9 01986 bsf OP_flags,op_list_mode ; no more "macro expansion" 0349 2B83 01987 goto cmd_ok 034A 3007 01988 cmd_nl: movlw CW_CHR_M ; switch to "Macro mode" ? 034B 0234 01989 subwf KY_decoded_char,w 034C 1D03 01990 btfss STATUS,Z 034D 2B50 01991 goto cmd_nm 034E 10B9 01992 bcf OP_flags,op_list_mode ; terminate "list" = enable macro expansion 034F 2B83 01993 goto cmd_ok 0350 3006 01994 cmd_nm: movlw CW_CHR_N ; enter three-digit "Number" ? 0351 0234 01995 subwf KY_decoded_char,w 0352 1D03 01996 btfss STATUS,Z 0353 2B58 01997 goto cmd_nn 0354 16B9 01998 bsf NR_flags,nr_digit1 ; set flag to receive 1st digit 0355 30E8 01999 movlw b'11101000' 0356 22B9 02000 call MessageBeeps ; signal "N", then.. 0357 2B83 02001 goto cmd_ok ; signal "R" 0358 301D 02002 cmd_nn: movlw CW_CHR_Q ; activate "Quick digit mode" ? 0359 0234 02003 subwf KY_decoded_char,w 035A 1D03 02004 btfss STATUS,Z 035B 2B5E 02005 goto cmd_nq 035C 1539 02006 bsf OP_flags,op_quick_digits gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 39 LOC OBJECT CODE LINE SOURCE TEXT VALUE 035D 2B83 02007 goto cmd_ok 035E 3008 02008 cmd_nq: movlw CW_CHR_S ; activate "Standard digit mode" ? 035F 0234 02009 subwf KY_decoded_char,w ; (also call it "Slow digit mode") 0360 1D03 02010 btfss STATUS,Z 0361 2B64 02011 goto cmd_ns 0362 1139 02012 bcf OP_flags,op_quick_digits 0363 2B83 02013 goto cmd_ok 0364 3003 02014 cmd_ns: movlw CW_CHR_T ; set higher CW speed. 0365 0234 02015 subwf KY_decoded_char,w 0366 1D03 02016 btfss STATUS,Z 0367 2B73 02017 goto cmd_nt 0368 03AF 02018 decf CW_timing,1 0369 03AF 02019 decf CW_timing,1 036A 03AF 02020 decf CW_timing,1 02021 02022 ; If CW period becomes less than d'012' (which gives a max speed 02023 ; of about 45 WPM) wrap around to max period (i.e. min speed). 02024 036B 300C 02025 movlw d'012' 036C 022F 02026 subwf CW_timing,0 036D 1803 02027 btfsc STATUS,C ; min speed exceeded if C is cleared 02028 ; goto cmd_ok ; "R" response not needed here 036E 2B71 02029 goto cmd_t2 036F 3069 02030 movlw d'105' ; wrap around to min speed 0370 00AF 02031 movwf CW_timing 0371 0103 02032 cmd_t2: clrw 0372 2B84 02033 goto cmd_mb_quit 0373 3009 02034 cmd_nt: movlw CW_CHR_U ; "tUne mode" (continuous carrier)? 0374 0234 02035 subwf KY_decoded_char,w 0375 1D03 02036 btfss STATUS,Z 0376 2B7C 02037 goto cmd_nu 0377 3041 02038 movlw d'65' ; allow 65*256 loops of "tuning" 0378 00B8 02039 movwf NoActivityTimer ; .. that's about 30 seconds 0379 3019 02040 movlw KYS_TUNE 037A 00AE 02041 movwf KY_state 02042 ; goto cmd_ok ; "R" response not needed here 037B 2825 02043 goto main_loop ; No call to "MessageBeeps" either 037C 02044 cmd_nu: 02045 037C 02046 cmd_error: ; command not recognized, signal questionmark 037C 30AE 02047 movlw b'10101110' ; Message-Beep: "?" 037D 22B9 02048 call MessageBeeps 037E 30EA 02049 movlw b'11101010' 037F 2B84 02050 goto cmd_mb_quit ; send signal(w), then quit 0380 02051 cmd_nr_error: ; "numeric error", signal "N?" 0380 30E8 02052 movlw b'11101000' 0381 22B9 02053 call MessageBeeps ; signal "N" 0382 2B7C 02054 goto cmd_error 02055 0383 02056 cmd_ok: ; command recognized, signal "R" (roger) 02057 ; and continue main loop. 0383 30BA 02058 movlw b'10111010' 0384 02059 cmd_mb_quit: ; send signal(w), then quit (to main_loop) 0384 22B9 02060 call MessageBeeps gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 40 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0385 2825 02061 goto main_loop 02062 gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 41 SYMBOL TABLE LABEL VALUE ADEN 00000003 App_di 00000285 AppendToMessage 0000027E Append_msg2 0000028A BRGH 00000002 C 00000000 C1INV 00000004 C1OUT 00000006 C2INV 00000005 C2OUT 00000007 CCP1CON 00000017 CCP1IE 00000002 CCP1IF 00000002 CCP1M0 00000000 CCP1M1 00000001 CCP1M2 00000002 CCP1M3 00000003 CCP1X 00000005 CCP1Y 00000004 CCPR1H 00000016 CCPR1L 00000015 CIS 00000003 CM0 00000000 CM1 00000001 CM2 00000002 CMCON 0000001F CMIE 00000006 CMIF 00000006 CREN 00000004 CSRC 00000007 CW_t_cnt 00000030 CW_timing 0000002F CommandDispatcher 000002F6 DC 00000001 Delay1 000002B7 Delay10 000002AE Delay2 000002B6 Delay3 000002B5 Delay4 000002B4 Delay5 000002B3 Delay6 000002B2 Delay7 000002B1 Delay8 000002B0 Delay9 000002AF DigitToMorse 00000001 DigitToMorse_Quick 00000013 EEADR 0000009B EECON1 0000009C EECON2 0000009D EEDATA 0000009A EEIE 00000007 EEIF 00000007 F 00000001 gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 42 LOC OBJECT CODE LINE SOURCE TEXT VALUE FERR 00000002 FSR 00000004 GIE 00000007 INDF 00000000 INTCON 0000000B INTE 00000004 INTEDG 00000006 INTF 00000001 IRP 00000007 IncrementNumber 00000291 KY_char_latch 00000033 KY_count_elements 00000035 KY_decoded_char 00000034 KY_dot_counter 00000036 KY_flags 00000032 KY_mem_index 00000031 KY_state 0000002E KeyerTask 00000029 MessageBeeps 000002B9 MorseD1 000002E1 MorseD2 000002EA MorseD3 000002F3 MorseToDigit 000002DF Msg2_End 0000006F Msg2_Start 00000040 MsgB_1 000002BD MsgB_2 000002C3 MsgB_3 000002D2 NOT_BO 00000000 NOT_BOD 00000000 NOT_BOR 00000000 NOT_PD 00000003 NOT_POR 00000001 NOT_RBPU 00000007 NOT_T1SYNC 00000002 NOT_TO 00000004 NR_hundreds 0000003A NR_ones 0000003C NR_tens 0000003B NoActivityTimer 00000038 OERR 00000001 OPTION_REG 00000081 OP_flags 00000039 OSCF 00000003 PCL 00000002 PCLATH 0000000A PCON 0000008E PEIE 00000006 PIE1 0000008C PIR1 0000000C PORTA 00000005 PORTB 00000006 PR2 00000092 PS0 00000000 gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 43 LOC OBJECT CODE LINE SOURCE TEXT VALUE PS1 00000001 PS2 00000002 PSA 00000003 PowerDown 000002A4 RAM_MSG2_LENGTH 00000030 RBIE 00000003 RBIF 00000000 RCIE 00000005 RCIF 00000005 RCREG 0000001A RCSTA 00000018 RD 00000000 RP0 00000005 RP1 00000006 RX9 00000006 RX9D 00000000 ReadFM1 00000276 ReadFM2 00000277 ReadFromEEPROM 0000025F ReadFromMessage 00000271 SPBRG 00000099 SPEN 00000007 SREN 00000005 STATUS 00000003 SYNC 00000004 SaveEW 00000257 SaveInEEPROM 00000248 SaveRdy 0000025B StopR2 0000026B StopRecording 00000267 T0CS 00000005 T0IE 00000005 T0IF 00000002 T0SE 00000004 T1CKPS0 00000004 T1CKPS1 00000005 T1CON 00000010 T1OSCEN 00000003 T2CKPS0 00000000 T2CKPS1 00000001 T2CON 00000012 TMR0 00000001 TMR1CS 00000001 TMR1H 0000000F TMR1IE 00000000 TMR1IF 00000000 TMR1L 0000000E TMR1ON 00000000 TMR2 00000011 TMR2IE 00000001 TMR2IF 00000001 TMR2ON 00000002 TOUTPS0 00000003 TOUTPS1 00000004 gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 44 LOC OBJECT CODE LINE SOURCE TEXT VALUE TOUTPS2 00000005 TOUTPS3 00000006 TRISA 00000085 TRISB 00000086 TRMT 00000001 TX9 00000006 TX9D 00000000 TXEN 00000005 TXIE 00000004 TXIF 00000004 TXREG 00000019 TXSTA 00000098 VR0 00000000 VR1 00000001 VR2 00000002 VR3 00000003 VRCON 0000009F VREN 00000007 VROE 00000006 VRR 00000005 W 00000000 WR 00000001 WREN 00000002 WRERR 00000003 WarningSignals 000002D6 Z 00000002 _BODEN_OFF 00003FBF _BODEN_ON 00003FFF _BOREN_OFF 00003FBF _BOREN_ON 00003FFF _CP_OFF 00003FFF _CP_ON 00001FFF _DATA_CP_OFF 00003FFF _DATA_CP_ON 00003EFF _ER_OSC_CLKOUT 00003FFF _ER_OSC_NOCLKOUT 00003FFE _EXTCLK_OSC 00003FEF _HS_OSC 00003FEE _INTOSC_OSC_CLKOUT 00003FFD _INTOSC_OSC_NOCLKOUT 00003FFC _INTRC_OSC_CLKOUT 00003FFD _INTRC_OSC_NOCLKOUT 00003FFC _LP_OSC 00003FEC _LVP_OFF 00003F7F _LVP_ON 00003FFF _MCLRE_OFF 00003FDF _MCLRE_ON 00003FFF _PWRTE_OFF 00003FFF _PWRTE_ON 00003FF7 _RC_OSC_CLKOUT 00003FFF _RC_OSC_NOCLKOUT 00003FFE _WDT_OFF 00003FFB _WDT_ON 00003FFF _XT_OSC 00003FED gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 45 LOC OBJECT CODE LINE SOURCE TEXT VALUE __16F628A 00000001 bStorageData 0000003D cmd_di1 000002FF cmd_di2 00000308 cmd_di3 00000310 cmd_e2 00000336 cmd_error 0000037C cmd_f2 00000341 cmd_mb_quit 00000384 cmd_na 00000316 cmd_nb 0000031C cmd_nc 00000323 cmd_nd 00000329 cmd_ne 00000338 cmd_nf 00000344 cmd_nl 0000034A cmd_nm 00000350 cmd_nn 00000358 cmd_nq 0000035E cmd_nr_error 00000380 cmd_ns 00000364 cmd_nt 00000373 cmd_nu 0000037C cmd_ok 00000383 cmd_t2 00000371 end_of_page0 00000046 kyt_append 000000BA kyt_ns 000000F3 kyt_play_beacon 00000119 kyt_play_check_end_msg 0000017C kyt_play_chk_loop 00000115 kyt_play_control_code 000000F2 kyt_play_digit1 00000120 kyt_play_el_continue 00000158 kyt_play_get_next_char 000000EA kyt_play_inc_nnn 0000011E kyt_play_init1 00000133 kyt_play_init2 00000135 kyt_play_init3 00000137 kyt_play_init4 00000139 kyt_play_init5 0000013B kyt_play_init6 0000013D kyt_play_init_char 00000127 kyt_play_init_digit 00000122 kyt_play_ltr_continues 0000016F kyt_play_nd1 00000182 kyt_play_nd2 00000187 kyt_play_next2 000000EA kyt_play_next_elem 0000013D kyt_play_next_loop 0000010F kyt_play_normal_letter 000000FC kyt_play_pause 000000F5 kyt_play_start_pause1 0000015B kyt_play_stop 0000011C gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 46 LOC OBJECT CODE LINE SOURCE TEXT VALUE kyt_play_wait_continues 00000177 kyt_play_wait_elem 0000014F kyt_play_wait_pause1 00000161 kyt_play_wait_pause2 00000171 kyt_play_wait_space 00000144 kyt_prepare_wait 00000046 kyt_prepare_wait_1dot 000000A6 kyt_send_dash 00000085 kyt_send_dash2 0000008E kyt_send_dot 00000064 kyt_space_incr_dots 000000DF kyt_space_save 000000E6 kyt_space_wait_dot 000000D7 kyt_start_dash 0000007F kyt_start_dash_pause 00000091 kyt_start_dot 0000005C kyt_tu2 00000199 kyt_tune 0000018B kyt_tune_stop 0000019A kyt_tune_stop2 0000019C kyt_wait_dash_pause 0000009A kyt_wait_dot_pause 00000072 kyt_wait_less_1dot 000000AA kyt_wait_less_5dots 000000BF kyt_wait_less_5dots2 000000C4 kyt_wait_less_5dots3 000000C9 kyt_waiting 00000052 main_loop 00000025 main_loop_sync 00000025 main_loop_sync12 00000062 msg1_play 000001DF msg1_pressed 000001C6 msg1_record 000001DA msg1_then_2 0000021F msg1_wait_release1 000001CB msg1_wait_release2 000001D4 msg2_play 00000246 msg2_pressed 0000022D msg2_record 00000241 msg2_then_1 0000021F msg2_wait_release1 00000232 msg2_wait_release2 0000023B msg_br 00000228 msg_done_command 0000022A msg_play 000001E0 msg_play_i 0000020D msg_play_no_partition 000001EB msg_play_partitioned 000001EF msg_play_skip_eom 000001E3 msg_pp0 000001F2 msg_pp1 000001F3 msg_pp2 000001FA msg_pp3 000001FB msg_pp5 00000203 gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 47 LOC OBJECT CODE LINE SOURCE TEXT VALUE msg_pp6 00000204 msg_pp7 00000208 msg_record_i 000001DC msg_release_both_buttons 00000217 msg_release_btn_pdown 00000216 msg_stop_recording 00000212 no_button 00000029 reset 0000019E status_temp 00000071 w_temp 00000070 warn_sig_nfull 000002DE CW_CHR_0 b'00111111' CW_CHR_1 b'00101111' CW_CHR_2 b'00100111' CW_CHR_3 b'00100011' CW_CHR_4 b'00100001' CW_CHR_5 b'00100000' CW_CHR_6 b'00110000' CW_CHR_7 b'00111000' CW_CHR_8 b'00111100' CW_CHR_9 b'00111110' CW_CHR_? b'01001100' CW_CHR_A b'00000101' CW_CHR_ANN b'01011010' CW_CHR_AR b'00101010' CW_CHR_B b'00011000' CW_CHR_C b'00011010' CW_CHR_D b'00001100' CW_CHR_E b'00000010' CW_CHR_EOM b'01011111' CW_CHR_F b'00010010' CW_CHR_G b'00001110' CW_CHR_H b'00010000' CW_CHR_I b'00000100' CW_CHR_J b'00010111' CW_CHR_K b'00001101' CW_CHR_KA b'00110101' CW_CHR_KN b'00110110' CW_CHR_L b'00010100' CW_CHR_M b'00000111' CW_CHR_N b'00000110' CW_CHR_NNN b'01101010' CW_CHR_O b'00001111' CW_CHR_P b'00010110' CW_CHR_POINT b'01010101' CW_CHR_Q b'00011101' CW_CHR_R b'00001010' CW_CHR_S b'00001000' CW_CHR_SEPA2 b'01100001' CW_CHR_SEPAR b'00110001' CW_CHR_SK b'01000101' CW_CHR_SLASH b'00110010' CW_CHR_SPACE b'10000000' CW_CHR_T b'00000011' gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 48 LOC OBJECT CODE LINE SOURCE TEXT VALUE CW_CHR_U b'00001001' CW_CHR_V b'00010001' CW_CHR_W b'00001011' CW_CHR_X b'00011001' CW_CHR_Y b'00011011' CW_CHR_Z b'00011100' EEPROM_ADR_CW_SPEED 0x7F EEPROM_ADR_MSG1_START 0x7E IOP_AUDIO_OUT PORTA, 7 IOP_DASH PORTB, 5 IOP_DOT PORTB, 4 IOP_HAND_KEY PORTB, 3 IOP_I2C_CLK PORTA, 4 IOP_KEY_MSG1 PORTB, 7 IOP_KEY_MSG2 PORTB, 6 IOP_KEY_OUTPUT PORTA, 6 IOP_RESERVE1 PORTB, 0 IOP_SIGNAL_LED PORTB, 2 IOP_TX_CONTROL PORTA, 1 IOP_UNUSED_RA0 PORTA, 0 IOP_UNUSED_RA2 PORTA, 2 IOP_UNUSED_RA3 PORTA, 3 IOP_UNUSED_RA4 PORTA, 4 IOP_UNUSED_RA5 PORTA, 5 KYS_PLAY_CHECK_END_MSG d'24' KYS_PLAY_GET_NEXT_CHAR d'15' KYS_PLAY_START_PAUSE1 d'20' KYS_PLAY_WAIT_DASH d'17' KYS_PLAY_WAIT_DASH2 d'18' KYS_PLAY_WAIT_DOT d'19' KYS_PLAY_WAIT_PAUSE1 d'21' KYS_PLAY_WAIT_PAUSE2 d'22' KYS_PLAY_WAIT_PAUSE22 d'23' KYS_PLAY_WAIT_SPACE d'16' KYS_PREPARE_WAIT 0 KYS_SEND_DASH 4 KYS_SEND_DASH2 5 KYS_SEND_DASH3 6 KYS_SEND_DOT 2 KYS_SPACE_INCR_DOTS d'14' KYS_SPACE_WAIT_DOT d'13' KYS_START_DASH_PAUSE 7 KYS_TUNE d'25' KYS_WAITING 1 KYS_WAIT_DASH_PAUSE 8 KYS_WAIT_DOT_PAUSE 3 KYS_WAIT_LESS_1DOT 9 KYS_WAIT_LESS_5DOTS d'10' KYS_WAIT_LESS_5DOTS2 d'11' KYS_WAIT_LESS_5DOTS3 d'12' L_save_eep_timer KY_char_latch L_timer KY_decoded_char NR_flags OP_flags SWI_TEST_QRQ 0 gpasm-0.13.7 beta qrpkeyer4.asm9-2-2011 17:06:10 PAGE 49 LOC OBJECT CODE LINE SOURCE TEXT VALUE SWI_WARN_QRK 1 ky_beep_cpl 6 ky_dash 1 ky_dot 0 ky_message2 4 ky_msg_full 5 ky_playing 3 ky_recording 2 ky_wait_cmd 7 nr_digit1 5 nr_digit2 6 nr_digit3 7 op_beacon_mode 4 op_dot_memory_off 0 op_list_mode 1 op_loop_mode 3 op_quick_digits 2 MEMORY USAGE MAP ('X' = Used, '-' = Unused) 00000000 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 00000040 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 00000080 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 000000c0 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 00000100 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 00000140 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 00000180 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 000001c0 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 00000200 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 00000240 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 00000280 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 000002c0 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 00000300 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 00000340 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 00000380 : XXXXXX---------- ---------------- ---------------- ---------------- 00002000 : XXXX---X-------- ---------------- ---------------- ---------------- 00002100 : ---XXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 00002140 : XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX All other memory blocks unused. Program Memory Words Used: 1032 Errors : 0 Warnings : 0 reported, 0 suppressed Messages : 14 reported, 0 suppressed