00001 /* Copyright 2008 Fred Cooke 00002 00003 This file is part of the FreeEMS project. 00004 00005 FreeEMS software is free software: you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation, either version 3 of the License, or 00008 (at your option) any later version. 00009 00010 FreeEMS software is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with any FreeEMS software. If not, see http://www.gnu.org/licenses/ 00017 00018 We ask that if you make any changes to this file you email them upstream to 00019 us at admin(at)diyefi(dot)org or, even better, fork the code on github.com! 00020 00021 Thank you for choosing FreeEMS to run your engine! */ 00022 00023 00041 #define COMMSISRS_C 00042 #include "inc/freeEMS.h" 00043 #include "inc/interrupts.h" 00044 #include "inc/utils.h" 00045 #include "inc/commsCore.h" 00046 #include "inc/commsISRs.h" 00047 00048 00049 /* The C89 standard is used in the 3.3.6 GCC compiler, please * 00050 * see the following URL for more info on inline functions : * 00051 * http://gcc.gnu.org/onlinedocs/gcc-3.3.6/Inline.html#Inline */ 00052 00053 00064 extern inline void sendAndIncrement(unsigned char rawValue){ 00065 SCI0DRL = rawValue; 00066 TXPacketLengthToSendSCI0--; 00067 TXBufferCurrentPositionSCI0++; 00068 } 00069 00070 00081 extern inline void receiveAndIncrement(const unsigned char value){ 00082 *RXBufferCurrentPosition = value; 00083 RXCalculatedChecksum += value; 00084 RXBufferCurrentPosition++; 00085 RXPacketLengthReceived++; 00086 } 00087 00088 00099 void resetReceiveState(unsigned char sourceIDState){ 00100 /* Set the receive buffer pointer to the beginning */ 00101 RXBufferCurrentPosition = (unsigned char*)&RXBuffer; 00102 00103 /* Zero the flags, buffer length and checksum */ 00104 RXPacketLengthReceived = 0; 00105 RXCalculatedChecksum = 0; 00106 RXStateFlags = 0; 00107 00108 /* Set the source ID state (clear all or all but one flag(s)) */ 00109 RXBufferContentSourceID = sourceIDState; 00110 00111 /* Which ever interface we are setting is the one we came from. By definition */ 00112 /* it must be on and we want it to stay on, so just turn off all the others. */ 00113 if(sourceIDState & COM_SET_SCI0_INTERFACE_ID){ 00114 /* Turn off all others here */ 00117 /* SPI ? I2C ? SCI1 ? */ 00118 }else if(sourceIDState & COM_SET_CAN0_INTERFACE_ID){ 00119 /* Turn off all others here */ 00120 /* Only SCI for now */ 00121 SCI0CR2 &= SCICR2_RX_DISABLE; 00122 SCI0CR2 &= SCICR2_RX_ISR_DISABLE; 00123 /* SPI ? I2C ? SCI1 ? */ 00124 }else{ /* If clearing all flags then enable RX on all interfaces */ 00125 /* Only SCI for now */ 00126 SCI0CR2 |= SCICR2_RX_ENABLE; 00127 SCI0CR2 |= SCICR2_RX_ISR_ENABLE; 00130 /* SPI ? I2C ? SCI1 ? */ 00131 } 00132 } 00133 00134 00147 void SCI0ISR(){ 00148 /* Read the flags register */ 00149 unsigned char flags = SCI0SR1; 00150 /* Note: Combined with reading or writing the data register this also clears the flags. */ 00151 00152 /* Start counting */ 00153 unsigned short start = TCNT; 00154 00155 /* If the RX interrupt is enabled check RX related flags */ 00156 if(SCI0CR2 & SCICR2_RX_ISR_ENABLE){ 00157 /* Grab the received byte from the register */ 00158 unsigned char rawByte = SCI0DRL; 00159 00160 PORTB |= BIT0; 00161 00162 /* Record error conditions always */ 00163 unsigned char resetOnError = 0; 00164 /* If there is noise on the receive line record it */ 00165 if(flags & SCISR1_RX_NOISE){ 00166 Counters.serialNoiseErrors++; 00167 resetOnError++; 00168 }/* If an overrun occurs record it */ 00169 if(flags & SCISR1_RX_OVERRUN){ 00170 Counters.serialOverrunErrors++; 00171 resetOnError++; 00172 }/* If a framing error occurs record it */ 00173 if(flags & SCISR1_RX_FRAMING){ 00174 Counters.serialFramingErrors++; 00175 resetOnError++; 00176 }/* If a parity error occurs record it */ 00177 if(flags & SCISR1_RX_PARITY){ 00178 Counters.serialParityErrors++; 00179 resetOnError++; 00180 } 00181 00182 /* Drop out because of error flags */ 00183 if(resetOnError){ 00184 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS); 00185 PORTB |= BIT1; 00186 return; 00187 } 00188 00189 /* If there is data waiting to be received */ 00190 if(flags & SCISR1_RX_REGISTER_FULL){ 00191 PORTB |= BIT2; 00192 /* Look for a start bresetReceiveStateyte to indicate a new packet */ 00193 if(rawByte == START_BYTE){ 00194 PORTB |= BIT3; 00195 /* If another interface is using it (Note, clear flag, not normal) */ 00196 if(RXBufferContentSourceID & COM_CLEAR_SCI0_INTERFACE_ID){ 00197 /* Turn off our reception */ 00198 SCI0CR2 &= SCICR2_RX_DISABLE; 00199 SCI0CR2 &= SCICR2_RX_ISR_DISABLE; 00200 PORTB |= BIT4; 00201 }else{ 00202 PORTB |= BIT5; 00203 /* If we are using it */ 00204 if(RXBufferContentSourceID & COM_SET_SCI0_INTERFACE_ID){ 00205 /* Increment the counter */ 00206 Counters.serialStartsInsideAPacket++; 00207 } 00208 /* Reset to us using it unless someone else was */ 00209 resetReceiveState(COM_SET_SCI0_INTERFACE_ID); 00210 } 00211 }else if(RXPacketLengthReceived >= RX_BUFFER_SIZE){ 00212 /* Buffer was full, record and reset */ 00213 Counters.serialPacketsOverLength++; 00214 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS); 00215 PORTB |= BIT6; 00216 }else if(RXBufferContentSourceID & COM_SET_SCI0_INTERFACE_ID){ 00217 if(RXStateFlags & RX_SCI_ESCAPED_NEXT){ 00218 PORTB |= BIT7; 00219 /* Clear escaped byte next flag, thanks Karsten! ((~ != !) == (! ~= ~)) == LOL */ 00220 RXStateFlags &= RX_SCI_NOT_ESCAPED_NEXT; 00221 00222 if(rawByte == ESCAPED_ESCAPE_BYTE){ 00223 /* Store and checksum escape byte */ 00224 receiveAndIncrement(ESCAPE_BYTE); 00225 }else if(rawByte == ESCAPED_START_BYTE){ 00226 /* Store and checksum start byte */ 00227 receiveAndIncrement(START_BYTE); 00228 }else if(rawByte == ESCAPED_STOP_BYTE){ 00229 /* Store and checksum stop byte */ 00230 receiveAndIncrement(STOP_BYTE); 00231 }else{ 00232 /* Otherwise reset and record as data is bad */ 00233 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS); 00234 Counters.serialEscapePairMismatches++; 00235 } 00236 }else if(rawByte == ESCAPE_BYTE){ 00237 PORTA |= BIT0; 00238 /* Set flag to indicate that the next byte should be un-escaped. */ 00239 RXStateFlags |= RX_SCI_ESCAPED_NEXT; 00240 }else if(rawByte == STOP_BYTE){ 00241 PORTA |= BIT1; 00242 /* Turn off reception */ 00243 SCI0CR2 &= SCICR2_RX_DISABLE; 00244 SCI0CR2 &= SCICR2_RX_ISR_DISABLE; 00245 00246 /* Bring the checksum back to where it should be */ 00247 unsigned char RXReceivedChecksum = (unsigned char)*(RXBufferCurrentPosition - 1); 00248 RXCalculatedChecksum -= RXReceivedChecksum; 00249 00250 /* Check that the checksum matches */ 00251 if(RXCalculatedChecksum == RXReceivedChecksum){ 00252 /* If it's OK set process flag */ 00253 RXStateFlags |= RX_READY_TO_PROCESS; 00254 PORTA |= BIT2; 00255 }else{ 00256 PORTA |= BIT3; 00257 /* Otherwise reset the state and record it */ 00258 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS); 00259 Counters.commsChecksumMismatches++; 00260 } 00261 }else{ 00262 PORTA |= BIT4; 00263 /* If it isn't special process it! */ 00264 receiveAndIncrement(rawByte); 00265 } 00266 }else{ 00267 /* Do nothing : drop the byte */ 00268 PORTA |= BIT5; 00269 } 00270 } 00271 } 00272 00273 /* If the TX interrupt is enabled check the register empty flag. */ 00274 if((SCI0CR2 & SCICR2_TX_ISR_ENABLE) && (flags & SCISR1_TX_REGISTER_EMPTY)){ 00275 /* Get the byte to be sent from the buffer */ 00276 unsigned char rawValue = *TXBufferCurrentPositionSCI0; 00277 00278 if(TXPacketLengthToSendSCI0 > 0){ 00279 if(TXByteEscaped == 0){ 00280 /* If the raw value needs to be escaped */ 00281 if(rawValue == ESCAPE_BYTE){ 00282 SCI0DRL = ESCAPE_BYTE; 00283 TXByteEscaped = ESCAPED_ESCAPE_BYTE; 00284 }else if(rawValue == START_BYTE){ 00285 SCI0DRL = ESCAPE_BYTE; 00286 TXByteEscaped = ESCAPED_START_BYTE; 00287 }else if(rawValue == STOP_BYTE){ 00288 SCI0DRL = ESCAPE_BYTE; 00289 TXByteEscaped = ESCAPED_STOP_BYTE; 00290 }else{ /* Otherwise just send it */ 00291 sendAndIncrement(rawValue); 00292 } 00293 }else{ 00294 sendAndIncrement(TXByteEscaped); 00295 TXByteEscaped = 0; 00296 } 00297 }else{ /* Length is zero */ 00298 /* Turn off transmission interrupt */ 00299 SCI0CR2 &= SCICR2_TX_ISR_DISABLE; 00300 /* Send the stop byte */ 00301 SCI0DRL = STOP_BYTE; 00302 /* Clear the TX in progress flag */ 00303 TXBufferInUseFlags &= COM_CLEAR_SCI0_INTERFACE_ID; 00304 } 00305 } 00306 00307 /* Record how long the operation took */ 00308 RuntimeVars.serialISRRuntime = TCNT - start; 00309 }