1 /* Copyright (C) 2014-2016 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>
30 #include "connect_scan.h"
34 // ----- Defines -----
36 #define UART_Num_Interfaces 2
39 #define UART_Buffer_Size UARTConnectBufSize_define
45 // Macro for popping from Tx ring buffer
46 #define uart_fillTxFifo( uartNum ) \
48 uint8_t fifoSize = ( ( UART##uartNum##_PFIFO & UART_PFIFO_TXFIFOSIZE ) >> 2 ); \
49 if ( fifoSize == 0 ) \
51 if ( Connect_debug ) \
53 print( "TxFIFO " #uartNum " - " ); \
54 printHex( fifoSize ); \
56 printHex( UART##uartNum##_TCFIFO ); \
58 printHex( uart_tx_buf[ uartNum ].items ); \
61 /* XXX Doesn't work well */ \
62 /* while ( UART##uartNum##_TCFIFO < fifoSize ) */ \
63 /* More reliable, albeit slower */ \
64 fifoSize -= UART##uartNum##_TCFIFO; \
65 while ( fifoSize-- != 0 ) \
67 if ( uart_tx_buf[ uartNum ].items == 0 ) \
69 UART##uartNum##_D = uart_tx_buf[ uartNum ].buffer[ uart_tx_buf[ uartNum ].head++ ]; \
70 uart_tx_buf[ uartNum ].items--; \
71 if ( uart_tx_buf[ uartNum ].head >= UART_Buffer_Size ) \
72 uart_tx_buf[ uartNum ].head = 0; \
76 // Macros for locking/unlock Tx buffers
77 #define uart_lockTx( uartNum ) \
79 /* First, secure place in line for the resource */ \
80 while ( uart_tx_status[ uartNum ].lock ); \
81 uart_tx_status[ uartNum ].lock = 1; \
82 /* Next, wait unit the UART is ready */ \
83 while ( uart_tx_status[ uartNum ].status != UARTStatus_Ready ); \
84 uart_tx_status[ uartNum ].status = UARTStatus_Wait; \
87 #define uart_lockBothTx( uartNum1, uartNum2 ) \
89 /* First, secure place in line for the resource */ \
90 while ( uart_tx_status[ uartNum1 ].lock || uart_tx_status[ uartNum2 ].lock ); \
91 uart_tx_status[ uartNum1 ].lock = 1; \
92 uart_tx_status[ uartNum2 ].lock = 1; \
93 /* Next, wait unit the UARTs are ready */ \
94 while ( uart_tx_status[ uartNum1 ].status != UARTStatus_Ready || uart_tx_status[ uartNum2 ].status != UARTStatus_Ready ); \
95 uart_tx_status[ uartNum1 ].status = UARTStatus_Wait; \
96 uart_tx_status[ uartNum2 ].status = UARTStatus_Wait; \
99 #define uart_unlockTx( uartNum ) \
101 /* Ready the UART */ \
102 uart_tx_status[ uartNum ].status = UARTStatus_Ready; \
103 /* Unlock the resource */ \
104 uart_tx_status[ uartNum ].lock = 0; \
109 // ----- Function Declarations -----
112 void cliFunc_connectCmd ( char *args );
113 void cliFunc_connectDbg ( char *args );
114 void cliFunc_connectIdl ( char *args );
115 void cliFunc_connectLst ( char *args );
116 void cliFunc_connectMst ( char *args );
117 void cliFunc_connectRst ( char *args );
118 void cliFunc_connectSts ( char *args );
122 // ----- Structs -----
124 typedef struct UARTRingBuf {
128 uint8_t buffer[UART_Buffer_Size];
131 typedef struct UARTDMABuf {
132 uint8_t buffer[UART_Buffer_Size];
136 typedef struct UARTStatusRx {
139 uint16_t bytes_waiting;
142 typedef struct UARTStatusTx {
149 // ----- Variables -----
151 // Connect Module command dictionary
152 CLIDict_Entry( connectCmd, "Sends a command via UART Connect, first arg is which uart, next arg is the command, rest are the arguments." );
153 CLIDict_Entry( connectDbg, "Toggle UARTConnect debug mode." );
154 CLIDict_Entry( connectIdl, "Sends N number of Idle commands, 2 is the default value, and should be sufficient in most cases." );
155 CLIDict_Entry( connectLst, "Lists available UARTConnect commands and index id" );
156 CLIDict_Entry( connectMst, "Sets the device as master. Use argument of s to set as slave." );
157 CLIDict_Entry( connectRst, "Resets both Rx and Tx connect buffers and state variables." );
158 CLIDict_Entry( connectSts, "UARTConnect status." );
159 CLIDict_Def( uartConnectCLIDict, "UARTConnect Module Commands" ) = {
160 CLIDict_Item( connectCmd ),
161 CLIDict_Item( connectDbg ),
162 CLIDict_Item( connectIdl ),
163 CLIDict_Item( connectLst ),
164 CLIDict_Item( connectMst ),
165 CLIDict_Item( connectRst ),
166 CLIDict_Item( connectSts ),
167 { 0, 0, 0 } // Null entry for dictionary end
171 // -- Connect Device Id Variables --
172 uint8_t Connect_id = 255; // Invalid, unset
173 uint8_t Connect_master = 0;
174 uint8_t Connect_maxId = 0;
177 // -- Control Variables --
178 uint32_t Connect_lastCheck = 0; // Cable Check scheduler
179 uint8_t Connect_debug = 0; // Set 1 for debug
180 uint8_t Connect_override = 0; // Prevents master from automatically being set
182 volatile uint8_t uarts_configured = 0;
185 // -- Rx Variables --
187 volatile UARTDMABuf uart_rx_buf[UART_Num_Interfaces];
188 volatile UARTStatusRx uart_rx_status[UART_Num_Interfaces];
191 // -- Tx Variables --
193 UARTRingBuf uart_tx_buf [UART_Num_Interfaces];
194 UARTStatusTx uart_tx_status[UART_Num_Interfaces];
197 // -- Ring Buffer Convenience Functions --
199 void Connect_addBytes( uint8_t *buffer, uint8_t count, uint8_t uart )
201 // Too big to fit into buffer
202 if ( count > UART_Buffer_Size )
204 erro_msg("Too big of a command to fit into the buffer...");
209 if ( uart >= UART_Num_Interfaces )
211 erro_print("Invalid UART to send from...");
215 // Delay UART copy until there's some space left
216 while ( uart_tx_buf[ uart ].items + count > UART_Buffer_Size )
218 warn_msg("Too much data to send on UART");
220 print( ", waiting..." NL );
224 // Append data to ring buffer
225 for ( uint8_t c = 0; c < count; c++ )
229 printHex( buffer[ c ] );
235 uart_tx_buf[ uart ].buffer[ uart_tx_buf[ uart ].tail++ ] = buffer[ c ];
236 uart_tx_buf[ uart ].items++;
237 if ( uart_tx_buf[ uart ].tail >= UART_Buffer_Size )
238 uart_tx_buf[ uart ].tail = 0;
239 if ( uart_tx_buf[ uart ].head == uart_tx_buf[ uart ].tail )
240 uart_tx_buf[ uart ].head++;
241 if ( uart_tx_buf[ uart ].head >= UART_Buffer_Size )
242 uart_tx_buf[ uart ].head = 0;
247 // -- Connect send functions --
249 // patternLen defines how many bytes should the incrementing pattern have
250 void Connect_send_CableCheck( uint8_t patternLen )
252 // Wait until the Tx buffers are ready, then lock them
253 uart_lockBothTx( UART_Master, UART_Slave );
256 uint8_t header[] = { 0x16, 0x01, CableCheck, patternLen };
259 Connect_addBytes( header, sizeof( header ), UART_Master );
260 Connect_addBytes( header, sizeof( header ), UART_Slave );
262 // Send 0xD2 (11010010) for each argument
263 uint8_t value = 0xD2;
264 for ( uint8_t c = 0; c < patternLen; c++ )
266 Connect_addBytes( &value, 1, UART_Master );
267 Connect_addBytes( &value, 1, UART_Slave );
270 // Release Tx buffers
271 uart_unlockTx( UART_Master );
272 uart_unlockTx( UART_Slave );
275 void Connect_send_IdRequest()
277 // Lock master bound Tx
278 uart_lockTx( UART_Master );
281 uint8_t header[] = { 0x16, 0x01, IdRequest };
284 Connect_addBytes( header, sizeof( header ), UART_Master );
287 uart_unlockTx( UART_Master );
290 // id is the value the next slave should enumerate as
291 void Connect_send_IdEnumeration( uint8_t id )
293 // Lock slave bound Tx
294 uart_lockTx( UART_Slave );
297 uint8_t header[] = { 0x16, 0x01, IdEnumeration, id };
300 Connect_addBytes( header, sizeof( header ), UART_Slave );
303 uart_unlockTx( UART_Slave );
306 // id is the currently assigned id to the slave
307 void Connect_send_IdReport( uint8_t id )
309 // Lock master bound Tx
310 uart_lockTx( UART_Master );
313 uint8_t header[] = { 0x16, 0x01, IdReport, id };
316 Connect_addBytes( header, sizeof( header ), UART_Master );
319 uart_unlockTx( UART_Master );
322 // id is the currently assigned id to the slave
323 // scanCodeStateList is an array of [scancode, state]'s (8 bit values)
324 // numScanCodes is the number of scan codes to parse from array
325 void Connect_send_ScanCode( uint8_t id, TriggerGuide *scanCodeStateList, uint8_t numScanCodes )
327 // Lock master bound Tx
328 uart_lockTx( UART_Master );
331 uint8_t header[] = { 0x16, 0x01, ScanCode, id, numScanCodes };
334 Connect_addBytes( header, sizeof( header ), UART_Master );
336 // Send each of the scan codes
337 Connect_addBytes( (uint8_t*)scanCodeStateList, numScanCodes * TriggerGuideSize, UART_Master );
340 uart_unlockTx( UART_Master );
343 // id is the currently assigned id to the slave
344 // paramList is an array of [param, value]'s (8 bit values)
345 // numParams is the number of params to parse from the array
346 void Connect_send_Animation( uint8_t id, uint8_t *paramList, uint8_t numParams )
348 // Lock slave bound Tx
349 uart_lockTx( UART_Slave );
352 uint8_t header[] = { 0x16, 0x01, Animation, id, numParams };
355 Connect_addBytes( header, sizeof( header ), UART_Slave );
357 // Send each of the scan codes
358 Connect_addBytes( paramList, numParams, UART_Slave );
361 uart_unlockTx( UART_Slave );
364 // Send a remote capability command using capability index
365 // This may not be what's expected (especially if the firmware is not the same on each node)
366 // To broadcast to all slave nodes, set id to 255 instead of a specific id
367 void Connect_send_RemoteCapability( uint8_t id, uint8_t capabilityIndex, uint8_t state, uint8_t stateType, uint8_t numArgs, uint8_t *args )
370 uint8_t header[] = { 0x16, 0x01, RemoteCapability, id, capabilityIndex, state, stateType, numArgs };
373 if ( id == Connect_id )
376 // Send towards slave node
377 if ( id > Connect_id )
379 // Lock slave bound Tx
380 uart_lockTx( UART_Slave );
383 Connect_addBytes( header, sizeof( header ), UART_Slave );
386 Connect_addBytes( args, numArgs, UART_Slave );
389 uart_unlockTx( UART_Slave );
392 // Send towards master node
393 if ( id < Connect_id || id == 255 )
395 // Lock slave bound Tx
396 uart_lockTx( UART_Master );
399 Connect_addBytes( header, sizeof( header ), UART_Master );
402 Connect_addBytes( args, numArgs, UART_Master );
405 uart_unlockTx( UART_Master );
409 void Connect_send_Idle( uint8_t num )
411 // Wait until the Tx buffers are ready, then lock them
412 uart_lockBothTx( UART_Slave, UART_Master );
414 // Send n number of idles to reset link status (if in a bad state)
415 uint8_t value = 0x16;
416 for ( uint8_t c = 0; c < num; c++ )
418 Connect_addBytes( &value, 1, UART_Master );
419 Connect_addBytes( &value, 1, UART_Slave );
422 // Release Tx buffers
423 uart_unlockTx( UART_Master );
424 uart_unlockTx( UART_Slave );
428 // -- Connect receive functions --
430 // - Cable Check variables -
431 uint32_t Connect_cableFaultsMaster = 0;
432 uint32_t Connect_cableFaultsSlave = 0;
433 uint32_t Connect_cableChecksMaster = 0;
434 uint32_t Connect_cableChecksSlave = 0;
435 uint8_t Connect_cableOkMaster = 0;
436 uint8_t Connect_cableOkSlave = 0;
438 uint8_t Connect_receive_CableCheck( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num )
440 // Check if this is the first byte
441 if ( *pending_bytes == 0xFFFF )
443 *pending_bytes = byte;
447 dbug_msg("PENDING SET -> ");
450 printHex( *pending_bytes );
459 // The argument bytes are always 0xD2 (11010010)
462 warn_print("Cable Fault!");
464 // Check which side of the chain
465 if ( uart_num == UART_Slave )
467 Connect_cableFaultsSlave++;
468 Connect_cableOkSlave = 0;
473 // Lower current requirement during errors
475 // Only if this is not the master node
476 if ( Connect_id != 0 )
478 Output_update_external_current( 100 );
481 Connect_cableFaultsMaster++;
482 Connect_cableOkMaster = 0;
488 // Signal that the command should wait for a SYN again
493 // Check which side of the chain
494 if ( uart_num == UART_Slave )
496 Connect_cableChecksSlave++;
500 // If we already have an Id, then set max current again
501 if ( Connect_id != 255 && Connect_id != 0 )
503 // TODO reset to original negotiated current
504 Output_update_external_current( 500 );
506 Connect_cableChecksMaster++;
511 // If cable check was successful, set cable ok
512 if ( *pending_bytes == 0 )
514 if ( uart_num == UART_Slave )
516 Connect_cableOkSlave = 1;
520 Connect_cableOkMaster = 1;
526 dbug_msg("CABLECHECK RECEIVE - ");
529 printHex( *pending_bytes );
533 // Check whether the cable check has finished
534 return *pending_bytes == 0 ? 1 : 0;
537 uint8_t Connect_receive_IdRequest( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num )
539 dbug_print("IdRequest");
540 // Check the directionality
541 if ( uart_num == UART_Master )
543 erro_print("Invalid IdRequest direction...");
546 // Check if master, begin IdEnumeration
547 if ( Connect_master )
549 // The first device is always id 1
550 // Id 0 is reserved for the master
551 Connect_send_IdEnumeration( 1 );
553 // Propagate IdRequest
556 Connect_send_IdRequest();
562 uint8_t Connect_receive_IdEnumeration( uint8_t id, uint16_t *pending_bytes, uint8_t uart_num )
564 dbug_print("IdEnumeration");
565 // Check the directionality
566 if ( uart_num == UART_Slave )
568 erro_print("Invalid IdEnumeration direction...");
574 // Send reponse back to master
575 Connect_send_IdReport( id );
577 // Node now enumerated, set external power to USB Max
578 // Only set if this is not the master node
579 // TODO Determine power slice for each node as part of protocol
580 if ( Connect_id != 0 )
582 Output_update_external_current( 500 );
585 // Propogate next Id if the connection is ok
586 if ( Connect_cableOkSlave )
588 Connect_send_IdEnumeration( id + 1 );
594 uint8_t Connect_receive_IdReport( uint8_t id, uint16_t *pending_bytes, uint8_t uart_num )
596 dbug_print("IdReport");
597 // Check the directionality
598 if ( uart_num == UART_Master )
600 erro_print("Invalid IdRequest direction...");
603 // Track Id response if master
604 if ( Connect_master )
606 info_msg("Id Reported: ");
610 // Check if this is the highest ID
611 if ( id > Connect_maxId )
615 // Propagate id if yet another slave
618 Connect_send_IdReport( id );
624 // - Scan Code Variables -
625 TriggerGuide Connect_receive_ScanCodeBuffer;
626 uint8_t Connect_receive_ScanCodeBufferPos;
627 uint8_t Connect_receive_ScanCodeDeviceId;
629 uint8_t Connect_receive_ScanCode( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num )
631 // Check the directionality
632 if ( uart_num == UART_Master )
634 erro_print("Invalid ScanCode direction...");
637 // Master node, trigger scan codes
638 if ( Connect_master ) switch ( (*pending_bytes)-- )
640 // Byte count always starts at 0xFFFF
641 case 0xFFFF: // Device Id
642 Connect_receive_ScanCodeDeviceId = byte;
645 case 0xFFFE: // Number of TriggerGuides in bytes (byte * 3)
646 *pending_bytes = byte * sizeof( TriggerGuide );
647 Connect_receive_ScanCodeBufferPos = 0;
651 // Set the specific TriggerGuide entry
652 ((uint8_t*)&Connect_receive_ScanCodeBuffer)[ Connect_receive_ScanCodeBufferPos++ ] = byte;
654 // Reset the BufferPos if higher than sizeof TriggerGuide
655 // And send the TriggerGuide to the Macro Module
656 if ( Connect_receive_ScanCodeBufferPos >= sizeof( TriggerGuide ) )
658 Connect_receive_ScanCodeBufferPos = 0;
660 // Adjust ScanCode offset
661 if ( Connect_receive_ScanCodeDeviceId > 0 )
663 // Check if this node is too large
664 if ( Connect_receive_ScanCodeDeviceId >= InterconnectNodeMax )
666 warn_msg("Not enough interconnect layout nodes configured: ");
667 printHex( Connect_receive_ScanCodeDeviceId );
672 // This variable is in generatedKeymaps.h
673 extern uint8_t InterconnectOffsetList[];
674 Connect_receive_ScanCodeBuffer.scanCode = Connect_receive_ScanCodeBuffer.scanCode + InterconnectOffsetList[ Connect_receive_ScanCodeDeviceId - 1 ];
677 // ScanCode receive debug
681 printHex( Connect_receive_ScanCodeBuffer.type );
683 printHex( Connect_receive_ScanCodeBuffer.state );
685 printHex( Connect_receive_ScanCodeBuffer.scanCode );
689 // Send ScanCode to macro module
690 Macro_interconnectAdd( &Connect_receive_ScanCodeBuffer );
695 // Propagate ScanCode packet
696 // XXX It would be safer to buffer the scancodes first, before transmitting the packet -Jacob
697 // The current method is the more efficient/aggressive, but could cause issues if there were errors during transmission
698 else switch ( (*pending_bytes)-- )
700 // Byte count always starts at 0xFFFF
701 case 0xFFFF: // Device Id
703 Connect_receive_ScanCodeDeviceId = byte;
705 // Lock the master Tx buffer
706 uart_lockTx( UART_Master );
708 // Send header + Id byte
709 uint8_t header[] = { 0x16, 0x01, ScanCode, byte };
710 Connect_addBytes( header, sizeof( header ), UART_Master );
713 case 0xFFFE: // Number of TriggerGuides in bytes
714 *pending_bytes = byte * sizeof( TriggerGuide );
715 Connect_receive_ScanCodeBufferPos = 0;
718 Connect_addBytes( &byte, 1, UART_Master );
723 Connect_addBytes( &byte, 1, UART_Master );
725 // Unlock Tx Buffer after sending last byte
726 if ( *pending_bytes == 0 )
727 uart_unlockTx( UART_Master );
731 // Check whether the scan codes have finished sending
732 return *pending_bytes == 0 ? 1 : 0;
735 uint8_t Connect_receive_Animation( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num )
737 dbug_print("Animation");
741 // - Remote Capability Variables -
742 #define Connect_receive_RemoteCapabilityMaxArgs 25 // XXX Calculate the max using kll
743 RemoteCapabilityCommand Connect_receive_RemoteCapabilityBuffer;
744 uint8_t Connect_receive_RemoteCapabilityArgs[Connect_receive_RemoteCapabilityMaxArgs];
746 uint8_t Connect_receive_RemoteCapability( uint8_t byte, uint16_t *pending_bytes, uint8_t uart_num )
748 // Check which byte in the packet we are at
749 switch ( (*pending_bytes)-- )
751 // Byte count always starts at 0xFFFF
752 case 0xFFFF: // Device Id
753 Connect_receive_RemoteCapabilityBuffer.id = byte;
756 case 0xFFFE: // Capability Index
757 Connect_receive_RemoteCapabilityBuffer.capabilityIndex = byte;
760 case 0xFFFD: // State
761 Connect_receive_RemoteCapabilityBuffer.state = byte;
764 case 0xFFFC: // StateType
765 Connect_receive_RemoteCapabilityBuffer.stateType = byte;
768 case 0xFFFB: // Number of args
769 Connect_receive_RemoteCapabilityBuffer.numArgs = byte;
770 *pending_bytes = byte;
773 default: // Args (# defined by previous byte)
774 Connect_receive_RemoteCapabilityArgs[
775 Connect_receive_RemoteCapabilityBuffer.numArgs - *pending_bytes + 1
778 // If entire packet has been fully received
779 if ( *pending_bytes == 0 )
781 // Determine if this is the node to run the capability on
782 // Conditions: Matches or broadcast (0xFF)
783 if ( Connect_receive_RemoteCapabilityBuffer.id == 0xFF
784 || Connect_receive_RemoteCapabilityBuffer.id == Connect_id )
786 extern const Capability CapabilitiesList[]; // See generatedKeymap.h
787 void (*capability)(uint8_t, uint8_t, uint8_t*) = (void(*)(uint8_t, uint8_t, uint8_t*))(
788 CapabilitiesList[ Connect_receive_RemoteCapabilityBuffer.capabilityIndex ].func
791 Connect_receive_RemoteCapabilityBuffer.state,
792 Connect_receive_RemoteCapabilityBuffer.stateType,
793 &Connect_receive_RemoteCapabilityArgs[2]
797 // If this is not the correct node, keep sending it in the same direction (doesn't matter if more nodes exist)
798 // or if this is a broadcast
799 if ( Connect_receive_RemoteCapabilityBuffer.id == 0xFF
800 || Connect_receive_RemoteCapabilityBuffer.id != Connect_id )
802 // Prepare outgoing packet
803 Connect_receive_RemoteCapabilityBuffer.command = RemoteCapability;
805 // Send to the other UART (not the one receiving the packet from
806 uint8_t uart_direction = uart_num == UART_Master ? UART_Slave : UART_Master;
809 switch ( uart_direction )
811 case UART_Master: uart_lockTx( UART_Master ); break;
812 case UART_Slave: uart_lockTx( UART_Slave ); break;
816 uint8_t header[] = { 0x16, 0x01 };
817 Connect_addBytes( header, sizeof( header ), uart_direction );
819 // Send Remote Capability and arguments
820 Connect_addBytes( (uint8_t*)&Connect_receive_RemoteCapabilityBuffer, sizeof( RemoteCapabilityCommand ), uart_direction );
821 Connect_addBytes( Connect_receive_RemoteCapabilityArgs, Connect_receive_RemoteCapabilityBuffer.numArgs, uart_direction );
824 switch ( uart_direction )
826 case UART_Master: uart_unlockTx( UART_Master ); break;
827 case UART_Slave: uart_unlockTx( UART_Slave ); break;
834 // Check whether the scan codes have finished sending
835 return *pending_bytes == 0 ? 1 : 0;
840 // NOTE: If finer baud adjustment is needed see UARTx_C4 -> BRFA in the datasheet
841 uint16_t Connect_baud = UARTConnectBaud_define; // Max setting of 8191
842 uint16_t Connect_baudFine = UARTConnectBaudFine_define;
844 // Connect receive function lookup
845 void *Connect_receiveFunctions[] = {
846 Connect_receive_CableCheck,
847 Connect_receive_IdRequest,
848 Connect_receive_IdEnumeration,
849 Connect_receive_IdReport,
850 Connect_receive_ScanCode,
851 Connect_receive_Animation,
852 Connect_receive_RemoteCapability,
857 // ----- Functions -----
859 // Resets the state of the UART buffers and state variables
863 memset( (void*)uart_rx_status, 0, sizeof( UARTStatusRx ) * UART_Num_Interfaces );
866 memset( (void*)uart_tx_buf, 0, sizeof( UARTRingBuf ) * UART_Num_Interfaces );
867 memset( (void*)uart_tx_status, 0, sizeof( UARTStatusTx ) * UART_Num_Interfaces );
869 // Set Rx/Tx buffers as ready
870 for ( uint8_t inter = 0; inter < UART_Num_Interfaces; inter++ )
872 uart_tx_status[ inter ].status = UARTStatus_Ready;
873 uart_rx_buf[ inter ].last_read = UART_Buffer_Size;
878 // Setup connection to other side
879 // - Only supports a single slave and master
880 // - If USB has been initiallized at this point, this side is the master
881 // - If both sides assert master, flash error leds
882 void Connect_setup( uint8_t master )
884 // Indication that UARTs are not ready
885 uarts_configured = 0;
887 // Register Connect CLI dictionary
888 CLI_registerDictionary( uartConnectCLIDict, uartConnectCLIDictName );
891 Connect_master = master;
892 if ( Connect_master )
893 Connect_id = 0; // 0x00 is always the master Id
897 // Setup the the UART interface for keyboard data input
898 SIM_SCGC4 |= SIM_SCGC4_UART0; // Disable clock gating
899 SIM_SCGC4 |= SIM_SCGC4_UART1; // Disable clock gating
901 // Pin Setup for UART0 / UART1
902 PORTA_PCR1 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(2); // RX Pin
903 PORTA_PCR2 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(2); // TX Pin
904 PORTE_PCR0 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); // RX Pin
905 PORTE_PCR1 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); // TX Pin
908 UART0_BDH = (uint8_t)(Connect_baud >> 8);
909 UART0_BDL = (uint8_t)Connect_baud;
910 UART0_C4 = Connect_baudFine;
911 UART1_BDH = (uint8_t)(Connect_baud >> 8);
912 UART1_BDL = (uint8_t)Connect_baud;
913 UART1_C4 = Connect_baudFine;
915 // 8 bit, Even Parity, Idle Character bit after stop
916 // NOTE: For 8 bit with Parity you must enable 9 bit transmission (pg. 1065)
917 // You only need to use UART0_D for 8 bit reading/writing though
918 // UART_C1_M UART_C1_PE UART_C1_PT UART_C1_ILT
919 UART0_C1 = UART_C1_M | UART_C1_PE | UART_C1_ILT;
920 UART1_C1 = UART_C1_M | UART_C1_PE | UART_C1_ILT;
922 // Only using Tx Fifos
923 UART0_PFIFO = UART_PFIFO_TXFE;
924 UART1_PFIFO = UART_PFIFO_TXFE;
927 SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
928 SIM_SCGC7 |= SIM_SCGC7_DMA;
930 // Start with channels disabled first
934 // Configure DMA channels
935 //DMA_DSR_BCR0 |= DMA_DSR_BCR_DONE_MASK; // TODO What's this?
939 // Default control register
943 DMA_DCHPRI0 = 0; // Ch 0, priority 0
944 DMA_DCHPRI1 = 1; // ch 1, priority 1
946 // Clear error interrupts
950 DMA_TCD0_SADDR = (uint32_t*)&UART0_D;
951 DMA_TCD1_SADDR = (uint32_t*)&UART1_D;
955 // No modulo, 8-bit transfer size
956 DMA_TCD0_ATTR = DMA_TCD_ATTR_SMOD(0) | DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DMOD(0) | DMA_TCD_ATTR_DSIZE(0);
957 DMA_TCD1_ATTR = DMA_TCD_ATTR_SMOD(0) | DMA_TCD_ATTR_SSIZE(0) | DMA_TCD_ATTR_DMOD(0) | DMA_TCD_ATTR_DSIZE(0);
959 // One byte transferred at a time
960 DMA_TCD0_NBYTES_MLNO = 1;
961 DMA_TCD1_NBYTES_MLNO = 1;
963 // Source address does not change
967 // Destination buffer
968 DMA_TCD0_DADDR = (uint32_t*)uart_rx_buf[0].buffer;
969 DMA_TCD1_DADDR = (uint32_t*)uart_rx_buf[1].buffer;
971 // Incoming byte, increment by 1 in the rx buffer
975 // Single major loop, must be the same value
976 DMA_TCD0_CITER_ELINKNO = UART_Buffer_Size;
977 DMA_TCD1_CITER_ELINKNO = UART_Buffer_Size;
978 DMA_TCD0_BITER_ELINKNO = UART_Buffer_Size;
979 DMA_TCD1_BITER_ELINKNO = UART_Buffer_Size;
981 // Reset buffer when full
982 DMA_TCD0_DLASTSGA = -( UART_Buffer_Size );
983 DMA_TCD1_DLASTSGA = -( UART_Buffer_Size );
985 // Enable DMA channels
986 DMA_ERQ |= DMA_ERQ_ERQ0 | DMA_ERQ_ERQ1;
988 // Setup DMA channel routing
989 DMAMUX0_CHCFG0 = DMAMUX_ENABLE | DMAMUX_SOURCE_UART0_RX;
990 DMAMUX0_CHCFG1 = DMAMUX_ENABLE | DMAMUX_SOURCE_UART1_RX;
992 // Enable DMA requests (requires Rx interrupts)
993 UART0_C5 = UART_C5_RDMAS;
994 UART1_C5 = UART_C5_RDMAS;
996 // TX Enabled, RX Enabled, RX Interrupt Enabled
997 UART0_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE;
998 UART1_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE;
1000 // Add interrupts to the vector table
1001 NVIC_ENABLE_IRQ( IRQ_UART0_STATUS );
1002 NVIC_ENABLE_IRQ( IRQ_UART1_STATUS );
1004 // UARTs are now ready to go
1005 uarts_configured = 1;
1007 // Reset the state of the UART variables
1012 #define DMA_BUF_POS( x, pos ) \
1014 pos = DMA_TCD##x##_CITER_ELINKNO; \
1016 void Connect_rx_process( uint8_t uartNum )
1018 // Determine current position to read until
1019 uint16_t bufpos = 0;
1022 DMA_BUF_POS( 0, bufpos );
1023 DMA_BUF_POS( 1, bufpos );
1026 // Process each of the new bytes
1027 // Even if we receive more bytes during processing, wait until the next check so we don't starve other tasks
1028 while ( bufpos != uart_rx_buf[ uartNum ].last_read )
1030 // If the last_read byte is at the buffer edge, roll back to beginning
1031 if ( uart_rx_buf[ uartNum ].last_read == 0 )
1033 uart_rx_buf[ uartNum ].last_read = UART_Buffer_Size;
1035 // Check to see if we're at the boundary
1036 if ( bufpos == UART_Buffer_Size )
1040 // Read the byte out of Rx DMA buffer
1041 uint8_t byte = uart_rx_buf[ uartNum ].buffer[ UART_Buffer_Size - uart_rx_buf[ uartNum ].last_read-- ];
1043 if ( Connect_debug )
1049 // Process UART byte
1050 switch ( uart_rx_status[ uartNum ].status )
1052 // Every packet must start with a SYN / 0x16
1053 case UARTStatus_Wait:
1054 if ( Connect_debug )
1058 uart_rx_status[ uartNum ].status = byte == 0x16 ? UARTStatus_SYN : UARTStatus_Wait;
1061 // After a SYN, there must be a SOH / 0x01
1062 case UARTStatus_SYN:
1063 if ( Connect_debug )
1067 uart_rx_status[ uartNum ].status = byte == 0x01 ? UARTStatus_SOH : UARTStatus_Wait;
1070 // After a SOH the packet structure may diverge a bit
1071 // This is the packet type field (refer to the Command enum)
1072 // For very small packets (e.g. IdRequest) this is all that's required to take action
1073 case UARTStatus_SOH:
1075 if ( Connect_debug )
1080 // Check if this is actually a reserved CMD 0x16 (Error condition)
1081 if ( byte == Command_SYN )
1083 uart_rx_status[ uartNum ].status = UARTStatus_SYN;
1087 // Otherwise process the command
1088 if ( byte < Command_TOP )
1090 uart_rx_status[ uartNum ].status = UARTStatus_Command;
1091 uart_rx_status[ uartNum ].command = byte;
1092 uart_rx_status[ uartNum ].bytes_waiting = 0xFFFF;
1094 // Invalid packet type, ignore
1097 uart_rx_status[ uartNum ].status = UARTStatus_Wait;
1100 // Check if this is a very short packet
1101 switch ( uart_rx_status[ uartNum ].command )
1104 Connect_receive_IdRequest( 0, (uint16_t*)&uart_rx_status[ uartNum ].bytes_waiting, uartNum );
1105 uart_rx_status[ uartNum ].status = UARTStatus_Wait;
1109 if ( Connect_debug )
1112 printHex( uart_rx_status[ uartNum ].command );
1119 // After the packet type has been deciphered do Command specific processing
1120 // Until the Command has received all the bytes it requires the UART buffer stays in this state
1121 case UARTStatus_Command:
1123 if ( Connect_debug )
1127 /* Call specific UARTConnect command receive function */
1128 uint8_t (*rcvFunc)(uint8_t, uint16_t(*), uint8_t) = (uint8_t(*)(uint8_t, uint16_t(*), uint8_t))(Connect_receiveFunctions[ uart_rx_status[ uartNum ].command ]);
1129 if ( rcvFunc( byte, (uint16_t*)&uart_rx_status[ uartNum ].bytes_waiting, uartNum ) )
1130 uart_rx_status[ uartNum ].status = UARTStatus_Wait;
1134 // Unknown status, should never get here
1136 erro_msg("Invalid UARTStatus...");
1137 uart_rx_status[ uartNum ].status = UARTStatus_Wait;
1141 if ( Connect_debug )
1149 // Scan for updates in the master/slave
1150 // - Interrupts will deal with most input functions
1151 // - Used to send queries
1152 // - SyncEvent is sent immediately once the current command is sent
1153 // - SyncEvent is also blocking until sent
1156 // Check if initially configured as a slave and usb comes up
1157 // Then reconfigure as a master
1158 if ( !Connect_master && Output_Available && !Connect_override )
1160 Connect_setup( Output_Available );
1163 // Limit how often we do cable checks
1164 //uint32_t time_compare = 0x007; // Used for debugging cables -HaaTa
1165 uint32_t time_compare = 0x7FF; // Must be all 1's, 0x3FF is valid, 0x4FF is not
1166 uint32_t current_time = systick_millis_count;
1167 if ( Connect_lastCheck != current_time
1168 && ( current_time & time_compare ) == time_compare
1171 // Make sure we don't double check if the clock speed is too high
1172 Connect_lastCheck = current_time;
1174 // Send a cable check command of 2 bytes
1175 Connect_send_CableCheck( UARTConnectCableCheckLength_define );
1177 // If this is a slave, and we don't have an id yeth
1178 // Don't bother sending if there are cable issues
1179 if ( !Connect_master && Connect_id == 0xFF && Connect_cableOkMaster )
1181 Connect_send_IdRequest();
1185 // Only process commands if uarts have been configured
1186 if ( uarts_configured )
1188 // Check if Tx Buffers are empty and the Tx Ring buffers have data to send
1189 // This happens if there was previously nothing to send
1190 if ( uart_tx_buf[ 0 ].items > 0 && UART0_TCFIFO == 0 )
1191 uart_fillTxFifo( 0 );
1192 if ( uart_tx_buf[ 1 ].items > 0 && UART1_TCFIFO == 0 )
1193 uart_fillTxFifo( 1 );
1195 // Process Rx Buffers
1196 Connect_rx_process( 0 );
1197 Connect_rx_process( 1 );
1202 // Called by parent Scan module whenever the available current changes
1203 void Connect_currentChange( unsigned int current )
1205 // TODO - Any potential power saving here?
1210 // ----- CLI Command Functions -----
1212 void cliFunc_connectCmd( char* args )
1214 // Parse number from argument
1215 // NOTE: Only first argument is used
1218 CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
1222 switch ( numToInt( &arg1Ptr[0] ) )
1225 Connect_send_CableCheck( UARTConnectCableCheckLength_define );
1229 Connect_send_IdRequest();
1233 Connect_send_IdEnumeration( 5 );
1237 Connect_send_IdReport( 8 );
1242 TriggerGuide scanCodes[] = { { 0x00, 0x01, 0x05 }, { 0x00, 0x03, 0x16 } };
1243 Connect_send_ScanCode( 10, scanCodes, 2 );
1249 case RemoteCapability:
1266 void cliFunc_connectDbg( char* args )
1269 info_msg("Connect Debug Mode Toggle");
1270 Connect_debug = !Connect_debug;
1273 void cliFunc_connectIdl( char* args )
1275 // Parse number from argument
1276 // NOTE: Only first argument is used
1279 CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
1282 info_msg("Sending Sync Idles...");
1284 uint8_t count = numToInt( &arg1Ptr[0] );
1285 // Default to 2 idles
1289 Connect_send_Idle( count );
1292 void cliFunc_connectLst( char* args )
1294 const char *Command_strs[] = {
1307 info_msg("List of UARTConnect commands");
1308 for ( uint8_t cmd = 0; cmd < Command_TOP; cmd++ )
1313 dPrint( (char*)Command_strs[ cmd ] );
1317 void cliFunc_connectMst( char* args )
1319 // Parse number from argument
1320 // NOTE: Only first argument is used
1323 CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
1328 Connect_override = 1;
1330 switch ( arg1Ptr[0] )
1335 Connect_override = 0;
1338 info_msg("Setting device as slave.");
1346 info_msg("Setting device as master.");
1353 void cliFunc_connectRst( char* args )
1356 info_msg("Resetting UARTConnect state...");
1363 void cliFunc_connectSts( char* args )
1366 info_msg("UARTConnect Status");
1367 print( NL "Device Type:\t" );
1368 print( Connect_master ? "Master" : "Slave" );
1369 print( NL "Device Id:\t" );
1370 printHex( Connect_id );
1371 print( NL "Max Id:\t" );
1372 printHex( Connect_maxId );
1373 print( NL "Master <=" NL "\tStatus:\t");
1374 printHex( Connect_cableOkMaster );
1375 print( NL "\tFaults:\t");
1376 printHex32( Connect_cableFaultsMaster );
1378 printHex32( Connect_cableChecksMaster );
1379 print( NL "\tRx:\t");
1380 printHex( uart_rx_status[UART_Master].status );
1381 print( NL "\tTx:\t");
1382 printHex( uart_tx_status[UART_Master].status );
1383 print( NL "Slave <=" NL "\tStatus:\t");
1384 printHex( Connect_cableOkSlave );
1385 print( NL "\tFaults:\t");
1386 printHex32( Connect_cableFaultsSlave );
1388 printHex32( Connect_cableChecksSlave );
1389 print( NL "\tRx:\t");
1390 printHex( uart_rx_status[UART_Slave].status );
1391 print( NL "\tTx:\t");
1392 printHex( uart_tx_status[UART_Slave].status );