-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.LST
1274 lines (1243 loc) · 98.9 KB
/
main.LST
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 1
C51 COMPILER V9.55, COMPILATION OF MODULE MAIN
OBJECT MODULE PLACED IN main.OBJ
COMPILER INVOKED BY: C:\Keil_v5\C51\BIN\C51.EXE main.c OPTIMIZE(8,SIZE) BROWSE DEBUG OBJECTEXTEND
line level source
1 /****************************************************************************************
2 ****************** COPYRIGHT (c) 2019 by Joseph Haas (DBA FF Systems) *****************
3 *
4 * File name: main.c
5 *
6 * Module: Control
7 *
8 * Summary: This is the main code file for the HM133 DTMF application
9 * License and other legal stuff:
10 * This software, comprised of all files contained in the original distribution archive,
11 * are protected by US Copyright laws. The files may be used and modified by the person
12 * receiving them under the following terms and conditions:
13 * 1) The software, or any protion thereof may not be distributed to any 3rd party by
14 * the recipient or any agent or assign of the recipient.
15 * 2) The recipient assumes all risks for the use (or mis-use) of this software.
16 *
17 *
18 * Project scope revision history:
19 * *** REV 02 ***
20 * 08-28-19 jmh: Debug of HM151 mode. Tested on IC-7000. Found that the first key is ignored if no
21 * other keys are detected after. This means that the F-2 key needn't be set to a
22 * null command (can't do this anyway). Also verified that HM-151 keys are active
23 * during TX.
24 * Modified code to trap leading and falling edge of 'G' key. If entering pass-thru
25 * mode, delay DMUTE switch until release of 'G', else switch DMUTE immediately.
26 * Revamped init code to make sure DMUTE is not set to pass-thru until just before the
27 * start of the MPL.
28 * Added timer clear statements to init code to cover warm start case.
29 * 08-19-19 jmh: Added pulse delay variable to radio_fbtn[][] array. Kenwood needs at least 80ms,
30 * ICOM can take 40ms. Other delays up to 125 are also included.
31 * HW MOD: changed comparator voltage ref to a voltage divider driven from M8V to
32 * follow what the radios do.
33 * HW MOD: changed how 5V is wired to reset circuit. Debug adapter now works at
34 * least as well as with the 3.3V bypass Vreg.
35 * 08-18-19 jmh: VERS 2 testing continues...
36 * Tested HM151 mode & corrected LED functions. *** Need to test with IC-7000.
37 * Abandoned SPR as a strap, made Ro3 3rd strap.
38 * *** need to test option straps.
39 * 08-17-19 jmh: VERS 2 initial bring-up complete. Issues:
40 * 1) The dual FET footprint was wrong. Had to re-map 4094 bitmap to correct.
41 * LED and DMUTE had to be re-wired, so no SW change for those signals.
42 * PCB rev 003 update complete. Added Ro3 "gimmick" resistor to make P0.6
43 * the 3rd strap option. *** Need to see if this works. ***
44 * 2) Voltage reg either broke or some configuration issue.
45 * Flaky debug and operation modes - will look again at this on 2nd build.
46 * 1st article has a 3V regulator piggy-backed on the 5V Vreg with a jumper to
47 * U2 Vdd net (Vregi pin is lifted). U5 Vhi is about 2.9V...not sure this
48 * can be counted on to work all the time.
49 * Made some code tweaks to get DTMFs to work correctly. Not sure why they broke going
50 * to rev 002 HW. Also, cleaned up some commented-out code (still some left).
51 * Added "mic present" mirror. If strap selects HM151, DN0 = MIC_DET_N any time MIC_DET_N
52 * changes state. In addition to mirror, this code kills PTT and tone related registers
53 * and clears DMUTE if the mic is removed.
54 * Added restart capability to re-initialize system when mic is removed. Code will
55 * continually restart until mic is re-connected.
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 2
56 * Resticted all keys but "M" in HM151 mode. DTMFs will generate if PTT pressed & DMUTE
57 * is active.
58 * 08-15-19 jmh: HM133 DTMF now works (mostly). PTT can NOT be pressed if HM133 DTMF-S is active.
59 * May not need HM133/HM151 strap-opt.
60 * Strap support for revA *mostly* working.
61 * 1st key logic now traps "1st" 1st key and ignores following until button released.
62 * 08-12-19 jmh: Added support for straps. radio_fbtn[][] array holds transistor pulse patterns that
63 * correspond to key/rig combinations.
64 * Added support for extended buttons (MC-44/MH-36) in the button operations switch{} and
65 * in the support Fns.
66 * Changed pulse_up/pulse_dn to a single funtion which now supports all of the transistor
67 * outputs of the CD4094 SR port expander.
68 * VERS 1 now support using DMUTE for a single expansion button (since it won't do the
69 * HM151 FT option correctly).
70 * Added support for HM151 FT mode. Fn LED = off if in FT mode, else, on for DTMF enabled mode.
71 * 08-09-19 jmh: Added #if directives to support PCB version 2. Re-mapped PTT, UP, and DN bit control
-s
72 * to use a central Fn to set/clear bits. Paves the way for port extender to be used
73 * in version 2 PCB. bbSPI code is in place for port expander. Waveforms verified on
74 * o'scope, but not tested. Port update uses TIMER0 ISR to clock 8 bits and strobe
75 * CD4094 port expander I.C.. XFR plus STB takes about 45us.
76 * 08-07-19 jmh: Added feature to interrupt U/D macros on any keypress
77 * Added feature to change Fn LED brightness. If no PTT, "*" = dim, "#" = brt.
78 *
79 * 08-04-19 jmh: basic functionality working with HM-151. HM-133 DTMFs need work.
80 * added a DTMF activity timer for HM-151 so that the MIC is unmuted
81 * after an interval of no DTMF key being pressed.
82 * The "Fn LED" now depicts mic mute status during tone cycles. Off =
83 * muted (or macro digit pressed), ON = unmuted. Blink = up/dn pulse.
84 *
85 * *** REV 01 ***
86 * 08-03-19 jmh: project baselined at rev 01
87 * 07-20-19 jmh: Project origin, copied from Orion PLL
88 *
89 ***************************************************************************************/
90
91 /****************************************************************************************
92 * File scope revision history:
93 * 04-09-16 jmh: creation date
94 *
95 ***************************************************************************************/
96
97 //--------------------------------------------------------------------------------------
98 // main.c
99 //
100 // The following resources of the F531 are used:
101 // 24.500 MHz internal osc
102 //
103 // UART: n/u
104 //
105 // Timer0: n/u
106 // Timer1: DDS sample driver
107 // Timer2: Application timer (1ms/tic)
108 //
109 // ADC: n/u
110 //
111 // PCA:
112 // CEX0 = ICOM mic data decode ISR
113 // CEX1 = DDS PWM ISR
114 // CEX2 = Aux LED PWM out (Fixed PWM ratio, no ISR)
115 //
116 // SYSTEM NOTES:
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 3
117 //
118 // This project adapts an HM-133 (or HM-151) microphone so that it can produce DTMF signals.
119 // The PCB features the F531 MCU, a 3.3V regulator, open-drain drivers for up/dn and PTT, and
120 // switching circuits for the microphone/DTMF signals. The small form-factor board is intended
121 // to be an in-line module between the microphone and the transciever. Additional features
122 // such as up/down toggle commands are also possible allowing a specific number of pulses (up or
123 // dn) to be issued to the connected radio. DTMF memories are also possible using spare FLASH
124 // to hold the sequences.
125 //
126 // DTMF signals are generated using DDS code running the PCA CEX1 output in 8-bit PWM mode. If
127 // a keypress is recieved while the PTT is active (from either the PTT input discrete or the PTT
128 // keycode), the system will turn on the appropriate DTMF pair until the key is released, or PTT
129 // goes inactive. Since PCA can't do an 8-bit regular interrupt, Timer1 is used to drive the sample
130 // clock. Thus, the DDS ISR code lives inside Timer1, and updates the PWM register. Timer1 needs to
131 // run at the same rate as the PCA to preserve update alignment.
132 //
133 // The DDS is currently being driven at FSAMP = 23,925 Hz to ease the filtering requirements. This
134 // increases the Fstep to 0.365Hz, but this is still well below the worst-case 10.4Hz ETSI requirement
135 // for DTMF.
136 //
137 // PCA CEX2 is used to drive an "AUX" LED on the HM-133 (typically blue, and is user installed near
138 // the u/d buttons on the HM-133/151). It is a fixed PWM output to provide a fine adjustment to the
139 // LED brightness. LED on/off/brightness can be used to convey status (power on, DTMF output, PGM
140 // mode enabled, etc...).
141 //
142 // The software also interprets HM-133 key codes to drive the PTT and U/D open-drain discretes.
143 // U/D also features a tiered pulse ramp whereby the initial keypress sends one pulse, then after
144 // 1 second of holding, the system begins pulsing at 5 Hz. After 3 seconds of keypress, the
145 // system begins pulsing at 10 Hz. Pulsing stops imeediately upon release of the key.
146 //
147 //--------------------------------------------------------------------------------------
148
149 //-----------------------------------------------------------------------------
150 // Includes
151 //-----------------------------------------------------------------------------
152 // compile defines
153 #include "init.h"
154 #include "typedef.h"
155 #include "c8051F520.h"
156
157 //-----------------------------------------------------------------------------
158 // Definitions
159 //-----------------------------------------------------------------------------
160
161
162 #define VERS 2 // PCB vers 2 uses 4094 port expander, else VERS = 1
163
164 //#define IS_SIM // enable this define if using simulator
165
166 // see init.h for #defines
167
168
169 //-----------------------------------------------------------------------------
170 // External Variables
171 //-----------------------------------------------------------------------------
172
173 extern code const U8 SINE[];
174 volatile U16 hmd_timer; // HM151 data idle timeout timer
175
176 //-----------------------------------------------------------------------------
177 // Main Variables
178 //-----------------------------------------------------------------------------
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 4
179
180 // port assignments
181
182 // PCB version 1 bit defines
183 #if VERS == 1
sbit MDATA = P1^7; // (i) mic data in
sbit MMUTE_N = P1^6; // (o) mic mute out (act low)
sbit PTTb = P1^5; // (o) PTT out to rig (act hi)
sbit DNb = P1^4; // (o) mic DN button out to rig (act hi)
sbit UPb = P1^3; // (o) mic UP button out to rig (act hi)
sbit PTTM_N = P1^1; // (i) mic PTT in (act low)
sbit DMUTE = P1^0; // (o) rig data mute out (act hi)
#endif
192 // PCB version 2 bbSPI defines
193 #if VERS == 2
194 sbit MDATA = P1^7; // (a) comparator (-) input (mic serial data)
195 sbit STB = P1^6; // (o) port expander serial strobe
196 sbit MIC_DET_N = P1^5; // (i) HM133 mic present detect
197 sbit SCLK = P1^4; // (o) port expander bbSPI SCLK
198 sbit MOSI = P1^3; // (o) port expander bbSPI MOSI
199 sbit CMP_IN = P1^2; // (a) comparator (+) input (VREF with hysteresis)
200 sbit PTTM_N = P1^1; // (i) mic PTT in (act low)
201 sbit DMUTE = P1^0; // (o) rig data mute out (act hi)
202 sbit Ro2 = P1^0; // (o) strap option 2 (bit 1)
203
204 sbit LED_PWM = P0^7; // (o) PWM out for LED
205 sbit Ro3 = P0^6; // (o) strap option 3 (bit 2)
206 sbit MMUTE_N = P0^5; // (o) mic mute out (act low)
207 sbit Ro1 = P0^5; // (o) strap option 1 (bit 0)
208 sbit SPR = P0^4; // (i) SW option bit input
209 sbit PWMDAC = P0^3; // (o) DDS PWMDAC output
210 sbit MDATA_IN = P0^2; // (i) limited serial data input (connected to comparator out)
211 sbit CMPOUT = P0^1; // (o) comparator putput
212 sbit VREF = P0^0; // (a) ext VREF in (NOT USED FOR GPIO IN THIS DESIGN)
213 #endif
214
215 //-----------------------------------------------------------------------------
216 // Local variables
217 //-----------------------------------------------------------------------------
218 #define HM_START 0x01
219 #define HM_ERROR 0x02
220 #define HM_BUFMAX 3 // HM-133/151 buffers and working regs
221 volatile U8 hm_hptr; // save ptr in case we overflow
222 volatile U8 hm_tptr; // HM-133/151 key buffer tail ptr
223 volatile U32 hm_buf[HM_BUFMAX];
224 volatile U8 hm_status_buf[HM_BUFMAX];
225 volatile U8 hm_ctptr; // capture buf tail ptr
226 volatile U8 hm_chptr; // capture buf head ptr
227 volatile U32 sys_error_flags; // system error flags
228 volatile char curr_key;
229
230 volatile U8 ipldds; // dds ISR init flag
231 volatile U16 delF1; // phase (tone) register for tone 1
232 volatile U16 delF2; // phase (tone) register for tone 2
233
234 volatile U16 hmkey_timer; // key timer
235 volatile U8 waittimer; // wait() function timer
236 volatile U8 dbounceHM_tmr;
237 volatile U8 iplTMR; // timer IPL init flag
238 volatile U16 press_timer; // key press timer and flag
239 volatile U8 press_flag; // key-press timeout flag
240 U8 pulse_delay; // pulse delay value
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 5
241 #define UD_PERIOD 10 // up/dn pulse period
242 volatile U8 ud_timer;
243 volatile U8 xport; // expansion port data register
244
245 // bbSPI registers
246 volatile U8 spdr;
247 volatile U8 spmask;
248
249 // HM133/151 ISR data decode vars
250 volatile U32 dmask; // data mask
251 volatile U32 hm_data; // data register
252 volatile U8 hm_status; // status register
253 volatile U16 last_edge; // last edge capture (sign extended to 32 bits)
254 volatile U8 bit_count; // count of # bits rcvd
255
256 // HM-133/151 code LUT arrays:
257 #define MAX_KEY 25 // # keys on HM-151
258 #define MAX_KEY_133 23 // # keys on HM-133
259
260 // HM-133: there are actually 25 keys, but two of them act as modifiers
261 // (func and dtmf) and do not send a key code. The keys have different
262 // labeling, but each key is in roughly the same position with the same
263 // code. However, many keys are labeled differently from the HM-151.
264 // HM-133 applications should use the following key map:
265 // Key code Function (key) HM-151 function (key)
266 // M F2 MR
267 // V F1 V/M
268 // X Band change XFC
269 // T MR (and MW with persistent press) TUNER/CALL
270 // L VFO SPCH/LOCK
271 // F n/a F1
272 // G n/a F2
273 //
274 // HM-133 function key return set. '%' and '!' are placekeepers to keep
275 // alignment with the key_addr[] array. These codes should never be sent
276 // by an HM-133. HM-151 doesn't have a FUNC mode, so it will never send
277 // any of these codes.
278 // !! These codes don't mean anything to the adapter, so they are included as comments
279 // for completeness. !!
280 /*code char fnkey_code[] = { 'p', 'o', 'n', 'k', 'm', 'l', 'j', '%',
281 '!', 'a', 'b', 'c', 'q', 'd', 'e', 'f',
282 'r', 'g', 'h', 'i', 's', '+', '`', '$',
283 't', '\0' };*/
284 // Normal mode keycodes for HM-151 and HM-133 (see above for HM-133 notes)
285 code char key_code[] = { 'L', 'T', 'X', '/', 'V', 'M', '\\', 'F',
286 'G', '1', '2', '3', 'A', '4', '5', '6',
287 'B', '7', '8', '9', 'C', '*', '0', '#',
288 'D', '\0' };
289
290 #define DTMF_OFFS (9) // offset to subtract from key_code index to become dtmf index
291 // this offset is dependent on the placement of keycodes in the
292 // "_code" tables above. SO...don't re-arrange the key_code[] table!
293
294 // DTMF tone lookup tables for row and column
295 code U16 dtmf_row[] = { ROW1_TONE, ROW1_TONE, ROW1_TONE, ROW1_TONE,
296 ROW2_TONE, ROW2_TONE, ROW2_TONE, ROW2_TONE,
297 ROW3_TONE, ROW3_TONE, ROW3_TONE, ROW3_TONE,
298 ROW4_TONE, ROW4_TONE, ROW4_TONE, ROW4_TONE,
299 };
300 code U16 dtmf_col[] = { COL1_TONE, COL2_TONE, COL3_TONE, COL4_TONE,
301 COL1_TONE, COL2_TONE, COL3_TONE, COL4_TONE,
302 COL1_TONE, COL2_TONE, COL3_TONE, COL4_TONE,
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 6
303 COL1_TONE, COL2_TONE, COL3_TONE, COL4_TONE,
304 };
305 // serial key codes less the func/dtmf/1stkey modifier nybble.
306 code U16 key_addr[] = {0x0b02,0x1302,0x2302,0x2202,0x0a02,0x1202,0x2002,0x1002,
307 0x0802,0x0b82,0x1382,0x2382,0x4382,0x0982,0x1182,0x2182,
308 0x4182,0x0a82,0x1282,0x2282,0x4282,0x0882,0x1082,0x2082,
309 0x4082,0x0000};
310
311 // The first index selects the radio type, the second index selects the button.
312 // The array return is written to the port expansion SR to select the desired Fn.
313 code U8 radio_fbtn[][7] = {
314 // HM133 button --> UP F1 VFO/LOCK DN MR/CALL BAND/OPT Pulse Delay
315 // | | | | | | |
316 { UP, UP1, UP2, DN, DN1, DN2, MS40}, // 0 generic (ICOM)
317 { UP, MH36_ACC, MH36_P1, DN, MH36_DMR, MH36_P2, MS100}, // 1 Yaesu MH36
318 { UP, UP1, UP2, DN, DN1, DN2, MS80}, // 2 generic (KW) <- placekeeper
-for new rig type
319 { UP, UP1, UP2, DN, DN1, DN2, MS100}, // 3 generic (ICOM/KW) <- placeke
-eper for new rig type
320 { UP, UP1, UP2, DN, DN1, DN2, MS125}, // 4 generic (ICOM/KW) <- placeke
-eper for new rig type
321 { UP, UP1, UP2, DN, DN1, DN2, MS125}, // 5 generic (ICOM/KW) <- placeke
-eper for new rig type
322 { UP, UP1, UP2, DN, DN1, DN2, MS125}, // 6 generic (ICOM/KW) <- placeke
-eper for new rig type
323 { 0, 0, 0, 0, 0, 0, 0} // 7 HM-151 (IC-7000) -- no up/dn
-or other outputs supported
324 }; // for this mic
325
326 //-----------------------------------------------------------------------------
327 // Local Prototypes
328 //-----------------------------------------------------------------------------
329
330 void process_hm(U8 flag);
331 void pulse(U8 discr, U8 pcount);
332 void outbit(U8 bitmap, U8 on);
333 void send8(U8 sdata);
334 U8 get_opt(void);
335 void wait(U8 wvalue);
336 U8 got_hmd(void);
337 S32 get_hmd(void);
338 char* get_hmcode(U32 keym);
339
340 //******************************************************************************
341 // main()
342 // The main function inits I/O and process I/O.
343 //
344 //******************************************************************************
345 void main(void) //using 0
346 {
347 1 volatile U8 i; // temp uchar
348 1 volatile U8 j;
349 1 U8 q; // DTMF-S temp
350 1 U8 t; // DTMF-S temp
351 1 U8 mdet_edge; // mic det edge reg
352 1 U8 new_events;
353 1 U8 dmute_mem; // reg to hold initial dmute status when "G" key detected
354 1 volatile char d; // temp char
355 1 char* dp; // pointer to key code array
356 1 #define MAX_ACCUM 99
357 1 volatile U8 accum; // u/d pulse-count accumulator
358 1 U32 si; // temp 32
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 7
359 1 static U8 hm_count; // hm key repeat counter
360 1 static U8 keyh_mem; // current key (used to determine 1st keypress)
361 1 static U8 keyh_edg; // 1st key edge
362 1 static U8 ptt_edge; // edge discrete
363 1 static U8 aflag; // accum repeat inhib flag
364 1 static U8 softptt; // soft ptt detected
365 1 volatile U8 swopt; // SW ipl strap options
366 1 volatile U8 run; // warm restart trigger
367 1
368 1 // start of main
369 1 while(1){ // outer loop is for soft-restart capability
370 2 PCA0MD = 0x00; // disable watchdog
371 2 EA = 0;
372 2 run = 1; // enable run
373 2 // init MCU system
374 2 Init_Device(); // init MCU
375 2 EA = 1;
376 2 xport = 0; // init expansion port
377 2 #if VERS == 1
// VERS 1 port init
PTTb = 0; // (o) PTT out to rig (act hi)
DNb = 0; // (o) mic DN button out to rig (act hi)
UPb = 0; // (o) mic UP button out to rig (act hi)
swopt = 0x0; // set version 1 SW strap
DMUTE = 0; // (o) rig data mute out (act hi)
#endif
385 2 #if VERS == 2
386 2 // VERS 2 port init
387 2 swopt = get_opt(); // fetch SW option straps
388 2 send8(xport);
389 2 P0MDOUT = 0xAE; // update GPIO config, post option read
390 2 P1MDOUT = 0x59;
391 2 DMUTE = 0;
392 2 #endif
393 2 swopt = swopt & 0x07; // isolate rig options
394 2 // swopt = STRAP_HM151; // force HM151 debug
395 2 pulse_delay = radio_fbtn[swopt][IDX_PLSDLY]; // fetch pulse delay
396 2 MDATA = 1; // (i) mic data in
397 2 MMUTE_N = UNMUTE_BIT; // (o) mic mute out (act low)
398 2 PTTM_N = 1; // (i) mic PTT in (act low)
399 2 DMUTE = 1; // (o) rig data mute out (act hi)
400 2 MIC_DET_N = 1; // (i) init mic det (act low)
401 2 // init module vars
402 2 iplTMR = TMRIPL; // timer IPL init flag
403 2 PCA0CPM1 &= 0xfe; // disable CCF1
404 2 dmask = 0x01; // reset data regs
405 2 hm_data = 0;
406 2 bit_count = 0;
407 2 hm_status = 0;
408 2 last_edge = 0;
409 2 press_flag = 0;
410 2 keyh_edg = 0;
411 2 delF1 = 0; // cler the DDS tone regs
412 2 delF2 = 0;
413 2 hmkey_timer = 0;
414 2 waittimer = 0;
415 2 dbounceHM_tmr = 0;
416 2 press_timer = 0;
417 2 press_flag = 0;
418 2 ud_timer = 0;
419 2 ipldds = 1; // ipl the DDS
420 2 // process IPL init
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 8
421 2 keyh_mem = KEY_NULL;
422 2 hm_count = 0;
423 2 ptt_edge = ~PTTM_N;
424 2 aflag = 0;
425 2 softptt = 0; // init soft PTT
426 2 mdet_edge = ~MIC_DET_N; // init mic det edge to trap on IPL
427 2
428 2 #ifndef IS_SIM // skip DDS wait for sim
429 2 while(ipldds); // wait for DDS to init
430 2 #endif
431 2
432 2 #ifdef IS_SIM // allows range-checking of big constants in simulator
delF1 = HMT_SYNC; // place constant expressions here for a quick check
delF1 = COL4_TONE;
#endif
436 2
437 2 if(swopt == STRAP_HM151){ // if HM151 FT mode...
438 3 DMUTE = 0; // pass-thru MDATA
439 3 PCA0CPM2 &= ~0x40; // fn led off (ECOM);
440 3 }else{
441 3 DMUTE = 1; // inhibit pass-thru
442 3 PCA0CPM2 |= 0x40; // fn led on (ECOM);
443 3 }
444 2 // main loop
445 2 while(run){ // inner-loop runs the main application
446 3 new_events = 0;
447 3 d = PTTM_N;
448 3 if(d != ptt_edge){ // process manual PTT input
449 4 ptt_edge = d;
450 4 if(d){ // PTT input is ground true
451 5 MMUTE_N = MUTE_BIT; // PTT released
452 5 outbit(PTT, 0);
453 5 delF1 = 0;
454 5 delF2 = 0;
455 5 if(swopt != STRAP_HM151){ // if NOT HM151 FT mode...
456 6 PCA0CPM2 |= 0x40; // fn led on (ECOM);
457 6 }else{
458 6 if(DMUTE){
459 7 PCA0CPM2 |= 0x40; // fn led on (ECOM);
460 7 }
461 6 }
462 5 // turn off PWMO ISR
463 5 PCA0CPM1 &= 0xfe;
464 5 }else{
465 5 outbit(PTT, 1); // PTT pressed
466 5 MMUTE_N = UNMUTE_BIT;
467 5 }
468 4 }
469 3 d = '\0';
470 3 if(got_hmd()){ // trap keys
471 4 new_events = KEYHM_CHNG;
472 4 dbounceHM_tmr = 150;
473 4 }
474 3 if(dbounceHM_tmr == 0){
475 4 if(keyh_mem != KEY_NULL){ // trap debounce timeouts
476 5 new_events |= KEYHM_CHNG;
477 5 }
478 4 }
479 3 if(delF1){
480 4 press_timer = MS1650; // reset DTMF timer anytime a tone is being generated
481 4 }
482 3 if(press_flag){ // keypress timeout, enable mic
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 9
483 4 press_flag = 0;
484 4 if(swopt != STRAP_HM151){ // if NOT HM151 FT mode...
485 5 PCA0CPM2 |= 0x40; // fn led back on (ECOM);
486 5 }else{
487 5 if(DMUTE){
488 6 PCA0CPM2 |= 0x40; // fn led back on (ECOM);
489 6 }
490 5 }
491 4 MMUTE_N = UNMUTE_BIT; // unmute mic
492 4 }
493 3 t = MIC_DET_N; // grab the GPIO
494 3 if(mdet_edge != t){ // take action if there has been a change
495 4 mdet_edge = t;
496 4 if(t){ // if mic removed, abort PTT and tones
497 5 outbit(PTT, 0);
498 5 if(run == 2){ // This is an interlock to prevent continuous restarts while the mic is disconn
-ected
499 6 run = 0; // restart
500 6 }else{
501 6 run = 2; // set first pass interlock
502 6 }
503 5 }
504 4 if(swopt == STRAP_HM151){ // if HM151 FT mode... update mirror
505 5 t = ~t & 0x01; // need to invert to account for NFET inversion
506 5 outbit(DN, t);
507 5 }
508 4 }
509 3 // this branch handles key-driven events
510 3 if(new_events & KEYHM_CHNG){ // process trapped events
511 4 if(!softptt){
512 5 if(dbounceHM_tmr == 0){ // process no-key from HM-133/151
513 6 keyh_edg = 0;
514 6 if(keyh_mem != KEY_NULL){
515 7 // release key
516 7 if(!delF1){
517 8 if(swopt != STRAP_HM151){
518 9 PCA0CPM2 |= 0x40; // led back on if no tone (ECOM);
519 9 }else{
520 9 if(DMUTE){
521 10 PCA0CPM2 |= 0x40; // led back on if no tone (ECOM);
522 10 }
523 9 }
524 8 }
525 7 aflag = 0; // release accum inhibit
526 7 i = keyh_mem | 0x80; // set release keypress
527 7 }
528 6 keyh_mem = KEY_NULL; // if no key, clear current key mem.
529 6 }
530 5 }
531 4 si = get_hmd(); // get hm-133/151 data word
532 4 dp = get_hmcode(si); // do key-code lookup, pointer is set to keycode array
533 4 d = *(dp + HM_IDX_CODE);
534 4
535 4 if(*(dp + HM_IDX_STAT) & HM_1STKEY){
536 5 if(keyh_edg == 0){
537 6 keyh_edg = 1;
538 6 }else{
539 6 *(dp + HM_IDX_STAT) &= ~HM_1STKEY; // only allow 1 1stkey in a row
540 6 }
541 5 }else{
542 5 keyh_edg = 0;
543 5 }
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 10
544 4
545 4 if(d != KEY_NULL){ // trap first press, and prevent false repeats
546 5 if(d == PTT_CODE){
547 6 i = d;
548 6 keyh_mem = KEY_NULL;
549 6 }else{
550 6 dbounceHM_tmr = 150; // reset loss-of-key detect timer
551 6 if(d && (d != keyh_mem)){ // if mic data is not null AND key mem is null:
552 7 keyh_mem = d; // save key to mem (first key)
553 7 i = d;
554 7 hm_count = HMKEY_HOLD_CNT; // set key-hold counter
555 7 }else{
556 7 if(hm_count != 0){ // processes key-hold counter (not used at the moment)
557 8 if(--hm_count == 0){
558 9 // Process key "HOLD"
559 9 if((keyh_mem == '/') || (keyh_mem == '\\')){
560 10 *(dp + HM_IDX_STAT) |= HM_1STKEY; // recycle key
561 10 i = keyh_mem;
562 10 }
563 9 hm_count = 2;
564 9 }
565 8 }
566 7 }
567 6 }
568 5 }else{
569 5 keyh_edg = 0; // save null to key mem if debounce == 0
570 5 }
571 4 if(swopt == STRAP_HM151){ // if HM151 FT mode...
572 5 if(i == ('G'|0x80)){
573 6 if(dmute_mem){
574 7 DMUTE = 0;
575 7 PCA0CPM2 &= ~0x40; // fn led off (ECOM);
576 7 dmute_mem = 0;
577 7 }
578 6 }
579 5 if(*(dp + HM_IDX_STAT) & HM_1STKEY){
580 6 if(i == 'G'){ // toggle DMUTE when HM151-F2 key encountered
581 7 dmute_mem = DMUTE; // remember initial state of DMUTE
582 7 if(!DMUTE){ // update Fn LED
583 8 DMUTE = 1;
584 8 PCA0CPM2 |= 0x40; // fn led on (ECOM);
585 8 }
586 7 }
587 6 }
588 5 if(!DMUTE){ // ignore keypresses if data is NOT muted
589 6 i = '\0';
590 6 }
591 5 }
592 4 if(i & 0x80){
593 5 delF1 = 0;
594 5 delF2 = 0;
595 5 }
596 4 // process DTMF keys if PTT == 1, or into accum if PTT == 0
597 4 if(((i>='0') && (i<='9')) || ((i>='A') && (i<='D')) || (i =='*') || (i == '#')){
598 5 t = 1;
599 5 }else{
600 5 t = 0;
601 5 }
602 4 j = *(dp + HM_IDX_STAT) & HM_1STKEY;
603 4 if(*(dp + HM_IDX_STAT) & (HM_PTT | HM_DTMF) == (HM_PTT | HM_DTMF) && !t){
604 5 // DTMF-S PTT hold
605 5 q = 1;
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 11
606 5 delF1 = 0;
607 5 delF2 = 0;
608 5 }
609 4 /* if(((*(dp + HM_IDX_STAT) & HM_PTT) == HM_PTT) && q){
610 4 // DTMF-S release
611 4 q = 0;
612 4 MMUTE_N = UNMUTE_BIT; // (o) mic unmute out (act low)
613 4 }*/
614 4 if(t){
615 5 if(*(dp + HM_IDX_STAT) & HM_DTMF){
616 6 press_timer = MS1650; // reset DTMF timer
617 6 }
618 5 if(*(dp + HM_IDX_STAT) & HM_PTT){
619 6 outbit(PTT, 1);
620 6 }
621 5 if(xport & PTT){
622 6 if(j){
623 7 PCA0CPM2 &= ~0x40; // fn led off if dtmf (ECOM);
624 7 MMUTE_N = MUTE_BIT; // (o) mic mute out (act low)
625 7 delF1 = dtmf_row[*(dp+HM_IDX_DTMF)];
626 7 delF2 = dtmf_col[*(dp+HM_IDX_DTMF)];
627 7 }
628 6 }else{
629 6 if((i >= '0') && (i <= '9')){ // enter numbers into accumulator
630 7 if(swopt != STRAP_HM151){ // only if NOT in HM151 FT mode...
631 8 PCA0CPM2 &= ~0x40; //ECOM;
632 8 if(!aflag){
633 9 aflag = 1; // inhibit repeats
634 9 j = i - '0';
635 9 accum *= 10;
636 9 accum += j;
637 9 if(accum > MAX_ACCUM){
638 10 accum = j;
639 10 }
640 9 }
641 8 }
642 7 }else{
643 7 accum = 0; // non-numbers in DTMF space clear accum
644 7 if(i == '*'){
645 8 PCA0CPH2 = LED_DIM; // set dim LED
646 8 PCA0CPL2 = 0;
647 8 }
648 7 if(i == '#'){
649 8 PCA0CPH2 = LED_BRT; // set brt LED
650 8 PCA0CPL2 = 0;
651 8 }
652 7 }
653 6 }
654 5 }else{
655 5 if(swopt == STRAP_HM151){ // if HM151 FT mode...
656 6 if(i != 'M'){ // at this point, only "M" key is allowed in HM151 mode (other allowed keys hav
-e already been processed)
657 7 i = '\0'; // ...all others are ignored
658 7 }
659 6 }
660 5 switch(i){
661 6 case '/': // up key
662 6 if(*(dp + HM_IDX_STAT) & HM_1STKEY){
663 7 pulse(radio_fbtn[swopt][IDX_UP], accum);
664 7 accum = 0;
665 7 }
666 6 break;
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 12
667 6
668 6 case '\\': // down key
669 6 if(*(dp + HM_IDX_STAT) & HM_1STKEY){
670 7 pulse(radio_fbtn[swopt][IDX_DN], accum);
671 7 accum = 0;
672 7 }
673 6 break;
674 6
675 6 case PTT_CODE:
676 6 if(*(dp + HM_IDX_STAT) & HM_PTT){ // is PTT pressed keycode
677 7 if(*(dp + HM_IDX_STAT) & HM_DTMF){ // if DTMF active, time to turn off tones if we see this code
678 8 MMUTE_N = MUTE_BIT; // stay muted...
679 8 delF1 = 0;
680 8 delF2 = 0;
681 8 }else{
682 8 if(!press_timer){
683 9 MMUTE_N = UNMUTE_BIT; // unmute mic
684 9 }
685 8 }
686 7 outbit(PTT, 1); // activate PTT out
687 7 softptt = 1; // set soft PTT active
688 7 }else{
689 7 MMUTE_N = MUTE_BIT;
690 7 outbit(PTT, 0); // de-activate PTT out
691 7 delF1 = 0;
692 7 delF2 = 0;
693 7 if(swopt != STRAP_HM151){ // if NOT HM151 FT mode...
694 8 PCA0CPM2 |= 0x40; // fn led on (ECOM);
695 8 }else{
696 8 if(DMUTE){
697 9 PCA0CPM2 |= 0x40; // fn led on (ECOM);
698 9 }
699 8 }
700 7 softptt = 0; // set soft PTT inactive
701 7 }
702 6 break;
703 6
704 6 case 'L': // VFO/LOCK (HM151 = SPCH/LOCK)
705 6 if(*(dp + HM_IDX_STAT) & HM_1STKEY){
706 7 pulse(radio_fbtn[swopt][IDX_VFO], 1);
707 7 }
708 6 break;
709 6
710 6 case 'T': // MR/CALL (HM151 = TUNER/CALL)
711 6 if(*(dp + HM_IDX_STAT) & HM_1STKEY){
712 7 pulse(radio_fbtn[swopt][IDX_MR], 1);
713 7 }
714 6 break;
715 6
716 6 case 'X': // BND/OPT (HM151 = XFC)
717 6 // toggle DMUTE on v001 hardware
718 6 if(*(dp + HM_IDX_STAT) & HM_1STKEY){
719 7 pulse(radio_fbtn[swopt][IDX_BAND], 1);
720 7 }
721 6 break;
722 6
723 6 case 'V': // F1 (HM151 = V/M)
724 6 if(*(dp + HM_IDX_STAT) & HM_1STKEY){
725 7 pulse(radio_fbtn[swopt][IDX_F1], 1);
726 7 }
727 6 break;
728 6
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 13
729 6 case 'M': // Toggle test tone
730 6 if(*(dp + HM_IDX_STAT) & HM_1STKEY){
731 7 if(delF1){
732 8 MMUTE_N = UNMUTE_BIT; // (o) mic mute out (act low)
733 8 delF1 = 0;
734 8 delF2 = 0;
735 8 if(swopt != STRAP_HM151){ // if NOT HM151 FT mode...
736 9 PCA0CPM2 |= 0x40; // fn led on if no tone (ECOM);
737 9 }else{
738 9 if(DMUTE){
739 10 PCA0CPM2 |= 0x40; // fn led on if no tone (ECOM);
740 10 }
741 9 }
742 8 }else{
743 8 MMUTE_N = MUTE_BIT; // (o) mic mute out (act low)
744 8 delF1 = TONE_1000;
745 8 delF2 = 0;
746 8 PCA0CPM2 &= ~0x40; // fn led off if tone (ECOM);
747 8 }
748 7 }
749 6 break;
750 6
751 6 default:
752 6 i += 1;
753 6 break;
754 6 } // end key processing switch()
755 5 } // end "key processing" branch
756 4 } // end "new events"
757 3 } // end while(run)
758 2 } // end outer while()
759 1 } // end main()
760
761 // *********************************************
762 // *************** SUBROUTINES ***************
763 // *********************************************
764
765 //-----------------------------------------------------------------------------
766 // pulse() uses ms timer to pulse discretes pcount pulses
767 //-----------------------------------------------------------------------------
768
769 void pulse(U8 discr, U8 pcount){
770 1 U8 i; // temp vars
771 1 U8 j;
772 1
773 1 if(pcount == 0){
774 2 j = 1;
775 2 }else{
776 2 j = pcount;
777 2 press_timer = 100; // set some delay
778 2 do{
779 3 i = got_hmd();
780 3 if(i){
781 4 get_hmd(); // clear data word buffer
782 4 press_timer = 80;
783 4 }
784 3 }while(press_timer);
785 2 }
786 1 for(i=0; i<j; i++){
787 2 PCA0CPM2 &= ~0x40; // led dim (ECOM)
788 2 outbit(discr, 1);
789 2 ud_timer = pulse_delay;
790 2 while(ud_timer);
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 14
791 2 PCA0CPM2 |= 0x40; // led brt (ECOM)
792 2 outbit(discr, 0);
793 2 ud_timer = pulse_delay;
794 2 while(ud_timer);
795 2 if(got_hmd()){
796 3 i = j; // a keypress detected, abort
797 3 }
798 2 }
799 1 return;
800 1 }
801
802 //************************************************************************
803 // outbit() consolodates OC output port updates into a single function
804 //************************************************************************
805 void outbit(U8 bitmap, U8 on){
806 1 #if VERS == 1
// This is the version 1 routine. Only PTT, UP, DN, & F2 (MW) are supported
switch(bitmap){
case PTT:
if(on){
PTTb = 1;
xport |= bitmap;
}else{
PTTb = 0;
xport &= ~bitmap;
}
break;
case UP:
if(on) UPb = 1;
else UPb = 0;
break;
case DN:
if(on) DNb = 1;
else DNb = 0;
break;
case DN2:
if(on) DMUTE = 1;
else DMUTE = 0;
break;
default:
break;
}
#endif
838 1 #if VERS == 2
839 1 // This is the version 2 routine. PTT, UP, UP1, UP2, DN, DN1, & DN2 are supported
840 1
841 1 if(on){ // set/clear bitmap
842 2 xport |= bitmap;
843 2 }else{
844 2 xport &= ~bitmap;
845 2 }
846 1 send8(xport); // transfer to port expander
847 1 #endif
848 1 return;
849 1 }
850
851 #if VERS == 2
852 //************************************************************************
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 15
853 // send8() does a bit-bang SPI into a CD4094 to produce a port expansion
854 // output. Uses T0 to clock data
855 //************************************************************************
856 void send8(U8 sdata){
857 1
858 1 spmask = 0x80; // init mask
859 1 spdr = sdata; // store to bbSPI data reg
860 1 TR0 = 1;
861 1 while(TR0); // loop until xfr complete
862 1 STB = 1; // toggle strobe with delay
863 1 TR0 = 1;
864 1 while(TR0); // loop until xfr complete
865 1 STB = 0;
866 1 // since there will be several ms applied between send8 xfers, no further delay is needed
867 1 // but beware...this must be enforced by the programmer!!
868 1 return;
869 1 }
870
871 //************************************************************************
872 // get_opt() sets strap GPIOs for inputs (assumes they are already configured
873 // as OD outputs), reads the strap inputs, calculates the resulting option
874 // value, then returns that value to the caller.
875 //************************************************************************
876 U8 get_opt(void){
877 1 U8 rtn = 0;
878 1
879 1 Ro3 = 1; // set the option GPIOs for input
880 1 Ro2 = 1;
881 1 Ro1 = 1;
882 1 wait(50); // let the inputs settle
883 1 rtn = ((U8)Ro3 & 0x01) << 2; // collect the option inputs
884 1 rtn |= ((U8)Ro2 & 0x01) << 1;
885 1 rtn |= ((U8)Ro1 & 0x01);
886 1 rtn = ~rtn & 0x07; // convert to pos logic
887 1 return rtn;
888 1 }
889 #endif
890
891 //************************************************************************
892 // wait() waits the U8 value then returns.
893 //************************************************************************
894 void wait(U8 wvalue){
895 1
896 1 waittimer = wvalue; // set the timer
897 1 while(waittimer); // wait for it to expire
898 1 return;
899 1 }
900
901
902 // ******************* HM keypress capture ******************
903
904 //-----------------------------------------------------------------------------
905 // got_hmd() returns true if HM-133/151 data buffer not empty
906 //-----------------------------------------------------------------------------
907 U8 got_hmd(void){
908 1 U8 rtn = FALSE;
909 1
910 1 if(hm_tptr != hm_hptr){
911 2 rtn = TRUE;
912 2 }
913 1 return rtn;
914 1 }
C51 COMPILER V9.55 MAIN 08/28/2019 23:08:51 PAGE 16
915
916 //-----------------------------------------------------------------------------
917 // get_hmd() returns HM-133/151 data/status or -1 if no data
918 //-----------------------------------------------------------------------------
919 S32 get_hmd(void){
920 1 S32 rtn = -1L;
921 1
922 1 if(hm_tptr != hm_hptr){
923 2 rtn = (S32)(hm_buf[hm_tptr] & 0x00ffffff) | ((S32)hm_status_buf[hm_tptr] << 24);
924 2 if(++hm_tptr > (HM_BUFMAX-1)) hm_tptr = 0;
925 2 }
926 1 return rtn;
927 1 }
928
929 //-----------------------------------------------------------------------------
930 // get_hmcode() returns pointer to keycode array
931 // 1st index is key-data status
932 // 2nd index is keycode (KEY_NULL if invalid data)
933 // 3rd index is DTMF tone offset index
934 //-----------------------------------------------------------------------------
935 char* get_hmcode(U32 keym){
936 1 U16 ii; // temps
937 1 U8 i;
938 1 U8 di = 0; // dtmf index temp
939 1 static char hm_rtn[3]; // holding array for code and status data
940 1 // 0 = stat, 1 = code, 2 = DTMF idx
941 1
942 1 hm_rtn[HM_IDX_CODE] = KEY_NULL;
943 1 hm_rtn[HM_IDX_STAT] = (U8)keym & 0x0f; // get key status
944 1 ii = (U16)(keym >> 4); // conv hm151/133 keymatrix to keyaddr (low nyb is status)
945 1 if(ii == 0x0002){ // HM-133 PTT
946 2 hm_rtn[HM_IDX_CODE] = PTT_CODE; // semicolon is PTT
947 2 }else{
948 2 if(ii != 0xffff){
949 3 i = 0;
950 3 do{
951 4 if(ii == key_addr[i]){
952 5 hm_rtn[HM_IDX_CODE] = key_code[i]; // look for match in fn LUT