]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Scan/UARTConnect/connect_scan.c
8b647accbcdb513a0a3068be3f03804c0170d138
[kiibohd-controller.git] / Scan / UARTConnect / connect_scan.c
1 /* Copyright (C) 2014-2015 by Jacob Alexander
2  *
3  * This file is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * This file is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this file.  If not, see <http://www.gnu.org/licenses/>.
15  */
16
17 // ----- Includes -----
18
19 // Compiler Includes
20 #include <Lib/ScanLib.h>
21
22 // Project Includes
23 #include <cli.h>
24 #include <kll_defs.h>
25 #include <led.h>
26 #include <print.h>
27 #include <macro.h>
28
29 // Local Includes
30 #include "connect_scan.h"
31
32
33
34 // ----- Macros -----
35
36 #define UART_Master 1
37 #define UART_Slave  0
38 #define uart_lock_m( uartNum )         uart##uartNum##_lock
39 #define uart_buffer_items_m( uartNum ) uart##uartNum##_buffer_items
40 #define uart_buffer_m( uartNum )       uart##uartNum##_buffer
41 #define uart_buffer_head_m( uartNum )  uart##uartNum##_buffer_head
42 #define uart_buffer_tail_m( uartNum )  uart##uartNum##_buffer_tail
43 #define uart_tx_status_m( uartNum )    uart##uartNum##_tx_status
44
45 // Macro for adding to each uart Tx ring buffer
46 #define uart_addTxBuffer( uartNum ) \
47 case uartNum: \
48         /* Delay UART copy until there's some space left */ \
49         while ( uart_buffer_items_m( uartNum ) + count > uart_buffer_size ) \
50         { \
51                 warn_msg("Too much data to send on UART0, waiting..."); \
52                 delay( 1 ); \
53         } \
54         /* Append data to ring buffer */ \
55         for ( uint8_t c = 0; c < count; c++ ) \
56         { \
57                 if ( Connect_debug ) \
58                 { \
59                         printHex( buffer[ c ] ); \
60                         print( " +" #uartNum NL ); \
61                 } \
62                 uart_buffer_m( uartNum )[ uart_buffer_tail_m( uartNum )++ ] = buffer[ c ]; \
63                 uart_buffer_items_m( uartNum )++; \
64                 if ( uart_buffer_tail_m( uartNum ) >= uart_buffer_size ) \
65                         uart_buffer_tail_m( uartNum ) = 0; \
66                 if ( uart_buffer_head_m( uartNum ) == uart_buffer_tail_m( uartNum ) ) \
67                         uart_buffer_head_m( uartNum )++; \
68                 if ( uart_buffer_head_m( uartNum ) >= uart_buffer_size ) \
69                         uart_buffer_head_m( uartNum ) = 0; \
70         } \
71         break
72
73 // Macro for popping from Tx ring buffer
74 #define uart_fillTxFifo( uartNum ) \
75 { \
76         uint8_t fifoSize = ( ( UART##uartNum##_PFIFO & UART_PFIFO_TXFIFOSIZE ) >> 2 ); \
77         if ( fifoSize == 0 ) \
78                 fifoSize = 1; \
79         if ( Connect_debug ) \
80         { \
81                 print( "TxFIFO " #uartNum " - " ); \
82                 printHex( fifoSize ); \
83                 print("/"); \
84                 printHex( UART##uartNum##_TCFIFO ); \
85                 print("/"); \
86                 printHex( uart##uartNum##_buffer_items ); \
87                 print( NL ); \
88         } \
89         /* XXX Doesn't work well */ \
90         /* while ( UART##uartNum##_TCFIFO < fifoSize ) */ \
91         /* More reliable, albeit slower */ \
92         fifoSize -= UART##uartNum##_TCFIFO; \
93         while ( fifoSize-- != 0 ) \
94         { \
95                 if ( uart##uartNum##_buffer_items == 0 ) \
96                         break; \
97                 UART##uartNum##_D = uart##uartNum##_buffer[ uart##uartNum##_buffer_head++ ]; \
98                 uart##uartNum##_buffer_items--; \
99                 if ( uart##uartNum##_buffer_head >= uart_buffer_size ) \
100                         uart##uartNum##_buffer_head = 0; \
101         } \
102 }
103
104 // Macro for processing UART Rx
105 #define uart_processRx( uartNum ) \
106 { \
107         if ( !( UART##uartNum##_S1 & UART_S1_RDRF ) ) \
108                 return; \
109         uint8_t available = UART##uartNum##_RCFIFO; \
110         if ( available == 0 ) \
111         { \
112                 available = UART##uartNum##_D; \
113                 UART##uartNum##_CFIFO = UART_CFIFO_RXFLUSH; \
114                 return; \
115         } \
116         /* Process each byte in the UART buffer */ \
117         while ( available-- > 0 ) \
118         { \
119                 /* First check if there was noise or Parity issues with current byte */ \
120                 uint8_t err_status = UART##uartNum##_ED; \
121                 /* Read byte from Rx FIFO */ \
122                 uint8_t byteRead = UART##uartNum##_D; \
123                 if ( Connect_debug ) \
124                 { \
125                         printHex( byteRead ); \
126                         print("("); \
127                         printInt8( available ); \
128                         print(") <-"); \
129                 } \
130                 /* Check error status */ \
131                 if ( err_status & 0x80 ) \
132                 { \
133                         print(" NOISY "); \
134                 } \
135                 if ( err_status & 0x40 ) \
136                 { \
137                         print(" PARITY ERR "); \
138                 } \
139                 /* Ignore current byte if there was an error */ \
140                 if ( err_status ) \
141                 { \
142                         uart##uartNum##_rx_status = UARTStatus_Wait; \
143                         if ( Connect_debug ) \
144                         { \
145                                 print( NL ); \
146                         } \
147                         continue; \
148                 } \
149                 switch ( uart##uartNum##_rx_status ) \
150                 { \
151                 case UARTStatus_Wait: \
152                         if ( Connect_debug ) \
153                         { \
154                                 print(" Wait "); \
155                         } \
156                         uart##uartNum##_rx_status = byteRead == 0x16 ? UARTStatus_SYN : UARTStatus_Wait; \
157                         break; \
158                 case UARTStatus_SYN: \
159                         if ( Connect_debug ) \
160                         { \
161                                 print(" SYN "); \
162                         } \
163                         uart##uartNum##_rx_status = byteRead == 0x01 ? UARTStatus_SOH : UARTStatus_Wait; \
164                         break; \
165                 case UARTStatus_SOH: \
166                 { \
167                         if ( Connect_debug ) \
168                         { \
169                                 print(" SOH "); \
170                         } \
171                         /* Check if this is actually a reserved CMD 0x16 */ \
172                         if ( byteRead == Command_SYN ) \
173                         { \
174                                 uart##uartNum##_rx_status = UARTStatus_SYN; \
175                                 break; \
176                         } \
177                         /* Otherwise process the command */ \
178                         uint8_t byte = byteRead; \
179                         if ( byte < Command_TOP ) \
180                         { \
181                                 uart##uartNum##_rx_status = UARTStatus_Command; \
182                                 uart##uartNum##_rx_command = byte; \
183                                 uart##uartNum##_rx_bytes_waiting = 0xFFFF; \
184                         } \
185                         else \
186                         { \
187                                 uart##uartNum##_rx_status = UARTStatus_Wait; \
188                         } \
189                         switch ( uart##uartNum##_rx_command ) \
190                         { \
191                         case IdRequest: \
192                                 Connect_receive_IdRequest( 0, (uint16_t*)&uart##uartNum##_rx_bytes_waiting, uartNum ); \
193                                 uart##uartNum##_rx_status = UARTStatus_Wait; \
194                                 break; \
195                         default: \
196                                 if ( Connect_debug ) \
197                                 { \
198                                         print(" ### "); \
199                                         printHex( uart##uartNum##_rx_command ); \
200                                 } \
201                                 break; \
202                         } \
203                         break; \
204                 } \
205                 case UARTStatus_Command: \
206                 { \
207                         if ( Connect_debug ) \
208                         { \
209                                 print(" CMD "); \
210                         } \
211                         /* Call specific UARTConnect command receive function */ \
212                         uint8_t (*rcvFunc)(uint8_t, uint16_t(*), uint8_t) = (uint8_t(*)(uint8_t, uint16_t(*), uint8_t))(Connect_receiveFunctions[ uart##uartNum##_rx_command ]); \
213                         if ( rcvFunc( byteRead, (uint16_t*)&uart##uartNum##_rx_bytes_waiting, uartNum ) ) \
214                                 uart##uartNum##_rx_status = UARTStatus_Wait; \
215                         break; \
216                 } \
217                 default: \
218                         erro_msg("Invalid UARTStatus..."); \
219                         uart##uartNum##_rx_status = UARTStatus_Wait; \
220                         available++; \
221                         continue; \
222                 } \
223                 if ( Connect_debug ) \
224                 { \
225                         print( NL ); \
226                 } \
227         } \
228 }
229
230 // Macros for locking/unlock Tx buffers
231 #define uart_lockTx( uartNum ) \
232 { \
233         /* First, secure place in line for the resource */ \
234         while ( uart_lock_m( uartNum ) ); \
235         uart_lock_m( uartNum ) = 1; \
236         /* Next, wait unit the UART is ready */ \
237         while ( uart_tx_status_m( uartNum ) != UARTStatus_Ready ); \
238         uart_tx_status_m( uartNum ) = UARTStatus_Wait; \
239 }
240
241 #define uart_lockBothTx( uartNum1, uartNum2 ) \
242 { \
243         /* First, secure place in line for the resource */ \
244         while ( uart_lock_m( uartNum1 ) || uart_lock_m( uartNum2 ) ); \
245         uart_lock_m( uartNum1 ) = 1; \
246         uart_lock_m( uartNum2 ) = 1; \
247         /* Next, wait unit the UARTs are ready */ \
248         while ( uart_tx_status_m( uartNum1 ) != UARTStatus_Ready || uart_tx_status_m( uartNum2 ) != UARTStatus_Ready ); \
249         uart_tx_status_m( uartNum1 ) = UARTStatus_Wait; \
250         uart_tx_status_m( uartNum2 ) = UARTStatus_Wait; \
251 }
252
253 #define uart_unlockTx( uartNum ) \
254 { \
255         /* Ready the UART */ \
256         uart_tx_status_m( uartNum ) = UARTStatus_Ready; \
257         /* Unlock the resource */ \
258         uart_lock_m( uartNum ) = 0; \
259 }
260
261
262
263 // ----- Function Declarations -----
264
265 // CLI Functions
266 void cliFunc_connectCmd ( char *args );
267 void cliFunc_connectDbg ( char *args );
268 void cliFunc_connectIdl ( char *args );
269 void cliFunc_connectLst ( char *args );
270 void cliFunc_connectMst ( char *args );
271 void cliFunc_connectRst ( char *args );
272 void cliFunc_connectSts ( char *args );
273
274
275
276 // ----- Variables -----
277
278 // Connect Module command dictionary
279 CLIDict_Entry( connectCmd,  "Sends a command via UART Connect, first arg is which uart, next arg is the command, rest are the arguments." );
280 CLIDict_Entry( connectDbg,  "Toggle UARTConnect debug mode." );
281 CLIDict_Entry( connectIdl,  "Sends N number of Idle commands, 2 is the default value, and should be sufficient in most cases." );
282 CLIDict_Entry( connectLst,  "Lists available UARTConnect commands and index id" );
283 CLIDict_Entry( connectMst,  "Sets the device as master. Use argument of s to set as slave." );
284 CLIDict_Entry( connectRst,  "Resets both Rx and Tx connect buffers and state variables." );
285 CLIDict_Entry( connectSts,  "UARTConnect status." );
286 CLIDict_Def( uartConnectCLIDict, "UARTConnect Module Commands" ) = {
287         CLIDict_Item( connectCmd ),
288         CLIDict_Item( connectDbg ),
289         CLIDict_Item( connectIdl ),
290         CLIDict_Item( connectLst ),
291         CLIDict_Item( connectMst ),
292         CLIDict_Item( connectRst ),
293         CLIDict_Item( connectSts ),
294         { 0, 0, 0 } // Null entry for dictionary end
295 };
296
297
298 // -- Connect Device Id Variables --
299 uint8_t Connect_id = 255; // Invalid, unset
300 uint8_t Connect_master = 0;
301 uint8_t Connect_maxId = 0;
302
303
304 // -- Control Variables --
305 uint32_t Connect_lastCheck = 0; // Cable Check scheduler
306 uint8_t Connect_debug = 0;      // Set 1 for debug
307 uint8_t Connect_override = 0;   // Prevents master from automatically being set
308
309
310 // -- Rx Status Variables --
311
312 volatile UARTStatus uart0_rx_status;
313 volatile UARTStatus uart1_rx_status;
314 volatile uint16_t uart0_rx_bytes_waiting;
315 volatile uint16_t uart1_rx_bytes_waiting;
316 volatile Command uart0_rx_command;
317 volatile Command uart1_rx_command;
318 volatile uint8_t uart0_lock;
319 volatile uint8_t uart1_lock;
320
321
322 // -- Tx Status Variables --
323
324 volatile UARTStatus uart0_tx_status;
325 volatile UARTStatus uart1_tx_status;
326
327
328 // -- Ring Buffer Variables --
329
330 #define uart_buffer_size UARTConnectBufSize_define
331 volatile uint8_t uart0_buffer_head;
332 volatile uint8_t uart0_buffer_tail;
333 volatile uint8_t uart0_buffer_items;
334 volatile uint8_t uart0_buffer[uart_buffer_size];
335 volatile uint8_t uart1_buffer_head;
336 volatile uint8_t uart1_buffer_tail;
337 volatile uint8_t uart1_buffer_items;
338 volatile uint8_t uart1_buffer[uart_buffer_size];
339
340 volatile uint8_t uarts_configured = 0;
341
342
343 // -- Ring Buffer Convenience Functions --
344
345 void Connect_addBytes( uint8_t *buffer, uint8_t count, uint8_t uart )
346 {
347         // Too big to fit into buffer
348         if ( count > uart_buffer_size )
349         {
350                 erro_msg("Too big of a command to fit into the buffer...");
351                 return;
352         }
353
354         // Choose the uart
355         switch ( uart )
356         {
357         uart_addTxBuffer( UART_Master );
358         uart_addTxBuffer( UART_Slave );
359         default:
360                 erro_msg("Invalid UART to send from...");
361                 break;
362         }
363 }
364
365
366 // -- Connect send functions --
367
368 // patternLen defines how many bytes should the incrementing pattern have
369 void Connect_send_CableCheck( uint8_t patternLen )
370 {
371         // Wait until the Tx buffers are ready, then lock them
372         uart_lockBothTx( UART_Master, UART_Slave );
373
374         // Prepare header
375         uint8_t header[] = { 0x16, 0x01, CableCheck, patternLen };
376
377         // Send header
378         Connect_addBytes( header, sizeof( header ), UART_Master );
379         Connect_addBytes( header, sizeof( header ), UART_Slave );
380
381         // Send 0xD2 (11010010) for each argument
382         uint8_t value = 0xD2;
383         for ( uint8_t c = 0; c < patternLen; c++ )
384         {
385                 Connect_addBytes( &value, 1, UART_Master );
386                 Connect_addBytes( &value, 1, UART_Slave );
387         }
388
389         // Release Tx buffers
390         uart_unlockTx( UART_Master );
391         uart_unlockTx( UART_Slave );
392 }
393
394 void Connect_send_IdRequest()
395 {
396         // Lock master bound Tx
397         uart_lockTx( UART_Master );
398
399         // Prepare header
400         uint8_t header[] = { 0x16, 0x01, IdRequest };
401
402         // Send header
403         Connect_addBytes( header, sizeof( header ), UART_Master );
404
405         // Unlock Tx
406         uart_unlockTx( UART_Master );
407 }
408
409 // id is the value the next slave should enumerate as
410 void Connect_send_IdEnumeration( uint8_t id )
411 {
412         // Lock slave bound Tx
413         uart_lockTx( UART_Slave );
414
415         // Prepare header
416         uint8_t header[] = { 0x16, 0x01, IdEnumeration, id };
417
418         // Send header
419         Connect_addBytes( header, sizeof( header ), UART_Slave );
420
421         // Unlock Tx
422         uart_unlockTx( UART_Slave );
423 }
424
425 // id is the currently assigned id to the slave
426 void Connect_send_IdReport( uint8_t id )
427 {
428         // Lock master bound Tx
429         uart_lockTx( UART_Master );
430
431         // Prepare header
432         uint8_t header[] = { 0x16, 0x01, IdReport, id };
433
434         // Send header
435         Connect_addBytes( header, sizeof( header ), UART_Master );
436
437         // Unlock Tx
438         uart_unlockTx( UART_Master );
439 }
440
441 // id is the currently assigned id to the slave
442 // scanCodeStateList is an array of [scancode, state]'s (8 bit values)
443 // numScanCodes is the number of scan codes to parse from array
444 void Connect_send_ScanCode( uint8_t id, TriggerGuide *scanCodeStateList, uint8_t numScanCodes )
445 {
446         // Lock master bound Tx
447         uart_lockTx( UART_Master );
448
449         // Prepare header
450         uint8_t header[] = { 0x16, 0x01, ScanCode, id, numScanCodes };
451
452         // Send header
453         Connect_addBytes( header, sizeof( header ), UART_Master );
454
455         // Send each of the scan codes
456         Connect_addBytes( (uint8_t*)scanCodeStateList, numScanCodes * TriggerGuideSize, UART_Master );
457
458         // Unlock Tx
459         uart_unlockTx( UART_Master );
460 }
461
462 // id is the currently assigned id to the slave
463 // paramList is an array of [param, value]'s (8 bit values)
464 // numParams is the number of params to parse from the array
465 void Connect_send_Animation( uint8_t id, uint8_t *paramList, uint8_t numParams )
466 {
467         // Lock slave bound Tx
468         uart_lockTx( UART_Slave );
469
470         // Prepare header
471         uint8_t header[] = { 0x16, 0x01, Animation, id, numParams };
472
473         // Send header
474         Connect_addBytes( header, sizeof( header ), UART_Slave );
475
476         // Send each of the scan codes
477         Connect_addBytes( paramList, numParams, UART_Slave );
478
479         // Unlock Tx
480         uart_unlockTx( UART_Slave );
481 }
482
483 void Connect_send_Idle( uint8_t num )
484 {
485         // Wait until the Tx buffers are ready, then lock them
486         uart_lockBothTx( UART_Slave, UART_Master );
487
488         // Send n number of idles to reset link status (if in a bad state)
489         uint8_t value = 0x16;
490         for ( uint8_t c = 0; c < num; c++ )
491         {
492                 Connect_addBytes( &value, 1, UART_Master );
493                 Connect_addBytes( &value, 1, UART_Slave );
494         }
495
496         // Release Tx buffers
497         uart_unlockTx( UART_Master );
498         uart_unlockTx( UART_Slave );
499 }
500
501
502 // -- Connect receive functions --
503
504 // - Cable Check variables -
505 uint32_t Connect_cableFaultsMaster = 0;
506 uint32_t Connect_cableFaultsSlave  = 0;
507 uint32_t Connect_cableChecksMaster = 0;
508 uint32_t Connect_cableChecksSlave  = 0;
509 uint8_t  Connect_cableOkMaster = 0;
510 uint8_t  Connect_cableOkSlave  = 0;
511
512 uint8_t Connect_receive_CableCheck( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num )
513 {
514         // Check if this is the first byte
515         if ( *pending_bytes == 0xFFFF )
516         {
517                 *pending_bytes = byte;
518
519                 if ( Connect_debug )
520                 {
521                         dbug_msg("PENDING SET -> ");
522                         printHex( byte );
523                         print(" ");
524                         printHex( *pending_bytes );
525                         print( NL );
526                 }
527         }
528         // Verify byte
529         else
530         {
531                 (*pending_bytes)--;
532
533                 // The argument bytes are always 0xD2 (11010010)
534                 if ( byte != 0xD2 )
535                 {
536                         warn_print("Cable Fault!");
537
538                         // Check which side of the chain
539                         if ( uart_num == UART_Slave )
540                         {
541                                 Connect_cableFaultsSlave++;
542                                 Connect_cableOkSlave = 0;
543                                 print(" Slave ");
544                         }
545                         else
546                         {
547                                 Connect_cableFaultsMaster++;
548                                 Connect_cableOkMaster = 0;
549                                 print(" Master ");
550                         }
551                         printHex( byte );
552                         print( NL );
553
554                         // Signal that the command should wait for a SYN again
555                         return 1;
556                 }
557                 else
558                 {
559                         // Check which side of the chain
560                         if ( uart_num == UART_Slave )
561                         {
562                                 Connect_cableChecksSlave++;
563                         }
564                         else
565                         {
566                                 Connect_cableChecksMaster++;
567                         }
568                 }
569         }
570
571         // If cable check was successful, set cable ok
572         if ( *pending_bytes == 0 )
573         {
574                 if ( uart_num == UART_Slave )
575                 {
576                         Connect_cableOkSlave = 1;
577                 }
578                 else
579                 {
580                         Connect_cableOkMaster = 1;
581                 }
582         }
583
584         if ( Connect_debug )
585         {
586                 dbug_msg("CABLECHECK RECEIVE - ");
587                 printHex( byte );
588                 print(" ");
589                 printHex( *pending_bytes );
590                 print( NL );
591         }
592
593         // Check whether the cable check has finished
594         return *pending_bytes == 0 ? 1 : 0;
595 }
596
597 uint8_t Connect_receive_IdRequest( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num )
598 {
599         dbug_print("IdRequest");
600         // Check the directionality
601         if ( uart_num == UART_Master )
602         {
603                 erro_print("Invalid IdRequest direction...");
604         }
605
606         // Check if master, begin IdEnumeration
607         if ( Connect_master )
608         {
609                 // The first device is always id 1
610                 // Id 0 is reserved for the master
611                 Connect_send_IdEnumeration( 1 );
612         }
613         // Propagate IdRequest
614         else
615         {
616                 Connect_send_IdRequest();
617         }
618
619         return 1;
620 }
621
622 uint8_t Connect_receive_IdEnumeration( uint8_t id, uint16_t *pending_bytes, uint8_t uart_num )
623 {
624         dbug_print("IdEnumeration");
625         // Check the directionality
626         if ( uart_num == UART_Slave )
627         {
628                 erro_print("Invalid IdEnumeration direction...");
629         }
630
631         // Set the device id
632         Connect_id = id;
633
634         // Send reponse back to master
635         Connect_send_IdReport( id );
636
637         // Propogate next Id if the connection is ok
638         if ( Connect_cableOkSlave )
639         {
640                 Connect_send_IdEnumeration( id + 1 );
641         }
642
643         return 1;
644 }
645
646 uint8_t Connect_receive_IdReport( uint8_t id, uint16_t *pending_bytes, uint8_t uart_num )
647 {
648         dbug_print("IdReport");
649         // Check the directionality
650         if ( uart_num == UART_Master )
651         {
652                 erro_print("Invalid IdRequest direction...");
653         }
654
655         // Track Id response if master
656         if ( Connect_master )
657         {
658                 info_msg("Id Reported: ");
659                 printHex( id );
660                 print( NL );
661
662                 // Check if this is the highest ID
663                 if ( id > Connect_maxId )
664                         Connect_maxId = id;
665                 return 1;
666         }
667         // Propagate id if yet another slave
668         else
669         {
670                 Connect_send_IdReport( id );
671         }
672
673         return 1;
674 }
675
676 // - Scan Code Variables -
677 TriggerGuide Connect_receive_ScanCodeBuffer;
678 uint8_t Connect_receive_ScanCodeBufferPos;
679 uint8_t Connect_receive_ScanCodeDeviceId;
680
681 uint8_t Connect_receive_ScanCode( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num )
682 {
683         // Check the directionality
684         if ( uart_num == UART_Master )
685         {
686                 erro_print("Invalid ScanCode direction...");
687         }
688
689         // Master node, trigger scan codes
690         if ( Connect_master ) switch ( (*pending_bytes)-- )
691         {
692         // Byte count always starts at 0xFFFF
693         case 0xFFFF: // Device Id
694                 Connect_receive_ScanCodeDeviceId = byte;
695                 break;
696
697         case 0xFFFE: // Number of TriggerGuides in bytes (byte * 3)
698                 *pending_bytes = byte * sizeof( TriggerGuide );
699                 Connect_receive_ScanCodeBufferPos = 0;
700                 break;
701
702         default:
703                 // Set the specific TriggerGuide entry
704                 ((uint8_t*)&Connect_receive_ScanCodeBuffer)[ Connect_receive_ScanCodeBufferPos++ ] = byte;
705
706                 // Reset the BufferPos if higher than sizeof TriggerGuide
707                 // And send the TriggerGuide to the Macro Module
708                 if ( Connect_receive_ScanCodeBufferPos >= sizeof( TriggerGuide ) )
709                 {
710                         Connect_receive_ScanCodeBufferPos = 0;
711
712                         // Adjust ScanCode offset
713                         if ( Connect_receive_ScanCodeDeviceId > 0 )
714                         {
715                                 // Check if this node is too large
716                                 if ( Connect_receive_ScanCodeDeviceId >= InterconnectNodeMax )
717                                 {
718                                         warn_msg("Not enough interconnect layout nodes configured: ");
719                                         printHex( Connect_receive_ScanCodeDeviceId );
720                                         print( NL );
721                                         break;
722                                 }
723
724                                 // This variable is in generatedKeymaps.h
725                                 extern uint8_t InterconnectOffsetList[];
726                                 Connect_receive_ScanCodeBuffer.scanCode = Connect_receive_ScanCodeBuffer.scanCode + InterconnectOffsetList[ Connect_receive_ScanCodeDeviceId - 1 ];
727                         }
728
729                         // ScanCode receive debug
730                         if ( Connect_debug )
731                         {
732                                 dbug_msg("");
733                                 printHex( Connect_receive_ScanCodeBuffer.type );
734                                 print(" ");
735                                 printHex( Connect_receive_ScanCodeBuffer.state );
736                                 print(" ");
737                                 printHex( Connect_receive_ScanCodeBuffer.scanCode );
738                                 print( NL );
739                         }
740
741                         // Send ScanCode to macro module
742                         Macro_interconnectAdd( &Connect_receive_ScanCodeBuffer );
743                 }
744
745                 break;
746         }
747         // Propagate ScanCode packet
748         else switch ( (*pending_bytes)-- )
749         {
750         // Byte count always starts at 0xFFFF
751         case 0xFFFF: // Device Id
752         {
753                 Connect_receive_ScanCodeDeviceId = byte;
754
755                 // Lock the master Tx buffer
756                 uart_lockTx( UART_Master );
757
758                 // Send header + Id byte
759                 uint8_t header[] = { 0x16, 0x01, ScanCode, byte };
760                 Connect_addBytes( header, sizeof( header ), UART_Master );
761                 break;
762         }
763         case 0xFFFE: // Number of TriggerGuides in bytes
764                 *pending_bytes = byte * sizeof( TriggerGuide );
765                 Connect_receive_ScanCodeBufferPos = 0;
766
767                 // Pass through byte
768                 Connect_addBytes( &byte, 1, UART_Master );
769                 break;
770
771         default:
772                 // Pass through byte
773                 Connect_addBytes( &byte, 1, UART_Master );
774
775                 // Unlock Tx Buffer after sending last byte
776                 if ( *pending_bytes == 0 )
777                         uart_unlockTx( UART_Master );
778                 break;
779         }
780
781         // Check whether the scan codes have finished sending
782         return *pending_bytes == 0 ? 1 : 0;
783 }
784
785 uint8_t Connect_receive_Animation( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num )
786 {
787         dbug_print("Animation");
788         return 1;
789 }
790
791
792 // Baud Rate
793 // NOTE: If finer baud adjustment is needed see UARTx_C4 -> BRFA in the datasheet
794 uint16_t Connect_baud = UARTConnectBaud_define; // Max setting of 8191
795 uint16_t Connect_baudFine = UARTConnectBaudFine_define;
796
797 // Connect receive function lookup
798 void *Connect_receiveFunctions[] = {
799         Connect_receive_CableCheck,
800         Connect_receive_IdRequest,
801         Connect_receive_IdEnumeration,
802         Connect_receive_IdReport,
803         Connect_receive_ScanCode,
804         Connect_receive_Animation,
805 };
806
807
808
809 // ----- Interrupt Functions -----
810
811 // Master / UART0 ISR
812 void uart0_status_isr()
813 {
814         // Process Rx buffer
815         uart_processRx( 0 );
816 }
817
818 // Slave / UART1 ISR
819 void uart1_status_isr()
820 {
821         // Process Rx buffer
822         uart_processRx( 1 );
823 }
824
825
826
827 // ----- Functions -----
828
829 // Resets the state of the UART buffers and state variables
830 void Connect_reset()
831 {
832         // Rx Status Variables
833         uart0_rx_status = UARTStatus_Wait;
834         uart1_rx_status = UARTStatus_Wait;
835         uart0_rx_bytes_waiting = 0;
836         uart1_rx_bytes_waiting = 0;
837         uart0_lock = 0;
838         uart1_lock = 0;
839
840         // Tx Status Variables
841         uart0_tx_status = UARTStatus_Ready;
842         uart1_tx_status = UARTStatus_Ready;
843
844         // Ring Buffer Variables
845         uart0_buffer_head = 0;
846         uart0_buffer_tail = 0;
847         uart0_buffer_items = 0;
848         uart1_buffer_head = 0;
849         uart1_buffer_tail = 0;
850         uart1_buffer_items = 0;
851 }
852
853
854 // Setup connection to other side
855 // - Only supports a single slave and master
856 // - If USB has been initiallized at this point, this side is the master
857 // - If both sides assert master, flash error leds
858 void Connect_setup( uint8_t master )
859 {
860         // Indication that UARTs are not ready
861         uarts_configured = 0;
862
863         // Register Connect CLI dictionary
864         CLI_registerDictionary( uartConnectCLIDict, uartConnectCLIDictName );
865
866         // Check if master
867         Connect_master = master;
868         if ( Connect_master )
869                 Connect_id = 0; // 0x00 is always the master Id
870
871         // Master / UART0 setup
872         // Slave  / UART1 setup
873         // Setup the the UART interface for keyboard data input
874         SIM_SCGC4 |= SIM_SCGC4_UART0; // Disable clock gating
875         SIM_SCGC4 |= SIM_SCGC4_UART1; // Disable clock gating
876
877         // Pin Setup for UART0 / UART1
878         PORTA_PCR1 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(2); // RX Pin
879         PORTA_PCR2 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(2); // TX Pin
880         PORTE_PCR0 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); // RX Pin
881         PORTE_PCR1 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); // TX Pin
882
883         // Baud Rate setting
884         UART0_BDH = (uint8_t)(Connect_baud >> 8);
885         UART0_BDL = (uint8_t)Connect_baud;
886         UART0_C4  = Connect_baudFine;
887         UART1_BDH = (uint8_t)(Connect_baud >> 8);
888         UART1_BDL = (uint8_t)Connect_baud;
889         UART1_C4  = Connect_baudFine;
890
891         // 8 bit, Even Parity, Idle Character bit after stop
892         // NOTE: For 8 bit with Parity you must enable 9 bit transmission (pg. 1065)
893         //       You only need to use UART0_D for 8 bit reading/writing though
894         // UART_C1_M UART_C1_PE UART_C1_PT UART_C1_ILT
895         UART0_C1 = UART_C1_M | UART_C1_PE | UART_C1_ILT;
896         UART1_C1 = UART_C1_M | UART_C1_PE | UART_C1_ILT;
897
898         // Number of bytes in FIFO before TX Interrupt
899         UART0_TWFIFO = 1;
900         UART1_TWFIFO = 1;
901
902         // Number of bytes in FIFO before RX Interrupt
903         UART0_RWFIFO = 1;
904         UART1_RWFIFO = 1;
905
906         // Enable TX and RX FIFOs
907         UART0_PFIFO = UART_PFIFO_TXFE | UART_PFIFO_RXFE;
908         UART1_PFIFO = UART_PFIFO_TXFE | UART_PFIFO_RXFE;
909
910         // Reciever Inversion Disabled, LSBF
911         // UART_S2_RXINV UART_S2_MSBF
912         UART0_S2 |= 0x00;
913         UART1_S2 |= 0x00;
914
915         // Transmit Inversion Disabled
916         // UART_C3_TXINV
917         UART0_C3 |= 0x00;
918         UART1_C3 |= 0x00;
919
920         // TX Enabled, RX Enabled, RX Interrupt Enabled
921         // UART_C2_TE UART_C2_RE UART_C2_RIE
922         UART0_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE;
923         UART1_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE;
924
925         // Add interrupts to the vector table
926         NVIC_ENABLE_IRQ( IRQ_UART0_STATUS );
927         NVIC_ENABLE_IRQ( IRQ_UART1_STATUS );
928
929         // UARTs are now ready to go
930         uarts_configured = 1;
931
932         // Reset the state of the UART variables
933         Connect_reset();
934 }
935
936
937 // Scan for updates in the master/slave
938 // - Interrupts will deal with most input functions
939 // - Used to send queries
940 // - SyncEvent is sent immediately once the current command is sent
941 // - SyncEvent is also blocking until sent
942 void Connect_scan()
943 {
944         // Check if initially configured as a slave and usb comes up
945         // Then reconfigure as a master
946         if ( !Connect_master && Output_Available && !Connect_override )
947         {
948                 Connect_setup( Output_Available );
949         }
950
951         // Limit how often we do cable checks
952         uint32_t time_compare = 0x7FF; // Must be all 1's, 0x3FF is valid, 0x4FF is not
953         uint32_t current_time = systick_millis_count;
954         if ( Connect_lastCheck != current_time
955                 && ( current_time & time_compare ) == time_compare
956         )
957         {
958                 // Make sure we don't double check if the clock speed is too high
959                 Connect_lastCheck = current_time;
960
961                 // Send a cable check command of 2 bytes
962                 Connect_send_CableCheck( UARTConnectCableCheckLength_define );
963
964                 // If this is a slave, and we don't have an id yeth
965                 // Don't bother sending if there are cable issues
966                 if ( !Connect_master && Connect_id == 0xFF && Connect_cableOkMaster )
967                 {
968                         Connect_send_IdRequest();
969                 }
970         }
971
972         // Only process commands if uarts have been configured
973         if ( uarts_configured )
974         {
975                 // Check if Tx Buffers are empty and the Tx Ring buffers have data to send
976                 // This happens if there was previously nothing to send
977                 if ( uart0_buffer_items > 0 && UART0_TCFIFO == 0 )
978                         uart_fillTxFifo( 0 );
979                 if ( uart1_buffer_items > 0 && UART1_TCFIFO == 0 )
980                         uart_fillTxFifo( 1 );
981         }
982 }
983
984
985
986 // ----- CLI Command Functions -----
987
988 void cliFunc_connectCmd( char* args )
989 {
990         // Parse number from argument
991         //  NOTE: Only first argument is used
992         char* arg1Ptr;
993         char* arg2Ptr;
994         CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
995
996         print( NL );
997
998         switch ( numToInt( &arg1Ptr[0] ) )
999         {
1000         case CableCheck:
1001                 Connect_send_CableCheck( UARTConnectCableCheckLength_define );
1002                 break;
1003
1004         case IdRequest:
1005                 Connect_send_IdRequest();
1006                 break;
1007
1008         case IdEnumeration:
1009                 Connect_send_IdEnumeration( 5 );
1010                 break;
1011
1012         case IdReport:
1013                 Connect_send_IdReport( 8 );
1014                 break;
1015
1016         case ScanCode:
1017         {
1018                 TriggerGuide scanCodes[] = { { 0x00, 0x01, 0x05 }, { 0x00, 0x03, 0x16 } };
1019                 Connect_send_ScanCode( 10, scanCodes, 2 );
1020                 break;
1021         }
1022         case Animation:
1023                 break;
1024
1025         case RemoteCapability:
1026                 // TODO
1027                 break;
1028
1029         case RemoteOutput:
1030                 // TODO
1031                 break;
1032
1033         case RemoteInput:
1034                 // TODO
1035                 break;
1036
1037         default:
1038                 break;
1039         }
1040 }
1041
1042 void cliFunc_connectDbg( char* args )
1043 {
1044         print( NL );
1045         info_msg("Connect Debug Mode Toggle");
1046         Connect_debug = !Connect_debug;
1047 }
1048
1049 void cliFunc_connectIdl( char* args )
1050 {
1051         // Parse number from argument
1052         //  NOTE: Only first argument is used
1053         char* arg1Ptr;
1054         char* arg2Ptr;
1055         CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
1056
1057         print( NL );
1058         info_msg("Sending Sync Idles...");
1059
1060         uint8_t count = numToInt( &arg1Ptr[0] );
1061         // Default to 2 idles
1062         if ( count == 0 )
1063                 count = 2;
1064
1065         Connect_send_Idle( count );
1066 }
1067
1068 void cliFunc_connectLst( char* args )
1069 {
1070         const char *Command_strs[] = {
1071                 "CableCheck",
1072                 "IdRequest",
1073                 "IdEnumeration",
1074                 "IdReport",
1075                 "ScanCode",
1076                 "Animation",
1077                 "RemoteCapability",
1078                 "RemoteOutput",
1079                 "RemoteInput",
1080         };
1081
1082         print( NL );
1083         info_msg("List of UARTConnect commands");
1084         for ( uint8_t cmd = 0; cmd < Command_TOP; cmd++ )
1085         {
1086                 print( NL );
1087                 printInt8( cmd );
1088                 print(" - ");
1089                 dPrint( (char*)Command_strs[ cmd ] );
1090         }
1091 }
1092
1093 void cliFunc_connectMst( char* args )
1094 {
1095         // Parse number from argument
1096         //  NOTE: Only first argument is used
1097         char* arg1Ptr;
1098         char* arg2Ptr;
1099         CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
1100
1101         print( NL );
1102
1103         // Set override
1104         Connect_override = 1;
1105
1106         switch ( arg1Ptr[0] )
1107         {
1108         // Disable override
1109         case 'd':
1110         case 'D':
1111                 Connect_override = 0;
1112         case 's':
1113         case 'S':
1114                 info_msg("Setting device as slave.");
1115                 Connect_master = 0;
1116                 Connect_id = 0xFF;
1117                 break;
1118
1119         case 'm':
1120         case 'M':
1121         default:
1122                 info_msg("Setting device as master.");
1123                 Connect_master = 1;
1124                 Connect_id = 0;
1125                 break;
1126         }
1127 }
1128
1129 void cliFunc_connectRst( char* args )
1130 {
1131         print( NL );
1132         info_msg("Resetting UARTConnect state...");
1133         Connect_reset();
1134
1135         // Reset node id
1136         Connect_id = 0xFF;
1137 }
1138
1139 void cliFunc_connectSts( char* args )
1140 {
1141         print( NL );
1142         info_msg("UARTConnect Status");
1143         print( NL "Device Type:\t" );
1144         print( Connect_master ? "Master" : "Slave" );
1145         print( NL "Device Id:\t" );
1146         printHex( Connect_id );
1147         print( NL "Max Id:\t" );
1148         printHex( Connect_maxId );
1149         print( NL "Master <=" NL "\tStatus:\t");
1150         printHex( Connect_cableOkMaster );
1151         print( NL "\tFaults:\t");
1152         printHex32( Connect_cableFaultsMaster );
1153         print("/");
1154         printHex32( Connect_cableChecksMaster );
1155         print( NL "\tRx:\t");
1156         printHex( uart1_rx_status );
1157         print( NL "\tTx:\t");
1158         printHex( uart1_tx_status );
1159         print( NL "Slave <=" NL "\tStatus:\t");
1160         printHex( Connect_cableOkSlave );
1161         print( NL "\tFaults:\t");
1162         printHex32( Connect_cableFaultsSlave );
1163         print("/");
1164         printHex32( Connect_cableChecksSlave );
1165         print( NL "\tRx:\t");
1166         printHex( uart0_rx_status );
1167         print( NL "\tTx:\t");
1168         printHex( uart0_tx_status );
1169 }
1170