1 /* Copyright (C) 2014-2015 by Jacob Alexander
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.
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.
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/>.
17 // ----- Includes -----
20 #include <Lib/ScanLib.h>
29 #include "connect_scan.h"
35 // Macro for adding to each uart Tx ring buffer
36 #define uart_addTxBuffer( uartNum ) \
38 while ( uart##uartNum##_buffer_items + count > uart_buffer_size ) \
40 warn_msg("Too much data to send on UART0, waiting..."); \
43 for ( uint8_t c = 0; c < count; c++ ) \
45 printHex( buffer[ c ] ); \
46 print( " +" #uartNum NL ); \
47 uart##uartNum##_buffer[ uart##uartNum##_buffer_tail++ ] = buffer[ c ]; \
48 uart##uartNum##_buffer_items++; \
49 if ( uart##uartNum##_buffer_tail >= uart_buffer_size ) \
50 uart##uartNum##_buffer_tail = 0; \
51 if ( uart##uartNum##_buffer_head == uart##uartNum##_buffer_tail ) \
52 uart##uartNum##_buffer_head++; \
53 if ( uart##uartNum##_buffer_head >= uart_buffer_size ) \
54 uart##uartNum##_buffer_head = 0; \
58 // Macro for popping from Tx ring buffer
59 #define uart_fillTxFifo( uartNum ) \
61 uint8_t fifoSize = ( ( UART##uartNum##_PFIFO & UART_PFIFO_TXFIFOSIZE ) >> 2 ); \
62 if ( fifoSize == 0 ) \
64 while ( UART##uartNum##_TCFIFO < fifoSize ) \
66 if ( uart##uartNum##_buffer_items == 0 ) \
68 UART##uartNum##_D = uart##uartNum##_buffer[ uart##uartNum##_buffer_head++ ]; \
69 uart##uartNum##_buffer_items--; \
70 if ( uart##uartNum##_buffer_head >= uart_buffer_size ) \
71 uart##uartNum##_buffer_head = 0; \
75 // Macro for processing UART Rx
76 #define uart_processRx( uartNum ) \
78 if ( !( UART##uartNum##_S1 & UART_S1_RDRF ) ) \
80 uint8_t available = UART##uartNum##_RCFIFO; \
81 if ( available == 0 ) \
83 available = UART##uartNum##_D; \
84 UART##uartNum##_CFIFO = UART_CFIFO_RXFLUSH; \
87 while ( available-- > 0 ) \
89 uint8_t byteRead = UART##uartNum##_D; \
90 printHex( byteRead ); \
92 printInt8( available ); \
94 switch ( uart##uartNum##_rx_status ) \
96 case UARTStatus_Wait: \
98 uart##uartNum##_rx_status = byteRead == 0x16 ? UARTStatus_SYN : UARTStatus_Wait; \
100 case UARTStatus_SYN: \
102 uart##uartNum##_rx_status = byteRead == 0x01 ? UARTStatus_SOH : UARTStatus_Wait; \
104 case UARTStatus_SOH: \
107 uint8_t byte = byteRead; \
108 if ( byte <= Animation ) \
110 uart##uartNum##_rx_status = UARTStatus_Command; \
111 uart##uartNum##_rx_command = byte; \
112 uart##uartNum##_rx_bytes_waiting = 0xFFFF; \
116 uart##uartNum##_rx_status = UARTStatus_Wait; \
118 switch ( uart##uartNum##_rx_command ) \
121 Connect_receive_IdRequest( 0, (uint16_t*)&uart##uartNum##_rx_bytes_waiting, uartNum ); \
122 uart##uartNum##_rx_status = UARTStatus_Wait; \
130 case UARTStatus_Command: \
133 uint8_t (*rcvFunc)(uint8_t, uint16_t(*), uint8_t) = (uint8_t(*)(uint8_t, uint16_t(*), uint8_t))(Connect_receiveFunctions[ uart##uartNum##_rx_command ]); \
134 if ( rcvFunc( byteRead, (uint16_t*)&uart##uartNum##_rx_bytes_waiting, uartNum ) ) \
135 uart##uartNum##_rx_status = UARTStatus_Wait; \
139 erro_msg("Invalid UARTStatus..."); \
140 uart##uartNum##_rx_status = UARTStatus_Wait; \
148 // Macros for locking/unlock Tx buffers
149 #define uart_lockTx( uartNum ) \
151 while ( uart##uartNum##_tx_status == UARTStatus_Wait ); \
152 uart##uartNum##_tx_status = UARTStatus_Wait; \
155 #define uart_unlockTx( uartNum ) \
157 uart##uartNum##_tx_status = UARTStatus_Ready; \
162 // ----- Function Declarations -----
165 void cliFunc_connectCmd ( char *args );
166 void cliFunc_connectIdl ( char *args );
167 void cliFunc_connectMst ( char *args );
168 void cliFunc_connectRst ( char *args );
169 void cliFunc_connectSts ( char *args );
173 // ----- Variables -----
175 // Connect Module command dictionary
176 CLIDict_Entry( connectCmd, "Sends a command via UART Connect, first arg is which uart, next arg is the command, rest are the arguments." );
177 CLIDict_Entry( connectIdl, "Sends N number of Idle commands, 2 is the default value, and should be sufficient in most cases." );
178 CLIDict_Entry( connectMst, "Sets the device as master. Use argument of s to set as slave." );
179 CLIDict_Entry( connectRst, "Resets both Rx and Tx connect buffers and state variables." );
180 CLIDict_Entry( connectSts, "UARTConnect status." );
181 CLIDict_Def( uartConnectCLIDict, "UARTConnect Module Commands" ) = {
182 CLIDict_Item( connectCmd ),
183 CLIDict_Item( connectIdl ),
184 CLIDict_Item( connectMst ),
185 CLIDict_Item( connectRst ),
186 CLIDict_Item( connectSts ),
187 { 0, 0, 0 } // Null entry for dictionary end
191 // -- Connect Device Id Variables --
192 uint8_t Connect_id = 255; // Invalid, unset
193 uint8_t Connect_master = 0;
196 // -- Rx Status Variables --
198 volatile UARTStatus uart0_rx_status;
199 volatile UARTStatus uart1_rx_status;
200 volatile uint16_t uart0_rx_bytes_waiting;
201 volatile uint16_t uart1_rx_bytes_waiting;
202 volatile Command uart0_rx_command;
203 volatile Command uart1_rx_command;
206 // -- Tx Status Variables --
208 volatile UARTStatus uart0_tx_status;
209 volatile UARTStatus uart1_tx_status;
212 // -- Ring Buffer Variables --
214 #define uart_buffer_size UARTConnectBufSize_define
215 volatile uint8_t uart0_buffer_head;
216 volatile uint8_t uart0_buffer_tail;
217 volatile uint8_t uart0_buffer_items;
218 volatile uint8_t uart0_buffer[uart_buffer_size];
219 volatile uint8_t uart1_buffer_head;
220 volatile uint8_t uart1_buffer_tail;
221 volatile uint8_t uart1_buffer_items;
222 volatile uint8_t uart1_buffer[uart_buffer_size];
224 volatile uint8_t uarts_configured = 0;
227 // -- Ring Buffer Convenience Functions --
229 void Connect_addBytes( uint8_t *buffer, uint8_t count, uint8_t uart )
231 // Too big to fit into buffer
232 if ( count > uart_buffer_size )
234 erro_msg("Too big of a command to fit into the buffer...");
241 uart_addTxBuffer( 0 );
242 uart_addTxBuffer( 1 );
244 erro_msg("Invalid UART to send from...");
250 // -- Connect send functions --
252 // patternLen defines how many bytes should the incrementing pattern have
253 void Connect_send_CableCheck( uint8_t patternLen )
255 // Wait until the Tx buffers are ready, then lock them
260 uint8_t header[] = { 0x16, 0x01, CableCheck, patternLen };
263 Connect_addBytes( header, sizeof( header ), 1 ); // Master
264 Connect_addBytes( header, sizeof( header ), 0 ); // Slave
266 // Send 0xD2 (11010010) for each argument
267 uint8_t value = 0xD2;
268 for ( uint8_t c = 0; c < patternLen; c++ )
270 Connect_addBytes( &value, 1, 1 ); // Master
271 Connect_addBytes( &value, 1, 0 ); // Slave
274 // Release Tx buffers
279 void Connect_send_IdRequest()
281 // Lock master bound Tx
285 uint8_t header[] = { 0x16, 0x01, IdRequest };
288 Connect_addBytes( header, sizeof( header ), 1 ); // Master
294 // id is the value the next slave should enumerate as
295 void Connect_send_IdEnumeration( uint8_t id )
297 // Lock slave bound Tx
301 uint8_t header[] = { 0x16, 0x01, IdEnumeration, id };
304 Connect_addBytes( header, sizeof( header ), 0 ); // Slave
310 // id is the currently assigned id to the slave
311 void Connect_send_IdReport( uint8_t id )
313 // Lock master bound Tx
317 uint8_t header[] = { 0x16, 0x01, IdReport, id };
320 Connect_addBytes( header, sizeof( header ), 1 ); // Master
326 // id is the currently assigned id to the slave
327 // scanCodeStateList is an array of [scancode, state]'s (8 bit values)
328 // numScanCodes is the number of scan codes to parse from array
329 void Connect_send_ScanCode( uint8_t id, TriggerGuide *scanCodeStateList, uint8_t numScanCodes )
331 // Lock master bound Tx
335 uint8_t header[] = { 0x16, 0x01, ScanCode, id, numScanCodes };
338 Connect_addBytes( header, sizeof( header ), 1 ); // Master
340 // Send each of the scan codes
341 Connect_addBytes( (uint8_t*)scanCodeStateList, numScanCodes * TriggerGuideSize, 1 ); // Master
347 // id is the currently assigned id to the slave
348 // paramList is an array of [param, value]'s (8 bit values)
349 // numParams is the number of params to parse from the array
350 void Connect_send_Animation( uint8_t id, uint8_t *paramList, uint8_t numParams )
352 // Lock slave bound Tx
356 uint8_t header[] = { 0x16, 0x01, Animation, id, numParams };
359 Connect_addBytes( header, sizeof( header ), 0 ); // Slave
361 // Send each of the scan codes
362 Connect_addBytes( paramList, numParams, 0 ); // Slave
368 void Connect_send_Idle( uint8_t num )
370 // Wait until the Tx buffers are ready, then lock them
374 // Send n number of idles to reset link status (if in a bad state)
375 uint8_t value = 0x16;
376 for ( uint8_t c = 0; c < num; c++ )
378 Connect_addBytes( &value, 1, 1 ); // Master
379 Connect_addBytes( &value, 1, 0 ); // Slave
382 // Release Tx buffers
388 // -- Connect receive functions --
390 // - Cable Check variables -
391 uint32_t Connect_cableFaultsMaster = 0;
392 uint32_t Connect_cableFaultsSlave = 0;
393 uint8_t Connect_cableOkMaster = 0;
394 uint8_t Connect_cableOkSlave = 0;
396 uint8_t Connect_receive_CableCheck( uint8_t byte, uint16_t *pending_bytes, uint8_t to_master )
398 // Check if this is the first byte
399 if ( *pending_bytes == 0xFFFF )
401 dbug_msg("PENDING SET -> ");
404 *pending_bytes = byte;
405 printHex( *pending_bytes );
413 // The argument bytes are always 0xD2 (11010010)
416 warn_print("Cable Fault!");
418 // Check which side of the chain
421 Connect_cableFaultsMaster++;
422 Connect_cableOkMaster = 0;
427 Connect_cableFaultsSlave++;
428 Connect_cableOkSlave = 0;
434 // Signal that the command should wait for a SYN again
439 // If cable check was successful, set cable ok
440 if ( *pending_bytes == 0 )
444 Connect_cableOkMaster = 1;
448 Connect_cableOkSlave = 1;
451 dbug_msg("CABLECHECK RECEIVE - ");
454 printHex( *pending_bytes );
457 // Check whether the cable check has finished
458 return *pending_bytes == 0 ? 1 : 0;
461 uint8_t Connect_receive_IdRequest( uint8_t byte, uint16_t *pending_bytes, uint8_t to_master )
463 dbug_print("IdRequest");
464 // Check the directionality
467 erro_print("Invalid IdRequest direction...");
470 // Check if master, begin IdEnumeration
471 if ( Connect_master )
473 // The first device is always id 1
474 // Id 0 is reserved for the master
475 Connect_send_IdEnumeration( 1 );
477 // Propagate IdRequest
480 Connect_send_IdRequest();
486 uint8_t Connect_receive_IdEnumeration( uint8_t id, uint16_t *pending_bytes, uint8_t to_master )
488 dbug_print("IdEnumeration");
489 // Check the directionality
492 erro_print("Invalid IdEnumeration direction...");
498 // Send reponse back to master
499 Connect_send_IdReport( id );
501 // Propogate next Id if the connection is ok
502 if ( Connect_cableOkSlave )
504 Connect_send_IdEnumeration( id + 1 );
510 uint8_t Connect_receive_IdReport( uint8_t id, uint16_t *pending_bytes, uint8_t to_master )
512 dbug_print("IdReport");
513 // Check the directionality
516 erro_print("Invalid IdRequest direction...");
519 // Track Id response if master
520 if ( Connect_master )
523 info_msg("Id Reported: ");
528 // Propagate id if yet another slave
531 Connect_send_IdReport( id );
537 // - Scan Code Variables -
538 TriggerGuide Connect_receive_ScanCodeBuffer;
539 uint8_t Connect_receive_ScanCodeBufferPos;
540 uint8_t Connect_receive_ScanCodeDeviceId;
542 uint8_t Connect_receive_ScanCode( uint8_t byte, uint16_t *pending_bytes, uint8_t to_master )
544 dbug_print("ScanCode");
545 // Check the directionality
548 erro_print("Invalid ScanCode direction...");
551 // Master node, trigger scan codes
552 if ( Connect_master ) switch ( (*pending_bytes)-- )
554 case 0xFFFF: // Device Id
555 Connect_receive_ScanCodeDeviceId = byte;
558 case 0xFFFE: // Number of TriggerGuides in bytes (byte * 3)
559 *pending_bytes = byte * 3;
560 Connect_receive_ScanCodeBufferPos = 0;
564 // Set the specific TriggerGuide entry
565 ((uint8_t*)&Connect_receive_ScanCodeBuffer)[ Connect_receive_ScanCodeBufferPos++ ] = byte;
567 // Reset the BufferPos if higher than 3
568 // And send the TriggerGuide to the Macro Module
569 if ( Connect_receive_ScanCodeBufferPos > 3 )
571 Connect_receive_ScanCodeBufferPos = 0;
572 Macro_triggerState( &Connect_receive_ScanCodeBuffer, 1 );
577 // Propagate ScanCode packet
578 else switch ( (*pending_bytes)-- )
580 case 0xFFFF: // Device Id
582 Connect_receive_ScanCodeDeviceId = byte;
584 // Lock the master Tx buffer
587 // Send header + Id byte
588 uint8_t header[] = { 0x16, 0x01, ScanCode, byte };
589 Connect_addBytes( header, sizeof( header ), 1 ); // Master
592 case 0xFFFE: // Number of TriggerGuides in bytes (byte * 3)
593 *pending_bytes = byte * 3;
594 Connect_receive_ScanCodeBufferPos = 0;
597 Connect_addBytes( &byte, 1, 1 ); // Master
602 Connect_addBytes( &byte, 1, 1 ); // Master
604 // Unlock Tx Buffer after sending last byte
605 if ( *pending_bytes == 0 )
610 // Check whether the scan codes have finished sending
611 return *pending_bytes == 0 ? 1 : 0;
614 uint8_t Connect_receive_Animation( uint8_t byte, uint16_t *pending_bytes, uint8_t to_master )
616 dbug_print("Animation");
622 // NOTE: If finer baud adjustment is needed see UARTx_C4 -> BRFA in the datasheet
623 uint16_t Connect_baud = UARTConnectBaud_define; // Max setting of 8191
624 uint16_t Connect_baudFine = UARTConnectBaudFine_define;
626 // Connect receive function lookup
627 void *Connect_receiveFunctions[] = {
628 Connect_receive_CableCheck,
629 Connect_receive_IdRequest,
630 Connect_receive_IdEnumeration,
631 Connect_receive_IdReport,
632 Connect_receive_ScanCode,
633 Connect_receive_Animation,
638 // ----- Interrupt Functions -----
640 // Master / UART0 ISR
641 void uart0_status_isr()
648 void uart1_status_isr()
656 // ----- Functions -----
658 // Resets the state of the UART buffers and state variables
661 // Rx Status Variables
662 uart0_rx_status = UARTStatus_Wait;
663 uart1_rx_status = UARTStatus_Wait;
664 uart0_rx_bytes_waiting = 0;
665 uart1_rx_bytes_waiting = 0;
667 // Tx Status Variables
668 uart0_tx_status = UARTStatus_Ready;
669 uart1_tx_status = UARTStatus_Ready;
671 // Ring Buffer Variables
672 uart0_buffer_head = 0;
673 uart0_buffer_tail = 0;
674 uart0_buffer_items = 0;
675 uart1_buffer_head = 0;
676 uart1_buffer_tail = 0;
677 uart1_buffer_items = 0;
681 // Setup connection to other side
682 // - Only supports a single slave and master
683 // - If USB has been initiallized at this point, this side is the master
684 // - If both sides assert master, flash error leds
685 void Connect_setup( uint8_t master )
687 // Indication that UARTs are not ready
688 uarts_configured = 0;
690 // Register Connect CLI dictionary
691 CLI_registerDictionary( uartConnectCLIDict, uartConnectCLIDictName );
693 Connect_master = master;
695 // Master / UART0 setup
696 // Slave / UART1 setup
697 // Setup the the UART interface for keyboard data input
698 SIM_SCGC4 |= SIM_SCGC4_UART0; // Disable clock gating
699 SIM_SCGC4 |= SIM_SCGC4_UART1; // Disable clock gating
701 // Pin Setup for UART0 / UART1
702 // XXX TODO Set to actual (Teensy 3.1s don't have the correct pins available)
703 PORTB_PCR16 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); // RX Pin
704 PORTB_PCR17 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); // TX Pin
705 PORTC_PCR3 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); // RX Pin
706 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); // TX Pin
707 //PORTA_PCR1 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(2); // RX Pin
708 //PORTA_PCR2 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(2); // TX Pin
709 //PORTE_PCR0 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); // RX Pin
710 //PORTE_PCR1 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); // TX Pin
713 UART0_BDH = (uint8_t)(Connect_baud >> 8);
714 UART0_BDL = (uint8_t)Connect_baud;
715 UART0_C4 = Connect_baudFine;
716 UART1_BDH = (uint8_t)(Connect_baud >> 8);
717 UART1_BDL = (uint8_t)Connect_baud;
718 UART1_C4 = Connect_baudFine;
720 // 8 bit, Even Parity, Idle Character bit after stop
721 // NOTE: For 8 bit with Parity you must enable 9 bit transmission (pg. 1065)
722 // You only need to use UART0_D for 8 bit reading/writing though
723 // UART_C1_M UART_C1_PE UART_C1_PT UART_C1_ILT
724 UART0_C1 = UART_C1_M | UART_C1_PE | UART_C1_ILT;
725 UART1_C1 = UART_C1_M | UART_C1_PE | UART_C1_ILT;
727 // Number of bytes in FIFO before TX Interrupt
732 // Number of bytes in FIFO before RX Interrupt
736 // Enable TX and RX FIFOs
737 UART0_PFIFO = UART_PFIFO_TXFE | UART_PFIFO_RXFE;
738 UART1_PFIFO = UART_PFIFO_TXFE | UART_PFIFO_RXFE;
740 // Reciever Inversion Disabled, LSBF
741 // UART_S2_RXINV UART_S2_MSBF
745 // Transmit Inversion Disabled
750 // TX Enabled, RX Enabled, RX Interrupt Enabled
751 // UART_C2_TE UART_C2_RE UART_C2_RIE
752 UART0_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE;
753 UART1_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE;
755 // Add interrupts to the vector table
756 NVIC_ENABLE_IRQ( IRQ_UART0_STATUS );
757 NVIC_ENABLE_IRQ( IRQ_UART1_STATUS );
759 // UARTs are now ready to go
760 uarts_configured = 1;
762 // Reset the state of the UART variables
767 // Scan for updates in the master/slave
768 // - Interrupts will deal with most input functions
769 // - Used to send queries
770 // - SyncEvent is sent immediately once the current command is sent
771 // - SyncEvent is also blocking until sent
774 // Check if Tx Buffers are empty and the Tx Ring buffers have data to send
775 // This happens if there was previously nothing to send
776 if ( uart0_buffer_items > 0 && UART0_TCFIFO == 0 )
777 uart_fillTxFifo( 0 );
778 if ( uart1_buffer_items > 0 && UART1_TCFIFO == 0 )
779 uart_fillTxFifo( 1 );
784 // ----- CLI Command Functions -----
786 void cliFunc_connectCmd( char* args )
788 // Parse number from argument
789 // NOTE: Only first argument is used
792 CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
796 switch ( numToInt( &arg1Ptr[0] ) )
799 Connect_send_CableCheck( 2 );
803 Connect_send_IdRequest();
807 Connect_send_IdEnumeration( 5 );
811 Connect_send_IdReport( 8 );
816 TriggerGuide scanCodes[] = { { 0x00, 0x01, 0x05 }, { 0x00, 0x03, 0x16 } };
817 Connect_send_ScanCode( 10, scanCodes, 2 );
826 void cliFunc_connectIdl( char* args )
828 // Parse number from argument
829 // NOTE: Only first argument is used
832 CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
835 info_msg("Sending Sync Idles...");
837 uint8_t count = numToInt( &arg1Ptr[0] );
838 // Default to 2 idles
842 Connect_send_Idle( count );
845 void cliFunc_connectMst( char* args )
847 // Parse number from argument
848 // NOTE: Only first argument is used
851 CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
855 switch ( arg1Ptr[0] )
859 info_msg("Setting device as slave.");
867 info_msg("Setting device as master.");
874 void cliFunc_connectRst( char* args )
877 info_msg("Resetting UARTConnect state...");
880 // TODO - Argument for re-sync
883 void cliFunc_connectSts( char* args )
886 info_msg("UARTConnect Status");
887 print( NL "Device Type:\t" );
888 print( Connect_master ? "Master" : "Slave" );
889 print( NL "Device Id:\t" );
890 printHex( Connect_id );
891 print( NL "Master <=" NL "\tStatus:\t");
892 printHex( Connect_cableOkMaster );
893 print( NL "\tFaults:\t");
894 printHex( Connect_cableFaultsMaster );
895 print( NL "\tRx:\t");
896 printHex( uart1_rx_status );
897 print( NL "\tTx:\t");
898 printHex( uart1_tx_status );
899 print( NL "Slave <=" NL "\tStatus:\t");
900 printHex( Connect_cableOkSlave );
901 print( NL "\tFaults:\t");
902 printHex( Connect_cableFaultsSlave );
903 print( NL "\tRx:\t");
904 printHex( uart0_rx_status );
905 print( NL "\tTx:\t");
906 printHex( uart0_tx_status );