-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.c
More file actions
1613 lines (1530 loc) · 68.4 KB
/
main.c
File metadata and controls
1613 lines (1530 loc) · 68.4 KB
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
/******************************************************************************/
/* MatrixEncoderDecoder v1.03 */
/* main.c */
/* John Kinkennon */
/* 11/2/2013 */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License along */
/* with this program; if not, write to the Free Software Foundation, Inc., */
/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
/* */
/* John Kinkennon, 4307 NE 65th Ct, Vancouver, WA 98661 USA */
/* email: john@kinkennon.com */
/* */
/* This program uses Microchip USB software. Refer to the included header */
/* files for Microchip licensing restrictions. */
/******************************************************************************/
/******************************************************************************/
/* Files to Include */
/******************************************************************************/
#include <xc.h> /* Include to use PIC32 peripheral libraries */
#include <stdint.h> /* For uint32_t definition */
#include <stdbool.h> /* For true/false definition */
#include <plib.h>
#include "GenericTypeDefs.h"
#include "Compiler.h"
#include "user.h" /* User funct/params, such as InitApp */
#include "midi.h" /* MIDI definitions */
#include "HardwareProfile.h"/* Board LEDs, switches, etc. */
#include "i2c_jk.h" /* Comms to Centipede Shields */
#include "sysex.h" /* Types for System Exclusive messages */
#include "usb.h"
#include "USB/usb_function_midi.h"
#include "lcd.h"
/******************************************************************************/
/* Global Variable Declaration */
/******************************************************************************/
/*
* These types are defined in sysex.h and store System Exclusive MIDI messages.
* The framework exists in parseMidiMsg() to put these messages to further use.
*/
HW_Sysex_LCD_Msg_t LCD_Msg;
HW_Sysex_Status_String_t HW_Status_String;
HW_Sysex_Status_Float_t HW_Status_Float;
HW_Sysex_Status_Byte_t HW_Status_Byte;
/*
* NVM Tables -- The .user_nvm_data section it located in the program area of
* flash memory. It has been moved well past the end of the present code to
* allow for program growth without the need to constantly relocate this data.
*/
uint8_t nvmTable1[BYTE_PAGE_SIZE] \
__attribute__((space(prog), address(NVM_ADDRESS_PAGE), \
section(".user_nvm_data"))) = {[0 ...(BYTE_PAGE_SIZE) - 1] = 0xFF};
/*
* keyTable[key#] is a byte representing recent scans on that key (or switch).
* The top bit == 1 (0b10000000) indicates that the key is considered to be down
* (closed or ON). The lower three bits indicate status for recent scans.
* A key that is ON (0b10000111) might transition to OFF as follows:
* (0b10000110) on this scan key was no longer closed (key up)
* (0b10000100) 1ms later it is again open
* (0b00000000) 2ms and the third scan shows open as well (no key bounce) and
* the program considers the key open (up). Opposite on key down.
*/
uint8_t keyTable[NUM_SWITCHES]; // qty. N channels x 64 keys, current status
/*
* The inverted input value at each of (64 x N channels) input points. The
* normal key up voltage is 3.3v giving a value of 1 at the port. This value is
* inverted as it's easier to think of ON == 1 and OFF == 0.
* Press key #23 and keyBit[23] = 1.
*/
bool keyBit[NUM_SWITCHES];
/*
* The translation table handles up to 512 keys or switches.
*/
uint8_t translateTable[8][64][8]; // 8 kybd, 64 keys, 4 bytes per msg x2
/* The SAMs table maps each SAM to an organ division,
* Centipede Shield chip#, and bitOffset where:
* Division
* 0x00 = no assignment
* 0x01 = pedal division -- SP1 on the Allen power supply
* 0x02 = swell division -- SP2
* 0x03 = great division -- SP3
* 0x04 = coupler panel -- SP4 (use SP4, disconnect CP power)
* Division assignments correspond to the original physical and electrical
* connections in the Allen console and may not match a given virtual
* organ's usage. They indicate which power supply output powers that SAM.
* chip number (add CENT_CHIP_1 to get chipAddress, chips 0 to 3
* are four MCP23017's on the first Centipede Shield,
* chips 4 to 7 are on a second Centipede Shield)
* 0 to 7
* bitOffset (0 to 7 is A0 to A7 on the MCP23017 IC,
* 8 to 15 is B0 to B7 on the IC)
* 0 to 15
*/
uint8_t samsTable[80][3] = {
// Pedal division SAMs (11)
{1, 0, 0}, // Schalmei 4 3-1-A0
// {1, 0, 0} is the pedal division, first chip on first shield, first bit (A0)
// 3-1-A0 is for the 3rd Centipede Shield, first chip, bit A0
// It's the 3rd shield because the first is for piston inputs, the second for
// inputs from stops, and the third is for output (control) to stops
{1, 0, 1}, // Posuane 16 3-1-A1
{1, 0, 2}, // Choral Bass 4 3-1-A2
{1, 0, 3}, // Octave 8 3-1-A3
{1, 0, 4}, // Diapason 16 3-1-A4
{1, 0, 5}, // Contra Bourdon 32 3-1-A5
{1, 0, 6}, // Trompete 8 3-1-A6
{1, 0, 7}, // Mixtur III 3-1-A7
{1, 0, 8}, // Gedeckt Flote 8 3-1-B0
{1, 0, 9}, // Leiblich Gedeckt 16 3-1-B1
{1, 0, 10}, // Bourdon 16 3-1-B2
// Swell division SAMs (19)
{2, 0, 11}, // Clarion 4 3-1-B3
{2, 0, 12}, // Contra Fagotto 16 3-1-B4
{2, 0, 13}, // Cymbale III 3-1-B5
{2, 0, 14}, // Fourniture IV 3-1-B6
{2, 0, 15}, // Prinzipal Coneique 4 3-1-B7
{2, 1, 0}, // Gemshorn 8 3-2-A0
{2, 1, 1}, // Salizional 8 3-2-A1
{2, 1, 2}, // Celeste 3-2-A2
{2, 1, 3}, // Trompette 8 3-2-A3
{2, 1, 4}, // Sifflet 1 3-2-A4
{2, 1, 5}, // Flute a bec 2 3-2-A5
{2, 1, 6}, // Flute a fuseau 4 3-2-A6
{2, 1, 7}, // Flute Bouchee 8 3-2-A7
{2, 1, 8}, // Voix Celeste 3-2-B0
{2, 1, 9}, // Tremulant 3-2-B1
{2, 1, 10}, // Hautbois 8 3-2-B2
{2, 1, 11}, // Tierce 1 3/5 3-2-B3
{2, 1, 12}, // Nazard 2 2/3 3-2-B4
{2, 1, 13}, // Blank 3-2-B5
// Great division SAMs (16)
{3, 1, 14}, // Trompete 8 3-2-B6
{3, 1, 15}, // Super Octav 2 3-2-B7
{3, 2, 0}, // Octav 4 3-3-A0
{3, 2, 1}, // Prinzipal 8 3-3-A1
{3, 2, 2}, // Gemshorn 16 3-3-A2
{3, 2, 3}, // Mixtur IV 3-3-A3
{3, 2, 4}, // Waldflote 2 3-3-A4
{3, 2, 5}, // Gamba 8 3-3-A5
{3, 2, 6}, // Flute Dolce II 3-3-A6
{3, 2, 7}, // Chiff 3-3-A7
// These choir SAMs are on the Great power supply section (3)
{3, 2, 8}, // Tremulant 3-3-B0
{3, 2, 9}, // Quinte 1 1/3 3-3-B1
{3, 2, 10}, // Spitzflote 4 3-3-B2
{3, 2, 11}, // Hohlflote 8 3-3-B3
{3, 2, 12}, // Celest tuning 3-3-B4
{3, 2, 13}, // Blank 3-3-B5
// One spare
{0, 2, 14}, // spare 3-3-B6
// 17 couplers here (SAMs)
{2, 2, 15}, // Group 1, Coupler 1 3-3-B7
{2, 3, 0}, // Group 1, Coupler 2 3-4-A0
{2, 3, 1}, // Group 1, Coupler 3 3-4-A1
{2, 3, 2}, // Group 1, Coupler 4 3-4-A2
{2, 3, 3}, // Group 1, Coupler 5 3-4-A3
{2, 3, 4}, // Group 1, Coupler 6 3-4-A4
{2, 3, 5}, // Group 1, Coupler 7 3-4-A5
{1, 3, 6}, // Group 2, Coupler 1 3-4-A6
{1, 3, 7}, // Group 2, Coupler 2 3-4-A7
{1, 3, 8}, // Group 2, Coupler 3 3-4-B0
{1, 3, 9}, // Group 2, Coupler 4 3-4-B1
{3, 3, 10}, // Group 2, Coupler 5 3-4-B2
{4, 3, 11}, // Group 3, Coupler 1 3-4-B3
{4, 3, 12}, // Group 3, Coupler 2 3-4-B4
{4, 3, 13}, // Group 3, Coupler 3 3-4-B5
{4, 3, 14}, // Group 3, Coupler 4 3-4-B6
{4, 3, 15}, // Group 3, Coupler 5 3-4-B7
// the 4th Centipede Shield is not present for the Allen 4100
{0, 4, 0}, // blank
{0, 4, 1}, // blank
{0, 4, 2}, // blank
{0, 4, 3}, // blank
{0, 4, 4}, // blank
{0, 4, 5}, // blank
{0, 4, 6}, // blank
{0, 4, 7}, // blank
{0, 4, 8}, // blank
{0, 4, 9}, // blank
{0, 4, 10}, // blank
{0, 4, 11}, // blank
{0, 4, 12}, // blank
{0, 4, 13}, // blank
{0, 4, 14}, // blank
{0, 4, 15} // blank
};
uint8_t ReceivedDataBuffer[SIZEOF_RX_BUF]; // data from USB
uint8_t midiRxMsg[SIZEOF_MSG_BUF]; // big enough to handle typical Sysex buffer
int rx = 0;
int mx = 0; // midiMsg index, not local to parseMidiMsg()
// as a message may not be complete
uint8_t midiTxMsg[SIZEOF_TX_BUF];
USB_AUDIO_MIDI_EVENT_PACKET midiData;
USB_HANDLE USBTxHandle = 0;
USB_HANDLE USBRxHandle = 0;
uint32_t i2cActualClock1;
uint32_t i2cActualClock2;
// the following arrays are 2 x 8 where there are two I2C buses with 8 ICs each
uint16_t i2cRxData[2][8]; // input data from pistons and stops
UINT16_VAL i2cTxData[2][8]; // output data to SAMs
bool i2cChipIsOutput[2][8]; // 2 buses x 8 chip each
uint8_t chipAddress = CENT_CHIP_1;
volatile uint32_t *adcBufferPtr[8] = { &ADC1BUF0, &ADC1BUF1, &ADC1BUF2,
&ADC1BUF3, &ADC1BUF4, &ADC1BUF5, &ADC1BUF6, &ADC1BUF7 };
uint32_t stalePot[16] = { 0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0 }; // previous potentiometer values
uint32_t freshPot[16] = { 0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0 }; // current potentiometer values
uint8_t keyScanCount = 0; // count reset every 32 kybd scans
bool potScanTime = false; // set by ADC interrupt
bool keyScanTime = false; // set by timer2 interrupt
bool setSAMsTime = false; // set 50ms after last stop change
bool pedalSAMsPending = false; // a stop has changed in the pedal division
bool swellSAMsPending = false; // a stop change on swell
bool greatSAMsPending = false; // a stop change on great
bool cpSAMsPending = false; // cp is coupler panel (rocker tablets)
bool SAMsPowerOn = false; // flag set when any SAMs power is active
uint8_t msgFinishedLen = 0; // set to length of MIDI msg
uint8_t msgType = 0;
uint8_t msgChannel = 0;
int8_t transposeHW = 0;
int8_t transposeSW = 0;
/******************************************************************************/
/* Main Program */
/******************************************************************************/
int32_t main(void) {
#ifndef PIC32_STARTER_KIT
/*The JTAG is on by default on POR. A PIC32 Starter Kit uses the JTAG, but
for other debug tool use, like ICD 3 and Real ICE, the JTAG should be off
to free up the JTAG I/O */
DDPCONbits.JTAGEN = 0;
#endif
/*Refer to the C32 peripheral library compiled help file for more
information on the SYTEMConfig function.
This function sets the PB divider, the Flash Wait States, and the DRM
/wait states to the optimum value. It also enables the cacheability for
the K0 segment. It could has side effects of possibly alter the pre-fetch
buffer and cache. It sets the RAM wait states to 0. Other than
the SYS_FREQ, this takes these parameters. The top 3 may be '|'ed
together:
SYS_CFG_WAIT_STATES (configures flash wait states from system clock)
SYS_CFG_PB_BUS (configures the PB bus from the system clock)
SYS_CFG_PCACHE (configures the pCache if used)
SYS_CFG_ALL (configures the flash wait states, PB bus, and pCache)*/
SYSTEMConfigPerformance(80000000L);
//SYSTEMConfig(PB_BUS_MAX_FREQ_HZ, SYS_CFG_ALL);
/* Initialize I/O and Peripherals for application */
InitApp();
InitializeSystem(); // the Microchip USB initialization
/*Configure Multivector Interrupt Mode. Using Single Vector Mode
is expensive from a timing perspective, so most applications
should probably not use a Single Vector Mode*/
INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR);
USBDeviceAttach(); // connect to host computer
if(USBDeviceState == ATTACHED_STATE)
resetTimer2(); // start scanning timer;
#ifdef USE_LCD
putsLCD("Kinkennon");
putsLCD("\n");
putsLCD("MIDI Encoder");
#endif
while(1)
{
ProcessIO();
}
}
/*
* parseMidiMsg() needs to process up to 64 bytes from ReceivedDataBuffer[]
* and assemble them into midiMsg[]. SysEx msgs are processed up to 64
* bytes and do not span two reads of the RxBuffer at this time.
* TODO: rewrite entire parseMidiMsg()...
*/
void parseMidiMsg(void) {
rx = 0; // receive buffer index
int i;
unsigned char tempData;
while (ReceivedDataBuffer[rx]) {
tempData = ReceivedDataBuffer[rx++];
switch (tempData) {
case MIDI_CIN_NOTE_OFF:
for (i = 0; i < 3; i++) {
midiRxMsg[mx++] = ReceivedDataBuffer[rx++];
}
msgType = midiRxMsg[0] & 0xf0;
msgChannel = midiRxMsg[0] & 0x0f;
msgFinishedLen = 3;
break;
case MIDI_CIN_NOTE_ON:
for (i = 0; i < 3; i++) {
midiRxMsg[mx++] = ReceivedDataBuffer[rx++];
}
msgType = midiRxMsg[0] & 0xf0;
msgChannel = midiRxMsg[0] & 0x0f;
msgFinishedLen = 3;
break;
case MIDI_CIN_POLY_KEY_PRESS:
case MIDI_CIN_CONTROL_CHANGE:
case MIDI_CIN_PITCH_BEND_CHANGE:
case MIDI_CIN_SSP:
for (i = 0; i < 3; i++) {
midiRxMsg[mx++] = ReceivedDataBuffer[rx++];
}
msgType = midiRxMsg[0] & 0xf0;
msgChannel = midiRxMsg[0] & 0x0f;
msgFinishedLen = 3;
break;
case MIDI_CIN_PROGRAM_CHANGE:
//case MIDI_CIN_CHANNEL_PRESSURE:
case MIDI_CIN_SONG_SELECT:
//case MIDI_CIN_MTC:
for (i = 0; i < 2; i++) {
midiRxMsg[mx++] = ReceivedDataBuffer[rx++];
}
msgType = midiRxMsg[0] & 0xf0;
msgChannel = midiRxMsg[0] & 0x0f;
msgFinishedLen = 2;
break;
case MIDI_CIN_SINGLE_BYTE:
// Real Time msg
// don't step on msgType, msgChannel, midiMsg[]
// advance rx to skip past this byte
rx++;
break;
case MIDI_CIN_SYSEX_START:
//case MIDI_CIN_SYSEX_CONTINUE:
for (i = 0; i < 3; i++) {
midiRxMsg[mx++] = ReceivedDataBuffer[rx++];
}
break;
case MIDI_CIN_SYSEX_ENDS_3:
midiRxMsg[mx++] = ReceivedDataBuffer[rx++];
// no break; fall through
case MIDI_CIN_SYSEX_ENDS_2:
midiRxMsg[mx++] = ReceivedDataBuffer[rx++];
// no break; fall through
case MIDI_CIN_SYSEX_ENDS_1:
midiRxMsg[mx++] = ReceivedDataBuffer[rx++];
if (ReceivedDataBuffer[rx - 1] == M_END_EXCLUSIVE) {
msgType = M_SYSTEM_EX;
msgFinishedLen = mx;
}
break;
default:
eraseMidiRxMsg(); // if not handled dump it
}
// if we have a complete message (all bytes received)
if ((msgFinishedLen > 0) && (mx == msgFinishedLen)) { // complete msg
if ((msgType == M_NOTE_ON) || (msgType == M_NOTE_OFF)) {
if (msgChannel == 5) {
// handle a stop action magnet (SAM)
int stop = midiRxMsg[1] - 0x24;
if (stop > 80) break; // sanity check
switch (samsTable[stop][0]) {
case 0:
break;
case 1:
pedalSAMsPending = true;
break;
case 2:
swellSAMsPending = true;
break;
case 3:
greatSAMsPending = true;
break;
case 4:
cpSAMsPending = true;
break;
}
uint8_t j = samsTable[stop][1];
uint8_t chipAddress = j + CENT_CHIP_1;
uint8_t bitOffset = samsTable[stop][2];
#ifdef USE_I2C
if (msgType == M_NOTE_ON)
i2cTxData[1][j].Val &= ~(1 << bitOffset); // clear bit
if (msgType == M_NOTE_OFF)
i2cTxData[1][j].Val |= 1 << bitOffset; // set bit
// Only send when HW status is Organ Ready
if (LATCbits.LATC2 == 0) {
putCentipedeBytes(CENTIPEDE_I2C_BUS2, chipAddress,
i2cTxData[1][j]);
resetTimer3(); // Timer 3 will make setSAMsTime = true
}
#endif
}
}
if ((msgType == M_SYSTEM_EX) && (midiRxMsg[1] == M_SYSEX_ID)) {
switch (msgFinishedLen) {
case 39: // handle Hauptwerk LCD message
for (i = 0; i < 39; i++)
LCD_Msg.v[i] = midiRxMsg[i];
if (LCD_Msg.s1.message_type != MSG_TYPE_LCD) break;
#ifdef USE_LCD
homeLCD();
delayTimer1(30); // Increase if first character is dropped
putsLCD(LCD_Msg.s3.ascii_line1 + '\0');
putsLCD("\n");
putsLCD(LCD_Msg.s3.ascii_line2 + '\0');
#endif
break;
case 22: // change to translation for one key
if (midiRxMsg[2] != 0x70) break; // msg type/length mis-match
int j = midiRxMsg[3]; // keybd
int k = midiRxMsg[4]; // key
if (k < NUM_SWITCHES) {
translateTable[j][k][0] = (midiRxMsg[5] << 4) | midiRxMsg[6];
translateTable[j][k][1] = (midiRxMsg[7] << 4) | midiRxMsg[8];
translateTable[j][k][2] = (midiRxMsg[9] << 4) | midiRxMsg[10];
translateTable[j][k][3] = (midiRxMsg[11] << 4) | midiRxMsg[12];
translateTable[j][k][4] = (midiRxMsg[13] << 4) | midiRxMsg[14];
translateTable[j][k][5] = (midiRxMsg[15] << 4) | midiRxMsg[16];
translateTable[j][k][6] = (midiRxMsg[17] << 4) | midiRxMsg[18];
translateTable[j][k][7] = (midiRxMsg[19] << 4) | midiRxMsg[20];
}
break;
case 21: // handle Hauptwerk Status, string variable
for (i = 0; i < 21; i++)
HW_Status_String.v[i] = midiRxMsg[i]; // copy msg to structure
if (HW_Status_String.s1.message_type != MSG_TYPE_STATUS_STRING) break;
// TODO: handle message
break;
case 9: // handle Hauptwerk Status, float variable
for (i = 0; i < 9; i++)
HW_Status_Float.v[i] = midiRxMsg[i]; // copy msg to structure
if (HW_Status_Float.s1.message_type != MSG_TYPE_STATUS_FLOAT) break;
switch (HW_Status_Float.s1.variable_ID) {
uint8_t temp;
case TRANSPOSER_SEMITONES:
temp = HW_Status_Float.s1.float_4;
if (temp & 0x40)
temp |= 0x80; // if 0bx1xxxxxx, 0b11xxxxxx
transposeHW = (int8_t)temp;
if (transposeSW > transposeHW) {
midiTxMsg[0] = translateTable[7][0x3d][0];
midiTxMsg[1] = translateTable[7][0x3d][1];
midiTxMsg[2] = translateTable[7][0x3d][2];
sendMidiMsg();
}
if (transposeHW > transposeSW) {
midiTxMsg[0] = translateTable[7][0x3e][0];
midiTxMsg[1] = translateTable[7][0x3e][1];
midiTxMsg[2] = translateTable[7][0x3e][2];
sendMidiMsg();
}
if (transposeSW == 0) {
LATCbits.LATC1 = 1; // RC1 - First LED - Red (transpose)
} else {
LATCbits.LATC1 = 0;
}
break;
}
break;
case 7: // load table from flash mem, or write one table
if (midiRxMsg[2] != 0x72) break; // msg type/length mis-match
if (midiRxMsg[3] == 0) { // 0 is load
getNvmTable();
} else if (midiRxMsg[3] == 1) { // 1 is write
putNvmTable();
}
break;
case 6: // handle Hauptwerk Status, boolean variables
for (i = 0; i < 6; i++)
HW_Status_Byte.v[i] = midiRxMsg[i]; // copy msg to structure
if (HW_Status_Byte.s.message_type != MSG_TYPE_STATUS_BOOLEAN) break;
switch (HW_Status_Byte.s.variable_ID) {
case IS_SETTER_MODE_ON:
if (HW_Status_Byte.s.byte_value)
LATGbits.LATG6 = 0; // RG6 - 5th LED - Red
else if (HW_Status_Byte.s.byte_value == 0)
LATGbits.LATG6 = 1; // turn off Indicator
break;
case IS_SCOPE_MODE_ON:
if (HW_Status_Byte.s.byte_value)
LATGbits.LATG6 = 0; // RG6 - 5th LED - Red
else if (HW_Status_Byte.s.byte_value == 0)
LATGbits.LATG6 = 1; // turn off Indicator
break;
case IS_RECORDING_AUDIO:
if (HW_Status_Byte.s.byte_value)
LATCbits.LATC3 = 0; // RC3 - 2nd Grn - Audio Recording
else if (HW_Status_Byte.s.byte_value == 0)
LATCbits.LATC3 = 1; // turn off Recording Indicator
break;
case IS_RECORDING_MIDI:
if (HW_Status_Byte.s.byte_value)
LATCbits.LATC3 = 0; // RC3 - 2nd Grn - MIDI Recording
else if (HW_Status_Byte.s.byte_value == 0)
LATCbits.LATC3 = 1; // turn off Recording Indicator
break;
case IS_PLAYING_MIDI:
if (HW_Status_Byte.s.byte_value)
LATCbits.LATC4 = 0; // RC4 - 3rd Grn - Red (transpose)
else if (HW_Status_Byte.s.byte_value == 0)
LATCbits.LATC4 = 1; // turn off MIDI Indicator
break;
case IS_ORGAN_READY:
if (HW_Status_Byte.s.byte_value) {
LATCbits.LATC2 = 0; // RC2 - Second LED - Audio Active
//initI2C(); // White (power)
//resetTimer2(); // start scanning
for (i=0; i<16; i++) {
stalePot[i] = 0;
}
}
else if (HW_Status_Byte.s.byte_value == 0) {
//T2CONbits.ON = 0; // stop scanning
LATCbits.LATC2 = 1; // turn off Audio Active
}
break;
case IS_IN_ERROR_STATE:
if (HW_Status_Byte.s.byte_value)
LATGbits.LATG7 = 0; // RG7 - 6th LED - Red - Error
else if (HW_Status_Byte.s.byte_value == 0)
LATGbits.LATG7 = 1; // turn off Error
break;
}
} // end of handled sysex messages
} // end of complete sysex msg
eraseMidiRxMsg();
} // end of complete msg
if (rx > SIZEOF_RX_BUF) eraseRxBuffer();
} // end of going through RxBuffer
eraseMidiRxMsg();
eraseRxBuffer();
}
void initNVM(void) {
initTranslateTable();
if (nvmTable1[0] == 0xFF) // if first flash table is uninitialized
putNvmTable(); // then init to defaults
getNvmTable(); // always retrieve saved translate table
}
void putNvmTable(void) {
unsigned int pageBuffer[PAGE_SIZE]; // temp storage for NVM functions
unsigned int flashAddress = NVM_PROGRAM_PAGE; // 0xbd010000+
NVMErasePage((void *) flashAddress);
NVMProgram((void *) flashAddress, (const void *) translateTable,
sizeof (translateTable), (void *) pageBuffer);
}
void getNvmTable(void) {
unsigned int flashAddress = NVM_PROGRAM_PAGE;
memcpy((void *) translateTable, (const void *) flashAddress, sizeof (translateTable));
}
void getNvmTableRow(int tableRow) {
unsigned int flashAddress = NVM_PROGRAM_PAGE + 0x200 * tableRow;
void * dest = &translateTable[tableRow];
memcpy((void *) dest, (const void *) flashAddress, 0x200);
}
void initI2C(void) {
int i, j;
for (i = 0; i < 2; i++) {
for (j = 0; j < 8; j++) {
i2cRxData[i][j] = 0xffff;
i2cTxData[i][j].Val = 0xffff;
}
}
// Set true if an i2c chip is used for output
i2cChipIsOutput[0][0] = false; // Pistons In
i2cChipIsOutput[0][1] = false;
i2cChipIsOutput[0][2] = false;
i2cChipIsOutput[0][3] = false;
i2cChipIsOutput[0][4] = false; // Stops In
i2cChipIsOutput[0][5] = false;
i2cChipIsOutput[0][6] = false;
i2cChipIsOutput[0][7] = false;
i2cChipIsOutput[1][0] = true; // Stops Out
i2cChipIsOutput[1][1] = true;
i2cChipIsOutput[1][2] = true;
i2cChipIsOutput[1][3] = true;
i2cChipIsOutput[1][4] = true; // Couplers In
i2cChipIsOutput[1][5] = true; // Couplers Out
i2cChipIsOutput[1][6] = true;
i2cChipIsOutput[1][7] = true;
// Set the I2C baudrate
i2cActualClock1 = I2CSetFrequency(CENTIPEDE_I2C_BUS1, GetPeripheralClock(), I2C_CLOCK_FREQ);
i2cActualClock2 = I2CSetFrequency(CENTIPEDE_I2C_BUS2, GetPeripheralClock(), I2C_CLOCK_FREQ);
// Enable the I2C1 bus
I2CConfigure(CENTIPEDE_I2C_BUS1, I2C_ENABLE_HIGH_SPEED);
I2CEnable(CENTIPEDE_I2C_BUS1, true);
// Enable the I2C2 bus
I2CConfigure(CENTIPEDE_I2C_BUS2, I2C_ENABLE_HIGH_SPEED);
I2CEnable(CENTIPEDE_I2C_BUS2, true);
// TODO: fix DUAL and SINGLE to reflect actual system configuration
chipAddress = CENT_CHIP_1;
for (i = 0; i < DUAL_CENT_NUM_CHIPS; i++) {
initCentipedeChip(CENTIPEDE_I2C_BUS1, chipAddress++, i2cChipIsOutput[0][i]);
}
chipAddress = CENT_CHIP_1;
for (i = 0; i < SINGLE_CENT_NUM_CHIPS; i++) {
initCentipedeChip(CENTIPEDE_I2C_BUS2, chipAddress++, i2cChipIsOutput[1][i]);
}
chipAddress = CENT_CHIP_1;
for (i = 0; i < SINGLE_CENT_NUM_CHIPS; i++) {
if (i2cChipIsOutput[1][i]) {
putCentipedeBytes(CENTIPEDE_I2C_BUS2, chipAddress, i2cTxData[1][i]);
}
chipAddress++;
}
}
void getTwelveBits(int matrixColumn) {
int i = 0;
switch (matrixColumn) {
case 0:
keyBit[0] = (PORTCbits.RC14) ? 0 : 1;
keyBit[64] = (PORTDbits.RD13) ? 0 : 1;
break;
case 11:
keyBit[128] = (PORTCbits.RC14) ? 0 : 1;
keyBit[192] = (PORTDbits.RD13) ? 0 : 1;
break;
default:
i = ((matrixColumn % 11) * 6) + ((matrixColumn / 11) * 128) - 5;
keyBit[i++] = (PORTDbits.RD0) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD1) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD2) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD3) ? 0 : 1;
keyBit[i++] = (PORTCbits.RC13) ? 0 : 1;
keyBit[i++] = (PORTCbits.RC14) ? 0 : 1;
i += 58;
keyBit[i++] = (PORTDbits.RD8) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD9) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD10) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD11) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD12) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD13) ? 0 : 1;
}
}
void getSixteenBits(int matrixColumn) {
int i;
i = ((matrixColumn % 8) * 8) + ((matrixColumn / 8) * 128);
keyBit[i++] = (PORTDbits.RD0) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD1) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD2) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD3) ? 0 : 1;
keyBit[i++] = (PORTCbits.RC13) ? 0 : 1;
keyBit[i++] = (PORTCbits.RC14) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD6) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD7) ? 0 : 1;
i += 56;
keyBit[i++] = (PORTDbits.RD8) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD9) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD10) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD11) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD12) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD13) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD14) ? 0 : 1;
keyBit[i++] = (PORTDbits.RD15) ? 0 : 1;
}
void updateKeyTable(int matrix) {
unsigned char key;
//unsigned char * pData = &keyTable[key];
unsigned char prevData;
int index = matrix * 64;
for (key = 0; key < 64; key++) { // process one set of 64 keys
//prevData = *pData;
prevData = keyTable[index];
unsigned int newKey = keyBit[index];
unsigned char keyDown = prevData & 0x80;
prevData <<= 1; // shift the data left one bit
if (newKey) prevData++; // set newest bit
prevData &= 0x07; // strip any high bits
if (!keyDown) { // if note is off in keyTable see if it should be on
if (prevData == 0b00000111) { // if 3 consecutive keyDown
keyDown = 1; // turn key on in keyTable
midiTxMsg[0] = M_NOTE_ON | matrix;
midiTxMsg[1] = key;
midiTxMsg[2] = M_VELOCITY_ON;
putMidiMsg();
}
} else if (keyDown) { // if note is on in keyTable...
if (prevData == 0b00000000) { // if 3 consecutive keyUp
keyDown = 0; // turn key off in keyTable
midiTxMsg[0] = M_NOTE_OFF | matrix;
midiTxMsg[1] = key;
midiTxMsg[2] = M_VELOCITY_OFF;
putMidiMsg(); // send note off msg
}
}
if (keyDown) prevData |= 0b10000000; // store the data
keyTable[index++] = prevData;
}
}
void putMidiMsg() {
uint8_t mType = midiTxMsg[0] & 0xf0;
int8_t key = midiTxMsg[1];
int8_t kybd = midiTxMsg[0] & 0x0f;
int index = (kybd * 64) + key;
switch (mType) {
case M_NOTE_ON:
if (kybd == 4) { // MIDI ch5
if (key == 0) { // if a transpose encoder bit
int8_t transposeTemp = 5;
if (keyBit[index++]) transposeTemp -= 1;
if (keyBit[index++]) transposeTemp -= 2;
if (keyBit[index++]) transposeTemp -= 4;
if (keyBit[index]) transposeTemp -= 8;
transposeSW = transposeTemp;
if (transposeSW > transposeHW) {
kybd = 7;
key = 0x3d; // increment
} else if (transposeHW > transposeSW) {
kybd = 7;
key = 0x3e; // decrement
} else {
mType = 0; // send nothing
}
}
else if (key < 4) {
mType = 0; // send nothing
}
}
midiTxMsg[0] = translateTable[kybd][key][0];
midiTxMsg[1] = translateTable[kybd][key][1];
midiTxMsg[2] = translateTable[kybd][key][2];
if (mType)
sendMidiMsg();
break;
case M_NOTE_OFF:
if (kybd == 4) { // MIDI ch5
if (key == 0) { // if a transpose encoder bit
int8_t transposeTemp = 5;
if (keyBit[index++]) transposeTemp -= 1;
if (keyBit[index++]) transposeTemp -= 2;
if (keyBit[index++]) transposeTemp -= 4;
if (keyBit[index]) transposeTemp -= 8;
transposeSW = transposeTemp;
if (transposeSW > transposeHW) {
kybd = 7;
key = 0x3d; // increment
} else if (transposeHW > transposeSW) {
kybd = 7;
key = 0x3e; // decrement
} else {
mType = 0; // send nothing
}
}
else if (key < 4) {
mType = 0; // send nothing
}
}
midiTxMsg[0] = translateTable[kybd][key][4];
midiTxMsg[1] = translateTable[kybd][key][5];
midiTxMsg[2] = translateTable[kybd][key][6];
if (mType)
sendMidiMsg();
break;
}
}
void sendMidiMsg(void) {
while (USBHandleBusy(USBTxHandle));
if (!USBHandleBusy(USBTxHandle)) {
midiData.Val = 0;
midiData.CableNumber = 0;
midiData.CodeIndexNumber = midiTxMsg[0] >> 4;
midiData.DATA_0 = midiTxMsg[0];
midiData.DATA_1 = midiTxMsg[1];
midiData.DATA_2 = midiTxMsg[2];
USBTxHandle = USBTxOnePacket(MIDI_EP, (BYTE*) & midiData, 4);
}
}
void getPots(int numPots) {
int i;
int pot = 0;
uint32_t diff;
for (i = 0; i < numPots; i++) {
freshPot[i] = *adcBufferPtr[i] >> 3;
freshPot[i] = (freshPot[i] + stalePot[i]) >> 1; // average old and new
diff = freshPot[i] - stalePot[i]; // find difference
if (diff) {
if (i == 0) {
pot = 7;
}
else pot = i - 1;
midiTxMsg[0] = M_CTRL_CHANGE | pot;
midiTxMsg[1] = M_CC_VOLUME;
midiTxMsg[2] = (uint8_t)freshPot[i];
stalePot[i] = freshPot[i]; // save previous value
sendMidiMsg();
}
}
}
/********************************************************************
* Function: static void InitializeSystem(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: InitializeSystem is a centralize initialization
* routine. All required USB initialization routines
* are called from here.
*
* User application initialization routine should
* also be called from here.
*
* Note: None
*******************************************************************/
static void InitializeSystem(void) {
// The USB specifications require that USB peripheral devices must never source
// current onto the Vbus pin. Additionally, USB peripherals should not source
// current on D+ or D- when the host/hub is not actively powering the Vbus line.
// When designing a self powered (as opposed to bus powered) USB peripheral
// device, the firmware should make sure not to turn on the USB module and D+
// or D- pull up resistor unless Vbus is actively powered. Therefore, the
// firmware needs some means to detect when Vbus is being powered by the host.
// A 5V tolerant I/O pin can be connected to Vbus (through a resistor), and
// can be used to detect when Vbus is high (host actively powering), or low
// (host is shut down or otherwise not supplying power). The USB firmware
// can then periodically poll this I/O pin to know when it is okay to turn on
// the USB module/D+/D- pull up resistor. When designing a purely bus powered
// peripheral device, it is not possible to source current on D+ or D- when the
// host is not actively providing power on Vbus. Therefore, implementing this
// bus sense feature is optional. This firmware can be made to use this bus
// sense feature by making sure "USE_USB_BUS_SENSE_IO" has been defined in the
// HardwareProfile.h file.
#if defined(USE_USB_BUS_SENSE_IO)
tris_usb_bus_sense = INPUT_PIN; // See HardwareProfile.h
#endif
// If the host PC sends a GetStatus (device) request, the firmware must respond
// and let the host know if the USB peripheral device is currently bus powered
// or self powered. See chapter 9 in the official USB specifications for details
// regarding this request. If the peripheral device is capable of being both
// self and bus powered, it should not return a hard coded value for this request.
// Instead, firmware should check if it is currently self or bus powered, and
// respond accordingly. If the hardware has been configured like demonstrated
// on the PICDEM FS USB Demo Board, an I/O pin can be polled to determine the
// currently selected power source. On the PICDEM FS USB Demo Board, "RA2"
// is used for this purpose. If using this feature, make sure "USE_SELF_POWER_SENSE_IO"
// has been defined in HardwareProfile.h, and that an appropriate I/O pin has been mapped
// to it in HardwareProfile.h.
#if defined(USE_SELF_POWER_SENSE_IO)
tris_self_power = INPUT_PIN; // See HardwareProfile.h
#endif
UserInit();
USBDeviceInit(); //usb_device.c. Initializes USB module SFRs and firmware
//variables to known states.
}//end InitializeSystem
/******************************************************************************
* Function: void UserInit(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This routine should take care of all of the demo code
* initialization that is required.
*
* Note:
*
*****************************************************************************/
void UserInit(void) {
//Initialize all of the LED pins
//mInitAllLEDs();
//Initialize all of the push buttons
//mInitAllSwitches();
//initialize the variable holding the handle for the last
// transmission
USBTxHandle = NULL;
USBRxHandle = NULL;
}//end UserInit
/********************************************************************
* Function: void ProcessIO(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: This function is a place holder for other user
* routines. It is a mixture of both USB and
* non-USB tasks.
*
* Note: None
*******************************************************************/
void ProcessIO(void) {
//Blink the LEDs according to the USB device status
//Don't blink if LCD is used -- RE pin conflicts
//BlinkUSBStatus();
// User Application USB tasks
if ((USBDeviceState < CONFIGURED_STATE) || (USBSuspendControl == 1)) return;
if (!USBHandleBusy(USBRxHandle)) {
//We have received a MIDI packet from the host, process it and then
// prepare to receive the next packet
//putsLCD("Parse RX Msg");
//INSERT MIDI PROCESSING CODE HERE
parseMidiMsg();
//Get ready for next packet (this will overwrite the old data)
USBRxHandle = USBRxOnePacket(MIDI_EP, (BYTE*) & ReceivedDataBuffer, 64);
}
if (keyScanTime) {
int i, j, k;
// get keyBit[] values by reading ports from low note to
// high note (61 notes)
#ifdef USE_11x6_MATRIX
// this is for an 11x6 matrix
for (i = 0; i < 22; i++) {
setMatrixColumn(i); // set one column at a time low
getTwelveBits(i);
clrMatrixColumn(i);
}
#else
// this is for an 8x8 matrix
for (i = 0; i < 8; i++) {
setMatrixColumn(i); // set one column at a time low
getSixteenBits(i);
clrMatrixColumn(i);
}
for (i = 11; i < 19; i++) {
setMatrixColumn(i); // set one column at a time low
getSixteenBits(i-3);// -3 because we are skipping the three extra
// columns used by an 11x6 matrix
clrMatrixColumn(i);
}
#endif
for (i = 0; i < 4; i++) {
updateKeyTable(i);
}
if (keyScanCount % 4 == 0) { // if 0, 4, 8, 12, 16, 20, 24, 28
i = keyScanCount / 4; // i = 0, 1, ...7
#ifdef USE_I2C
chipAddress = CENT_CHIP_1 + i;
if (!i2cChipIsOutput[0][i]) {
i2cRxData[0][i] = getCentipedeBytes(CENTIPEDE_I2C_BUS1, chipAddress, CENT_REG_A);