Archived
1
0

Initial commit for UARTConnect module

* Keyboard interconnect using two uarts
* Supports daisy chain addressing using a master/slave direction communication scheme

- Still needs more testing
- Functions have been tested alone to be generally working
This commit is contained in:
Jacob Alexander 2015-03-15 16:58:01 -07:00
parent aeaaaaa468
commit ed71f7fad5
9 changed files with 1108 additions and 4 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2014 by Jacob Alexander /* Copyright (C) 2014-2015 by Jacob Alexander
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -34,7 +34,7 @@
// ----- Defines ----- // ----- Defines -----
#define CLILineBufferMaxSize 100 #define CLILineBufferMaxSize 100
#define CLIMaxDictionaries 5 #define CLIMaxDictionaries 10
#define CLIEntryTabAlign 13 #define CLIEntryTabAlign 13

View File

@ -1467,7 +1467,9 @@ typedef struct {
#define UART0_IR *(volatile uint8_t *)0x4006A00E // UART Infrared Register #define UART0_IR *(volatile uint8_t *)0x4006A00E // UART Infrared Register
#define UART0_PFIFO *(volatile uint8_t *)0x4006A010 // UART FIFO Parameters #define UART0_PFIFO *(volatile uint8_t *)0x4006A010 // UART FIFO Parameters
#define UART_PFIFO_TXFE (uint8_t)0x80 #define UART_PFIFO_TXFE (uint8_t)0x80
#define UART_PFIFO_TXFIFOSIZE (uint8_t)0x70
#define UART_PFIFO_RXFE (uint8_t)0x08 #define UART_PFIFO_RXFE (uint8_t)0x08
#define UART_PFIFO_RXFIFOSIZE (uint8_t)0x07
#define UART0_CFIFO *(volatile uint8_t *)0x4006A011 // UART FIFO Control Register #define UART0_CFIFO *(volatile uint8_t *)0x4006A011 // UART FIFO Control Register
#define UART_CFIFO_TXFLUSH (uint8_t)0x80 // #define UART_CFIFO_TXFLUSH (uint8_t)0x80 //
#define UART_CFIFO_RXFLUSH (uint8_t)0x40 // #define UART_CFIFO_RXFLUSH (uint8_t)0x40 //

View File

@ -69,7 +69,7 @@ EXIT_STATUS=$?
# Load Screen Session if specified # Load Screen Session if specified
if (( "$EXIT_STATUS" == "0" )) && [[ "$AUTO_SCREEN_SESSION" != "" ]]; then if (( "$EXIT_STATUS" == "0" )) && [[ "$AUTO_SCREEN_SESSION" != "" ]]; then
if type screen &>/dev/null; then if type screen &>/dev/null; then
sleep 0.1 sleep 2
screen $AUTO_SCREEN_SESSION screen $AUTO_SCREEN_SESSION
else else
echo "screen is not installed" echo "screen is not installed"

View File

@ -393,6 +393,16 @@ nat_ptr_t *Macro_layerLookup( TriggerGuide *guide, uint8_t latch_expire )
} }
// Update the scancode using a list of TriggerGuides
// TODO Handle led state and analog
inline void Macro_triggerState( void *triggers, uint8_t num )
{
// Copy each of the TriggerGuides to the TriggerListBuffer
for ( uint8_t c = 0; c < num; c++ )
macroTriggerListBuffer[ macroTriggerListBufferSize++ ] = ((TriggerGuide*)triggers)[ c ];
}
// Update the scancode key state // Update the scancode key state
// States: // States:
// * 0x00 - Off // * 0x00 - Off

View File

@ -35,9 +35,10 @@ void Macro_layerShift_capability( uint8_t state, uint8_t stateType, uint8_t *arg
// ----- Functions ----- // ----- Functions -----
void Macro_keyState( uint8_t scanCode, uint8_t state );
void Macro_analogState( uint8_t scanCode, uint8_t state ); void Macro_analogState( uint8_t scanCode, uint8_t state );
void Macro_keyState( uint8_t scanCode, uint8_t state );
void Macro_ledState( uint8_t ledCode, uint8_t state ); void Macro_ledState( uint8_t ledCode, uint8_t state );
void Macro_triggerState( void *triggers, uint8_t num ); // triggers is of type TriggerGuide, void* for circular dependencies
void Macro_process(); void Macro_process();
void Macro_setup(); void Macro_setup();

View File

@ -0,0 +1,31 @@
Name = UARTConnectCapabilities;
Version = 0.1;
Author = "HaaTa (Jacob Alexander) 2015";
KLL = 0.3a;
# Modified Date
Date = 2015-03-15;
# UART Buffer Size
# Number of bytes to reserve for each side of UARTConnect
# For true NKRO support must be at least: <# of Keys> x 3 + 5
UARTConnectBufSize => UARTConnectBufSize_define;
UARTConnectBufSize = 128; # MDErgo1 requires at least a 119 byte buffer
# UART Speed
# *NOTE* This must be changed on every device in the chain or else UARTConnect will not work
# The faster the speed, the lower the latency, but higher chance for an error
UARTConnectBaud => UARTConnectBaud_define;
UARTConnectBaudFine => UARTConnectBaudFine_define;
# Generally, leave BaudFine at zero unless trying to tune the link to an external UART
# You'll want to look at the specific chip datasheet for the exact equation
#
# Example of 115200 Baud using a 48 MHz clock (mk20dx128vlf5)
# 48 MHz / ( 16 * Baud ) = BDH/L
# Baud: 115200 -> 48 MHz / ( 16 * 115200 ) = 26.0416667
# Thus baud setting = 26
# NOTE: If finer baud adjustment is needed see UARTx_C4 -> BRFA in the datasheet
# Baud fine setting = 0x02
UARTConnectBaud = 26;
UARTConnectBaudFine = 0x02;

View File

@ -0,0 +1,908 @@
/* Copyright (C) 2014-2015 by Jacob Alexander
*
* This file is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this file. If not, see <http://www.gnu.org/licenses/>.
*/
// ----- Includes -----
// Compiler Includes
#include <Lib/ScanLib.h>
// Project Includes
#include <cli.h>
#include <led.h>
#include <print.h>
#include <macro.h>
// Local Includes
#include "connect_scan.h"
// ----- Macros -----
// Macro for adding to each uart Tx ring buffer
#define uart_addTxBuffer( uartNum ) \
case uartNum: \
while ( uart##uartNum##_buffer_items + count > uart_buffer_size ) \
{ \
warn_msg("Too much data to send on UART0, waiting..."); \
delay( 1 ); \
} \
for ( uint8_t c = 0; c < count; c++ ) \
{ \
printHex( buffer[ c ] ); \
print( " +" #uartNum NL ); \
uart##uartNum##_buffer[ uart##uartNum##_buffer_tail++ ] = buffer[ c ]; \
uart##uartNum##_buffer_items++; \
if ( uart##uartNum##_buffer_tail >= uart_buffer_size ) \
uart##uartNum##_buffer_tail = 0; \
if ( uart##uartNum##_buffer_head == uart##uartNum##_buffer_tail ) \
uart##uartNum##_buffer_head++; \
if ( uart##uartNum##_buffer_head >= uart_buffer_size ) \
uart##uartNum##_buffer_head = 0; \
} \
break
// Macro for popping from Tx ring buffer
#define uart_fillTxFifo( uartNum ) \
{ \
uint8_t fifoSize = ( ( UART##uartNum##_PFIFO & UART_PFIFO_TXFIFOSIZE ) >> 2 ); \
if ( fifoSize == 0 ) \
fifoSize = 1; \
while ( UART##uartNum##_TCFIFO < fifoSize ) \
{ \
if ( uart##uartNum##_buffer_items == 0 ) \
break; \
UART##uartNum##_D = uart##uartNum##_buffer[ uart##uartNum##_buffer_head++ ]; \
uart##uartNum##_buffer_items--; \
if ( uart##uartNum##_buffer_head >= uart_buffer_size ) \
uart##uartNum##_buffer_head = 0; \
} \
}
// Macro for processing UART Rx
#define uart_processRx( uartNum ) \
{ \
if ( !( UART##uartNum##_S1 & UART_S1_RDRF ) ) \
return; \
uint8_t available = UART##uartNum##_RCFIFO; \
if ( available == 0 ) \
{ \
available = UART##uartNum##_D; \
UART##uartNum##_CFIFO = UART_CFIFO_RXFLUSH; \
return; \
} \
while ( available-- > 0 ) \
{ \
uint8_t byteRead = UART##uartNum##_D; \
printHex( byteRead ); \
print( "(" ); \
printInt8( available ); \
print( ") <-" ); \
switch ( uart##uartNum##_rx_status ) \
{ \
case UARTStatus_Wait: \
print(" SYN "); \
uart##uartNum##_rx_status = byteRead == 0x16 ? UARTStatus_SYN : UARTStatus_Wait; \
break; \
case UARTStatus_SYN: \
print(" SOH "); \
uart##uartNum##_rx_status = byteRead == 0x01 ? UARTStatus_SOH : UARTStatus_Wait; \
break; \
case UARTStatus_SOH: \
{ \
print(" CMD "); \
uint8_t byte = byteRead; \
if ( byte <= Animation ) \
{ \
uart##uartNum##_rx_status = UARTStatus_Command; \
uart##uartNum##_rx_command = byte; \
uart##uartNum##_rx_bytes_waiting = 0xFFFF; \
} \
else \
{ \
uart##uartNum##_rx_status = UARTStatus_Wait; \
} \
switch ( uart##uartNum##_rx_command ) \
{ \
case IdRequest: \
Connect_receive_IdRequest( 0, (uint16_t*)&uart##uartNum##_rx_bytes_waiting, uartNum ); \
uart##uartNum##_rx_status = UARTStatus_Wait; \
break; \
default: \
print("###"); \
break; \
} \
break; \
} \
case UARTStatus_Command: \
{ \
print(" CMD "); \
uint8_t (*rcvFunc)(uint8_t, uint16_t(*), uint8_t) = (uint8_t(*)(uint8_t, uint16_t(*), uint8_t))(Connect_receiveFunctions[ uart##uartNum##_rx_command ]); \
if ( rcvFunc( byteRead, (uint16_t*)&uart##uartNum##_rx_bytes_waiting, uartNum ) ) \
uart##uartNum##_rx_status = UARTStatus_Wait; \
break; \
} \
default: \
erro_msg("Invalid UARTStatus..."); \
uart##uartNum##_rx_status = UARTStatus_Wait; \
available++; \
continue; \
} \
print( NL ); \
} \
}
// Macros for locking/unlock Tx buffers
#define uart_lockTx( uartNum ) \
{ \
while ( uart##uartNum##_tx_status == UARTStatus_Wait ); \
uart##uartNum##_tx_status = UARTStatus_Wait; \
}
#define uart_unlockTx( uartNum ) \
{ \
uart##uartNum##_tx_status = UARTStatus_Ready; \
}
// ----- Function Declarations -----
// CLI Functions
void cliFunc_connectCmd ( char *args );
void cliFunc_connectIdl ( char *args );
void cliFunc_connectMst ( char *args );
void cliFunc_connectRst ( char *args );
void cliFunc_connectSts ( char *args );
// ----- Variables -----
// Connect Module command dictionary
CLIDict_Entry( connectCmd, "Sends a command via UART Connect, first arg is which uart, next arg is the command, rest are the arguments." );
CLIDict_Entry( connectIdl, "Sends N number of Idle commands, 2 is the default value, and should be sufficient in most cases." );
CLIDict_Entry( connectMst, "Sets the device as master. Use argument of s to set as slave." );
CLIDict_Entry( connectRst, "Resets both Rx and Tx connect buffers and state variables." );
CLIDict_Entry( connectSts, "UARTConnect status." );
CLIDict_Def( uartConnectCLIDict, "UARTConnect Module Commands" ) = {
CLIDict_Item( connectCmd ),
CLIDict_Item( connectIdl ),
CLIDict_Item( connectMst ),
CLIDict_Item( connectRst ),
CLIDict_Item( connectSts ),
{ 0, 0, 0 } // Null entry for dictionary end
};
// -- Connect Device Id Variables --
uint8_t Connect_id = 255; // Invalid, unset
uint8_t Connect_master = 0;
// -- Rx Status Variables --
volatile UARTStatus uart0_rx_status;
volatile UARTStatus uart1_rx_status;
volatile uint16_t uart0_rx_bytes_waiting;
volatile uint16_t uart1_rx_bytes_waiting;
volatile Command uart0_rx_command;
volatile Command uart1_rx_command;
// -- Tx Status Variables --
volatile UARTStatus uart0_tx_status;
volatile UARTStatus uart1_tx_status;
// -- Ring Buffer Variables --
#define uart_buffer_size UARTConnectBufSize_define
volatile uint8_t uart0_buffer_head;
volatile uint8_t uart0_buffer_tail;
volatile uint8_t uart0_buffer_items;
volatile uint8_t uart0_buffer[uart_buffer_size];
volatile uint8_t uart1_buffer_head;
volatile uint8_t uart1_buffer_tail;
volatile uint8_t uart1_buffer_items;
volatile uint8_t uart1_buffer[uart_buffer_size];
volatile uint8_t uarts_configured = 0;
// -- Ring Buffer Convenience Functions --
void Connect_addBytes( uint8_t *buffer, uint8_t count, uint8_t uart )
{
// Too big to fit into buffer
if ( count > uart_buffer_size )
{
erro_msg("Too big of a command to fit into the buffer...");
return;
}
// Choose the uart
switch ( uart )
{
uart_addTxBuffer( 0 );
uart_addTxBuffer( 1 );
default:
erro_msg("Invalid UART to send from...");
break;
}
}
// -- Connect send functions --
// patternLen defines how many bytes should the incrementing pattern have
void Connect_send_CableCheck( uint8_t patternLen )
{
// Wait until the Tx buffers are ready, then lock them
uart_lockTx( 0 );
uart_lockTx( 1 );
// Prepare header
uint8_t header[] = { 0x16, 0x01, CableCheck, patternLen };
// Send header
Connect_addBytes( header, sizeof( header ), 1 ); // Master
Connect_addBytes( header, sizeof( header ), 0 ); // Slave
// Send 0xD2 (11010010) for each argument
uint8_t value = 0xD2;
for ( uint8_t c = 0; c < patternLen; c++ )
{
Connect_addBytes( &value, 1, 1 ); // Master
Connect_addBytes( &value, 1, 0 ); // Slave
}
// Release Tx buffers
uart_unlockTx( 0 );
uart_unlockTx( 1 );
}
void Connect_send_IdRequest()
{
// Lock master bound Tx
uart_lockTx( 1 );
// Prepare header
uint8_t header[] = { 0x16, 0x01, IdRequest };
// Send header
Connect_addBytes( header, sizeof( header ), 1 ); // Master
// Unlock Tx
uart_unlockTx( 1 );
}
// id is the value the next slave should enumerate as
void Connect_send_IdEnumeration( uint8_t id )
{
// Lock slave bound Tx
uart_lockTx( 0 );
// Prepare header
uint8_t header[] = { 0x16, 0x01, IdEnumeration, id };
// Send header
Connect_addBytes( header, sizeof( header ), 0 ); // Slave
// Unlock Tx
uart_unlockTx( 0 );
}
// id is the currently assigned id to the slave
void Connect_send_IdReport( uint8_t id )
{
// Lock master bound Tx
uart_lockTx( 1 );
// Prepare header
uint8_t header[] = { 0x16, 0x01, IdReport, id };
// Send header
Connect_addBytes( header, sizeof( header ), 1 ); // Master
// Unlock Tx
uart_unlockTx( 1 );
}
// id is the currently assigned id to the slave
// scanCodeStateList is an array of [scancode, state]'s (8 bit values)
// numScanCodes is the number of scan codes to parse from array
void Connect_send_ScanCode( uint8_t id, TriggerGuide *scanCodeStateList, uint8_t numScanCodes )
{
// Lock master bound Tx
uart_lockTx( 1 );
// Prepare header
uint8_t header[] = { 0x16, 0x01, ScanCode, id, numScanCodes };
// Send header
Connect_addBytes( header, sizeof( header ), 1 ); // Master
// Send each of the scan codes
Connect_addBytes( (uint8_t*)scanCodeStateList, numScanCodes * TriggerGuideSize, 1 ); // Master
// Unlock Tx
uart_unlockTx( 1 );
}
// id is the currently assigned id to the slave
// paramList is an array of [param, value]'s (8 bit values)
// numParams is the number of params to parse from the array
void Connect_send_Animation( uint8_t id, uint8_t *paramList, uint8_t numParams )
{
// Lock slave bound Tx
uart_lockTx( 0 );
// Prepare header
uint8_t header[] = { 0x16, 0x01, Animation, id, numParams };
// Send header
Connect_addBytes( header, sizeof( header ), 0 ); // Slave
// Send each of the scan codes
Connect_addBytes( paramList, numParams, 0 ); // Slave
// Unlock Tx
uart_unlockTx( 0 );
}
void Connect_send_Idle( uint8_t num )
{
// Wait until the Tx buffers are ready, then lock them
uart_lockTx( 0 );
uart_lockTx( 1 );
// Send n number of idles to reset link status (if in a bad state)
uint8_t value = 0x16;
for ( uint8_t c = 0; c < num; c++ )
{
Connect_addBytes( &value, 1, 1 ); // Master
Connect_addBytes( &value, 1, 0 ); // Slave
}
// Release Tx buffers
uart_unlockTx( 0 );
uart_unlockTx( 1 );
}
// -- Connect receive functions --
// - Cable Check variables -
uint32_t Connect_cableFaultsMaster = 0;
uint32_t Connect_cableFaultsSlave = 0;
uint8_t Connect_cableOkMaster = 0;
uint8_t Connect_cableOkSlave = 0;
uint8_t Connect_receive_CableCheck( uint8_t byte, uint16_t *pending_bytes, uint8_t to_master )
{
// Check if this is the first byte
if ( *pending_bytes == 0xFFFF )
{
dbug_msg("PENDING SET -> ");
printHex( byte );
print(" ");
*pending_bytes = byte;
printHex( *pending_bytes );
print( NL );
}
// Verify byte
else
{
(*pending_bytes)--;
// The argument bytes are always 0xD2 (11010010)
if ( byte != 0xD2 )
{
warn_print("Cable Fault!");
// Check which side of the chain
if ( to_master )
{
Connect_cableFaultsMaster++;
Connect_cableOkMaster = 0;
print(" Master ");
}
else
{
Connect_cableFaultsSlave++;
Connect_cableOkSlave = 0;
print(" Slave ");
}
printHex( byte );
print( NL );
// Signal that the command should wait for a SYN again
return 1;
}
}
// If cable check was successful, set cable ok
if ( *pending_bytes == 0 )
{
if ( to_master )
{
Connect_cableOkMaster = 1;
}
else
{
Connect_cableOkSlave = 1;
}
}
dbug_msg("CABLECHECK RECEIVE - ");
printHex( byte );
print(" ");
printHex( *pending_bytes );
print(NL);
// Check whether the cable check has finished
return *pending_bytes == 0 ? 1 : 0;
}
uint8_t Connect_receive_IdRequest( uint8_t byte, uint16_t *pending_bytes, uint8_t to_master )
{
dbug_print("IdRequest");
// Check the directionality
if ( !to_master )
{
erro_print("Invalid IdRequest direction...");
}
// Check if master, begin IdEnumeration
if ( Connect_master )
{
// The first device is always id 1
// Id 0 is reserved for the master
Connect_send_IdEnumeration( 1 );
}
// Propagate IdRequest
else
{
Connect_send_IdRequest();
}
return 1;
}
uint8_t Connect_receive_IdEnumeration( uint8_t id, uint16_t *pending_bytes, uint8_t to_master )
{
dbug_print("IdEnumeration");
// Check the directionality
if ( to_master )
{
erro_print("Invalid IdEnumeration direction...");
}
// Set the device id
Connect_id = id;
// Send reponse back to master
Connect_send_IdReport( id );
// Propogate next Id if the connection is ok
if ( Connect_cableOkSlave )
{
Connect_send_IdEnumeration( id + 1 );
}
return 1;
}
uint8_t Connect_receive_IdReport( uint8_t id, uint16_t *pending_bytes, uint8_t to_master )
{
dbug_print("IdReport");
// Check the directionality
if ( !to_master )
{
erro_print("Invalid IdRequest direction...");
}
// Track Id response if master
if ( Connect_master )
{
// TODO, setup id's
info_msg("Id Reported: ");
printHex( id );
print( NL );
return 1;
}
// Propagate id if yet another slave
else
{
Connect_send_IdReport( id );
}
return 1;
}
// - Scan Code Variables -
TriggerGuide Connect_receive_ScanCodeBuffer;
uint8_t Connect_receive_ScanCodeBufferPos;
uint8_t Connect_receive_ScanCodeDeviceId;
uint8_t Connect_receive_ScanCode( uint8_t byte, uint16_t *pending_bytes, uint8_t to_master )
{
dbug_print("ScanCode");
// Check the directionality
if ( !to_master )
{
erro_print("Invalid ScanCode direction...");
}
// Master node, trigger scan codes
if ( Connect_master ) switch ( (*pending_bytes)-- )
{
case 0xFFFF: // Device Id
Connect_receive_ScanCodeDeviceId = byte;
break;
case 0xFFFE: // Number of TriggerGuides in bytes (byte * 3)
*pending_bytes = byte * 3;
Connect_receive_ScanCodeBufferPos = 0;
break;
default:
// Set the specific TriggerGuide entry
((uint8_t*)&Connect_receive_ScanCodeBuffer)[ Connect_receive_ScanCodeBufferPos++ ] = byte;
// Reset the BufferPos if higher than 3
// And send the TriggerGuide to the Macro Module
if ( Connect_receive_ScanCodeBufferPos > 3 )
{
Connect_receive_ScanCodeBufferPos = 0;
Macro_triggerState( &Connect_receive_ScanCodeBuffer, 1 );
}
break;
}
// Propagate ScanCode packet
else switch ( (*pending_bytes)-- )
{
case 0xFFFF: // Device Id
{
Connect_receive_ScanCodeDeviceId = byte;
// Lock the master Tx buffer
uart_lockTx( 1 );
// Send header + Id byte
uint8_t header[] = { 0x16, 0x01, ScanCode, byte };
Connect_addBytes( header, sizeof( header ), 1 ); // Master
break;
}
case 0xFFFE: // Number of TriggerGuides in bytes (byte * 3)
*pending_bytes = byte * 3;
Connect_receive_ScanCodeBufferPos = 0;
// Pass through byte
Connect_addBytes( &byte, 1, 1 ); // Master
break;
default:
// Pass through byte
Connect_addBytes( &byte, 1, 1 ); // Master
// Unlock Tx Buffer after sending last byte
if ( *pending_bytes == 0 )
uart_unlockTx( 1 );
break;
}
// Check whether the scan codes have finished sending
return *pending_bytes == 0 ? 1 : 0;
}
uint8_t Connect_receive_Animation( uint8_t byte, uint16_t *pending_bytes, uint8_t to_master )
{
dbug_print("Animation");
return 1;
}
// Baud Rate
// NOTE: If finer baud adjustment is needed see UARTx_C4 -> BRFA in the datasheet
uint16_t Connect_baud = UARTConnectBaud_define; // Max setting of 8191
uint16_t Connect_baudFine = UARTConnectBaudFine_define;
// Connect receive function lookup
void *Connect_receiveFunctions[] = {
Connect_receive_CableCheck,
Connect_receive_IdRequest,
Connect_receive_IdEnumeration,
Connect_receive_IdReport,
Connect_receive_ScanCode,
Connect_receive_Animation,
};
// ----- Interrupt Functions -----
// Master / UART0 ISR
void uart0_status_isr()
{
// Process Rx buffer
uart_processRx( 0 );
}
// Slave / UART1 ISR
void uart1_status_isr()
{
// Process Rx buffer
uart_processRx( 1 );
}
// ----- Functions -----
// Resets the state of the UART buffers and state variables
void Connect_reset()
{
// Rx Status Variables
uart0_rx_status = UARTStatus_Wait;
uart1_rx_status = UARTStatus_Wait;
uart0_rx_bytes_waiting = 0;
uart1_rx_bytes_waiting = 0;
// Tx Status Variables
uart0_tx_status = UARTStatus_Ready;
uart1_tx_status = UARTStatus_Ready;
// Ring Buffer Variables
uart0_buffer_head = 0;
uart0_buffer_tail = 0;
uart0_buffer_items = 0;
uart1_buffer_head = 0;
uart1_buffer_tail = 0;
uart1_buffer_items = 0;
}
// Setup connection to other side
// - Only supports a single slave and master
// - If USB has been initiallized at this point, this side is the master
// - If both sides assert master, flash error leds
void Connect_setup( uint8_t master )
{
// Indication that UARTs are not ready
uarts_configured = 0;
// Register Connect CLI dictionary
CLI_registerDictionary( uartConnectCLIDict, uartConnectCLIDictName );
Connect_master = master;
// Master / UART0 setup
// Slave / UART1 setup
// Setup the the UART interface for keyboard data input
SIM_SCGC4 |= SIM_SCGC4_UART0; // Disable clock gating
SIM_SCGC4 |= SIM_SCGC4_UART1; // Disable clock gating
// Pin Setup for UART0 / UART1
// XXX TODO Set to actual (Teensy 3.1s don't have the correct pins available)
PORTB_PCR16 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); // RX Pin
PORTB_PCR17 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); // TX Pin
PORTC_PCR3 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); // RX Pin
PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); // TX Pin
//PORTA_PCR1 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(2); // RX Pin
//PORTA_PCR2 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(2); // TX Pin
//PORTE_PCR0 = PORT_PCR_PE | PORT_PCR_PS | PORT_PCR_PFE | PORT_PCR_MUX(3); // RX Pin
//PORTE_PCR1 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(3); // TX Pin
// Baud Rate setting
UART0_BDH = (uint8_t)(Connect_baud >> 8);
UART0_BDL = (uint8_t)Connect_baud;
UART0_C4 = Connect_baudFine;
UART1_BDH = (uint8_t)(Connect_baud >> 8);
UART1_BDL = (uint8_t)Connect_baud;
UART1_C4 = Connect_baudFine;
// 8 bit, Even Parity, Idle Character bit after stop
// NOTE: For 8 bit with Parity you must enable 9 bit transmission (pg. 1065)
// You only need to use UART0_D for 8 bit reading/writing though
// UART_C1_M UART_C1_PE UART_C1_PT UART_C1_ILT
UART0_C1 = UART_C1_M | UART_C1_PE | UART_C1_ILT;
UART1_C1 = UART_C1_M | UART_C1_PE | UART_C1_ILT;
// Number of bytes in FIFO before TX Interrupt
// TODO Set 0
UART0_TWFIFO = 1;
UART1_TWFIFO = 1;
// Number of bytes in FIFO before RX Interrupt
UART0_RWFIFO = 1;
UART1_RWFIFO = 1;
// Enable TX and RX FIFOs
UART0_PFIFO = UART_PFIFO_TXFE | UART_PFIFO_RXFE;
UART1_PFIFO = UART_PFIFO_TXFE | UART_PFIFO_RXFE;
// Reciever Inversion Disabled, LSBF
// UART_S2_RXINV UART_S2_MSBF
UART0_S2 |= 0x00;
UART1_S2 |= 0x00;
// Transmit Inversion Disabled
// UART_C3_TXINV
UART0_C3 |= 0x00;
UART1_C3 |= 0x00;
// TX Enabled, RX Enabled, RX Interrupt Enabled
// UART_C2_TE UART_C2_RE UART_C2_RIE
UART0_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE;
UART1_C2 = UART_C2_TE | UART_C2_RE | UART_C2_RIE;
// Add interrupts to the vector table
NVIC_ENABLE_IRQ( IRQ_UART0_STATUS );
NVIC_ENABLE_IRQ( IRQ_UART1_STATUS );
// UARTs are now ready to go
uarts_configured = 1;
// Reset the state of the UART variables
Connect_reset();
}
// Scan for updates in the master/slave
// - Interrupts will deal with most input functions
// - Used to send queries
// - SyncEvent is sent immediately once the current command is sent
// - SyncEvent is also blocking until sent
void Connect_scan()
{
// Check if Tx Buffers are empty and the Tx Ring buffers have data to send
// This happens if there was previously nothing to send
if ( uart0_buffer_items > 0 && UART0_TCFIFO == 0 )
uart_fillTxFifo( 0 );
if ( uart1_buffer_items > 0 && UART1_TCFIFO == 0 )
uart_fillTxFifo( 1 );
}
// ----- CLI Command Functions -----
void cliFunc_connectCmd( char* args )
{
// Parse number from argument
// NOTE: Only first argument is used
char* arg1Ptr;
char* arg2Ptr;
CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
print( NL );
switch ( numToInt( &arg1Ptr[0] ) )
{
case CableCheck:
Connect_send_CableCheck( 2 );
break;
case IdRequest:
Connect_send_IdRequest();
break;
case IdEnumeration:
Connect_send_IdEnumeration( 5 );
break;
case IdReport:
Connect_send_IdReport( 8 );
break;
case ScanCode:
{
TriggerGuide scanCodes[] = { { 0x00, 0x01, 0x05 }, { 0x00, 0x03, 0x16 } };
Connect_send_ScanCode( 10, scanCodes, 2 );
break;
}
case Animation:
default:
break;
}
}
void cliFunc_connectIdl( char* args )
{
// Parse number from argument
// NOTE: Only first argument is used
char* arg1Ptr;
char* arg2Ptr;
CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
print( NL );
info_msg("Sending Sync Idles...");
uint8_t count = numToInt( &arg1Ptr[0] );
// Default to 2 idles
if ( count == 0 )
count = 2;
Connect_send_Idle( count );
}
void cliFunc_connectMst( char* args )
{
// Parse number from argument
// NOTE: Only first argument is used
char* arg1Ptr;
char* arg2Ptr;
CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
print( NL );
switch ( arg1Ptr[0] )
{
case 's':
case 'S':
info_msg("Setting device as slave.");
Connect_master = 0;
Connect_id = 0xFF;
break;
case 'm':
case 'M':
default:
info_msg("Setting device as master.");
Connect_master = 1;
Connect_id = 0;
break;
}
}
void cliFunc_connectRst( char* args )
{
print( NL );
info_msg("Resetting UARTConnect state...");
Connect_reset();
// TODO - Argument for re-sync
}
void cliFunc_connectSts( char* args )
{
print( NL );
info_msg("UARTConnect Status");
print( NL "Device Type:\t" );
print( Connect_master ? "Master" : "Slave" );
print( NL "Device Id:\t" );
printHex( Connect_id );
print( NL "Master <=" NL "\tStatus:\t");
printHex( Connect_cableOkMaster );
print( NL "\tFaults:\t");
printHex( Connect_cableFaultsMaster );
print( NL "\tRx:\t");
printHex( uart1_rx_status );
print( NL "\tTx:\t");
printHex( uart1_tx_status );
print( NL "Slave <=" NL "\tStatus:\t");
printHex( Connect_cableOkSlave );
print( NL "\tFaults:\t");
printHex( Connect_cableFaultsSlave );
print( NL "\tRx:\t");
printHex( uart0_rx_status );
print( NL "\tTx:\t");
printHex( uart0_tx_status );
}

View File

@ -0,0 +1,122 @@
/* Copyright (C) 2014-2015 by Jacob Alexander
*
* This file is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this file. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CONNECT_SCAN_H
#define __CONNECT_SCAN_H
// ----- Includes -----
// Project Includes
#include <kll.h>
// ----- Enums -----
// Functions
typedef enum Command {
CableCheck = 0, // Comm check
IdRequest = 1, // Slave initialization (request id from master)
IdEnumeration = 2, // Slave initialization (begin enumeration from master)
IdReport = 3, // Slave initialization complete, report id to master
ScanCode = 4, // ScanCode event status change
Animation = 5, // Master trigger animation event (same command is sent back to master when ready)
} Command;
// UART Rx/Tx Status
typedef enum UARTStatus {
UARTStatus_Wait = 0, // Waiting Rx: for SYN Tx: for current command copy to finish
UARTStatus_SYN = 1, // Rx: SYN Received, waiting for SOH
UARTStatus_SOH = 2, // Rx: SOH Received, waiting for Command
UARTStatus_Command = 3, // Rx: Command Received, waiting for data
UARTStatus_Ready = 4, // Tx: Ready to receive commands
} UARTStatus;
// ----- Structs -----
// UART Connect Commands
// Cable Check Command
// Called on each UART every few seconds to make sure there is a connection
// Also used to make sure there aren't any serious problems with the cable with data corruption
// This command must pass before sending any other commands on the particular UART
// Each argument is always 0xD2 (11010010)
typedef struct CableCheckCommand {
Command command;
uint8_t numArgs;
uint8_t firstArg[0];
} CableCheckCommand;
// Id Request Command
// Issued by the slave device (non-master) whenever it is powered up
// Do not issue any commands until given an Id
// (Except for Cable Check and IdRequestCommand)
typedef struct IdRequestCommand {
Command command;
} IdRequestCommand;
// Id Enumeration Command
// Issued by the master whenever an Id Request is received
// XXX Future work may include an "external capabilities" list in this command
typedef struct IdEnumerationCommand {
Command command;
uint8_t id;
} IdEnumerationCommand;
// Id Report Command
// Issued by each slave to the master when assigned an Id
// XXX Future work will include an "external capabilities" list in this command
typedef struct IdReportCommand {
Command command;
uint8_t id;
} IdReportCommand;
// Scan Code Command
// Sent from the slave to the master whenever there is a scan code state change
typedef struct ScanCodeCommand {
Command command;
uint8_t id;
uint8_t numScanCodes;
TriggerGuide firstScanCode[0];
} ScanCodeCommand;
// Animation Command
// Initiated by the master whenever an animation id should modify it's state
// Then after the leaf slave node receives the command, send it back to the master
// On the way back, each device can begin the animation adjustment
//
// The master->leaf command should indicate to each device that it should finish sending the
// current slave->master data and wait for the leaf->master command
// This allows for a tighter synchronization of animation events
typedef struct AnimationCommand {
Command command;
uint8_t animationId;
uint8_t numParams;
uint8_t firstParam[0];
} AnimationCommand;
// ----- Functions -----
void Connect_setup( uint8_t master );
void Connect_scan();
#endif // __CONNECT_SCAN_H

View File

@ -0,0 +1,30 @@
###| CMake Kiibohd Controller Scan Module |###
#
# Written by Jacob Alexander in 2014-2015 for the Kiibohd Controller
#
# Released into the Public Domain
#
###
###
# Sub-module flag, cannot be included stand-alone
#
set ( SubModule 1 )
###
# Module C files
#
set ( Module_SRCS
connect_scan.c
)
###
# Compiler Family Compatibility
#
set ( ModuleCompatibility
arm
)