Send and receive bytes serially. More...
#include "inc/freeEMS.h"
#include "inc/interrupts.h"
#include "inc/utils.h"
#include "inc/commsCore.h"
#include "inc/commsISRs.h"
Go to the source code of this file.
Defines | |
#define | COMMSISRS_C |
Functions | |
void | sendAndIncrement (unsigned char rawValue) |
Send And Increment. | |
void | receiveAndIncrement (const unsigned char value) |
Receive And Increment. | |
void | resetReceiveState (unsigned char sourceIDState) |
Reset Receive State. | |
void | SCI0ISR () |
Serial Communication Interface 0 ISR. |
Send and receive bytes serially.
This file contains the code for both send and receive of serial bytes through the UART SCI0 device. It is purely interrupt driven and controlled by a set of register and non-register flags that are toggled both inside and outside this file. Some additional helper functions are also kept here.
Definition in file commsISRs.c.
#define COMMSISRS_C |
Definition at line 44 of file commsISRs.c.
void receiveAndIncrement | ( | const unsigned char | value | ) | [inline] |
Receive And Increment.
Store the value and add it to the checksum, then increment the pointer and length.
value | is the byte of data to store in the buffer and add to the checksum. |
Definition at line 84 of file commsISRs.c.
References RXBufferCurrentPosition, RXCalculatedChecksum, and RXPacketLengthReceived.
Referenced by SCI0ISR().
00084 { 00085 *RXBufferCurrentPosition = value; 00086 RXCalculatedChecksum += value; 00087 RXBufferCurrentPosition++; 00088 RXPacketLengthReceived++; 00089 }
void resetReceiveState | ( | unsigned char | sourceIDState | ) |
Reset Receive State.
Reset communications reception to the state provided.
sourceIDState | is the state to apply to the RX buffer state variable. |
Definition at line 102 of file commsISRs.c.
References COM_SET_CAN0_INTERFACE_ID, COM_SET_SCI0_INTERFACE_ID, RXBufferContentSourceID, RXBufferCurrentPosition, RXCalculatedChecksum, RXPacketLengthReceived, RXStateFlags, SCI0CR2, SCICR2_RX_DISABLE, SCICR2_RX_ENABLE, SCICR2_RX_ISR_DISABLE, and SCICR2_RX_ISR_ENABLE.
Referenced by decodePacketAndRespond(), and SCI0ISR().
00102 { 00103 /* Set the receive buffer pointer to the beginning */ 00104 RXBufferCurrentPosition = (unsigned char*)&RXBuffer; 00105 00106 /* Zero the flags, buffer length and checksum */ 00107 RXPacketLengthReceived = 0; 00108 RXCalculatedChecksum = 0; 00109 RXStateFlags = 0; 00110 00111 /* Set the source ID state (clear all or all but one flag(s)) */ 00112 RXBufferContentSourceID = sourceIDState; 00113 00114 /* Which ever interface we are setting is the one we came from. By definition */ 00115 /* it must be on and we want it to stay on, so just turn off all the others. */ 00116 if(sourceIDState & COM_SET_SCI0_INTERFACE_ID){ 00117 /* Turn off all others here */ 00120 /* SPI ? I2C ? SCI1 ? */ 00121 }else if(sourceIDState & COM_SET_CAN0_INTERFACE_ID){ 00122 /* Turn off all others here */ 00123 /* Only SCI for now */ 00124 SCI0CR2 &= SCICR2_RX_DISABLE; 00125 SCI0CR2 &= SCICR2_RX_ISR_DISABLE; 00126 /* SPI ? I2C ? SCI1 ? */ 00127 }else{ /* If clearing all flags then enable RX on all interfaces */ 00128 /* Only SCI for now */ 00129 SCI0CR2 |= SCICR2_RX_ENABLE; 00130 SCI0CR2 |= SCICR2_RX_ISR_ENABLE; 00133 /* SPI ? I2C ? SCI1 ? */ 00134 } 00135 }
void SCI0ISR | ( | void | ) |
Serial Communication Interface 0 ISR.
SCI0 ISR handles all interrupts for SCI0 by reading flags and acting appropriately. Its functions are to send raw bytes out over the wire from a buffer and to receive bytes from the wire un-escape them, checksum them and store them in a buffer.
TODO Move this code into an include file much like the fuel interrupts such that it can be used for multiple UART SCI devices without duplication.
TODO Remove the debug code that uses the IO ports to light LEDs during specific actions.
Definition at line 150 of file commsISRs.c.
References BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, CLEAR_ALL_SOURCE_ID_FLAGS, COM_CLEAR_SCI0_INTERFACE_ID, COM_SET_SCI0_INTERFACE_ID, Counter::commsChecksumMismatches, Counters, ESCAPE_BYTE, ESCAPED_ESCAPE_BYTE, ESCAPED_START_BYTE, ESCAPED_STOP_BYTE, PORTA, PORTB, receiveAndIncrement(), resetReceiveState(), RuntimeVars, RX_BUFFER_SIZE, RX_READY_TO_PROCESS, RX_SCI_ESCAPED_NEXT, RX_SCI_NOT_ESCAPED_NEXT, RXBufferContentSourceID, RXBufferCurrentPosition, RXCalculatedChecksum, RXPacketLengthReceived, RXStateFlags, SCI0CR2, SCI0DRL, SCI0SR1, SCICR2_RX_DISABLE, SCICR2_RX_ISR_DISABLE, SCICR2_RX_ISR_ENABLE, SCICR2_TX_ISR_DISABLE, SCICR2_TX_ISR_ENABLE, SCISR1_RX_FRAMING, SCISR1_RX_NOISE, SCISR1_RX_OVERRUN, SCISR1_RX_PARITY, SCISR1_RX_REGISTER_FULL, SCISR1_TX_REGISTER_EMPTY, sendAndIncrement(), Counter::serialEscapePairMismatches, Counter::serialFramingErrors, RuntimeVar::serialISRRuntime, Counter::serialNoiseErrors, Counter::serialOverrunErrors, Counter::serialPacketsOverLength, Counter::serialParityErrors, Counter::serialStartsInsideAPacket, START_BYTE, STOP_BYTE, TCNT, TXBufferCurrentPositionSCI0, TXBufferInUseFlags, TXByteEscaped, and TXPacketLengthToSendSCI0.
00150 { 00151 /* Read the flags register */ 00152 unsigned char flags = SCI0SR1; 00153 /* Note: Combined with reading or writing the data register this also clears the flags. */ 00154 00155 /* Start counting */ 00156 unsigned short start = TCNT; 00157 00158 /* If the RX interrupt is enabled check RX related flags */ 00159 if(SCI0CR2 & SCICR2_RX_ISR_ENABLE){ 00160 /* Grab the received byte from the register */ 00161 unsigned char rawByte = SCI0DRL; 00162 00163 PORTB |= BIT0; 00164 00165 /* Record error conditions always */ 00166 unsigned char resetOnError = 0; 00167 /* If there is noise on the receive line record it */ 00168 if(flags & SCISR1_RX_NOISE){ 00169 Counters.serialNoiseErrors++; 00170 resetOnError++; 00171 }/* If an overrun occurs record it */ 00172 if(flags & SCISR1_RX_OVERRUN){ 00173 Counters.serialOverrunErrors++; 00174 resetOnError++; 00175 }/* If a framing error occurs record it */ 00176 if(flags & SCISR1_RX_FRAMING){ 00177 Counters.serialFramingErrors++; 00178 resetOnError++; 00179 }/* If a parity error occurs record it */ 00180 if(flags & SCISR1_RX_PARITY){ 00181 Counters.serialParityErrors++; 00182 resetOnError++; 00183 } 00184 00185 /* Drop out because of error flags */ 00186 if(resetOnError){ 00187 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS); 00188 PORTB |= BIT1; 00189 return; 00190 } 00191 00192 /* If there is data waiting to be received */ 00193 if(flags & SCISR1_RX_REGISTER_FULL){ 00194 PORTB |= BIT2; 00195 /* Look for a start bresetReceiveStateyte to indicate a new packet */ 00196 if(rawByte == START_BYTE){ 00197 PORTB |= BIT3; 00198 /* If another interface is using it (Note, clear flag, not normal) */ 00199 if(RXBufferContentSourceID & COM_CLEAR_SCI0_INTERFACE_ID){ 00200 /* Turn off our reception */ 00201 SCI0CR2 &= SCICR2_RX_DISABLE; 00202 SCI0CR2 &= SCICR2_RX_ISR_DISABLE; 00203 PORTB |= BIT4; 00204 }else{ 00205 PORTB |= BIT5; 00206 /* If we are using it */ 00207 if(RXBufferContentSourceID & COM_SET_SCI0_INTERFACE_ID){ 00208 /* Increment the counter */ 00209 Counters.serialStartsInsideAPacket++; 00210 } 00211 /* Reset to us using it unless someone else was */ 00212 resetReceiveState(COM_SET_SCI0_INTERFACE_ID); 00213 } 00214 }else if(RXPacketLengthReceived >= RX_BUFFER_SIZE){ 00215 /* Buffer was full, record and reset */ 00216 Counters.serialPacketsOverLength++; 00217 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS); 00218 PORTB |= BIT6; 00219 }else if(RXBufferContentSourceID & COM_SET_SCI0_INTERFACE_ID){ 00220 if(RXStateFlags & RX_SCI_ESCAPED_NEXT){ 00221 PORTB |= BIT7; 00222 /* Clear escaped byte next flag, thanks Karsten! ((~ != !) == (! ~= ~)) == LOL */ 00223 RXStateFlags &= RX_SCI_NOT_ESCAPED_NEXT; 00224 00225 if(rawByte == ESCAPED_ESCAPE_BYTE){ 00226 /* Store and checksum escape byte */ 00227 receiveAndIncrement(ESCAPE_BYTE); 00228 }else if(rawByte == ESCAPED_START_BYTE){ 00229 /* Store and checksum start byte */ 00230 receiveAndIncrement(START_BYTE); 00231 }else if(rawByte == ESCAPED_STOP_BYTE){ 00232 /* Store and checksum stop byte */ 00233 receiveAndIncrement(STOP_BYTE); 00234 }else{ 00235 /* Otherwise reset and record as data is bad */ 00236 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS); 00237 Counters.serialEscapePairMismatches++; 00238 } 00239 }else if(rawByte == ESCAPE_BYTE){ 00240 PORTA |= BIT0; 00241 /* Set flag to indicate that the next byte should be un-escaped. */ 00242 RXStateFlags |= RX_SCI_ESCAPED_NEXT; 00243 }else if(rawByte == STOP_BYTE){ 00244 PORTA |= BIT1; 00245 /* Turn off reception */ 00246 SCI0CR2 &= SCICR2_RX_DISABLE; 00247 SCI0CR2 &= SCICR2_RX_ISR_DISABLE; 00248 00249 /* Bring the checksum back to where it should be */ 00250 unsigned char RXReceivedChecksum = (unsigned char)*(RXBufferCurrentPosition - 1); 00251 RXCalculatedChecksum -= RXReceivedChecksum; 00252 00253 /* Check that the checksum matches */ 00254 if(RXCalculatedChecksum == RXReceivedChecksum){ 00255 /* If it's OK set process flag */ 00256 RXStateFlags |= RX_READY_TO_PROCESS; 00257 PORTA |= BIT2; 00258 }else{ 00259 PORTA |= BIT3; 00260 /* Otherwise reset the state and record it */ 00261 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS); 00262 Counters.commsChecksumMismatches++; 00263 } 00264 }else{ 00265 PORTA |= BIT4; 00266 /* If it isn't special process it! */ 00267 receiveAndIncrement(rawByte); 00268 } 00269 }else{ 00270 /* Do nothing : drop the byte */ 00271 PORTA |= BIT5; 00272 } 00273 } 00274 } 00275 00276 /* If the TX interrupt is enabled check the register empty flag. */ 00277 if((SCI0CR2 & SCICR2_TX_ISR_ENABLE) && (flags & SCISR1_TX_REGISTER_EMPTY)){ 00278 /* Get the byte to be sent from the buffer */ 00279 unsigned char rawValue = *TXBufferCurrentPositionSCI0; 00280 00281 if(TXPacketLengthToSendSCI0 > 0){ 00282 if(TXByteEscaped == 0){ 00283 /* If the raw value needs to be escaped */ 00284 if(rawValue == ESCAPE_BYTE){ 00285 SCI0DRL = ESCAPE_BYTE; 00286 TXByteEscaped = ESCAPED_ESCAPE_BYTE; 00287 }else if(rawValue == START_BYTE){ 00288 SCI0DRL = ESCAPE_BYTE; 00289 TXByteEscaped = ESCAPED_START_BYTE; 00290 }else if(rawValue == STOP_BYTE){ 00291 SCI0DRL = ESCAPE_BYTE; 00292 TXByteEscaped = ESCAPED_STOP_BYTE; 00293 }else{ /* Otherwise just send it */ 00294 sendAndIncrement(rawValue); 00295 } 00296 }else{ 00297 sendAndIncrement(TXByteEscaped); 00298 TXByteEscaped = 0; 00299 } 00300 }else{ /* Length is zero */ 00301 /* Turn off transmission interrupt */ 00302 SCI0CR2 &= SCICR2_TX_ISR_DISABLE; 00303 /* Send the stop byte */ 00304 SCI0DRL = STOP_BYTE; 00305 while(!(SCI0SR1 & 0x80)){/* Wait for ever until able to send then move on */} 00306 SCI0DRL = STOP_BYTE; // nasty hack that works... means at least one and most 2 stops are sent so stuff works, but is messy... there must be a better way. 00307 /* Clear the TX in progress flag */ 00308 TXBufferInUseFlags &= COM_CLEAR_SCI0_INTERFACE_ID; 00309 } 00310 } 00311 00312 /* Record how long the operation took */ 00313 RuntimeVars.serialISRRuntime = TCNT - start; 00314 }
void sendAndIncrement | ( | unsigned char | rawValue | ) | [inline] |
Send And Increment.
Increment the pointer, decrement the length, and send it!
rawValue | is the raw byte to be sent down the serial line. |
Definition at line 67 of file commsISRs.c.
References SCI0DRL, TXBufferCurrentPositionSCI0, and TXPacketLengthToSendSCI0.
Referenced by SCI0ISR().
00067 { 00068 SCI0DRL = rawValue; 00069 TXPacketLengthToSendSCI0--; 00070 TXBufferCurrentPositionSCI0++; 00071 }