00001 /* commsISRs.c 00002 00003 Copyright 2008 Fred Cooke 00004 00005 This file is part of the FreeEMS project. 00006 00007 FreeEMS software is free software: you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation, either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 FreeEMS software is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with any FreeEMS software. If not, see <http://www.gnu.org/licenses/>. 00019 00020 We ask that if you make any changes to this file you send them upstream to us at admin@diyefi.org 00021 00022 Thank you for choosing FreeEMS to run your engine! */ 00023 00024 #define COMMSISRS_C 00025 #include "inc/freeEMS.h" 00026 #include "inc/interrupts.h" 00027 #include "inc/utils.h" 00028 #include "inc/commsCore.h" 00029 #include "inc/commsISRs.h" 00030 00031 00032 /* The C89 standard is used in the 3.3.6 GCC compiler, please * 00033 * see the following URL for more info on inline functions : * 00034 * http://gcc.gnu.org/onlinedocs/gcc-3.3.6/Inline.html#Inline */ 00035 00036 00037 /* Increment the pointer, decrement the length, and send it! */ 00038 extern inline void sendAndIncrement(unsigned char rawValue){ 00039 SCI0DRL = rawValue; 00040 TXPacketLengthToSendSCI0--; 00041 TXBufferCurrentPositionSCI0++; 00042 } 00043 00044 00045 /* Store and checksum the value, then increment the pointer and length */ 00046 extern inline void receiveAndIncrement(const unsigned char value){ 00047 *RXBufferCurrentPosition = value; 00048 RXCalculatedChecksum += value; 00049 RXBufferCurrentPosition++; 00050 RXPacketLengthReceived++; 00051 } 00052 00053 00054 /* Reset serial reception to one of two states */ 00055 void resetReceiveState(unsigned char sourceIDState){ // WRONG 00056 /* Set the receive buffer pointer to the beginning */ 00057 RXBufferCurrentPosition = (unsigned char*)&RXBuffer; 00058 00059 /* Zero the flags, buffer length and checksum */ 00060 RXPacketLengthReceived = 0; 00061 RXCalculatedChecksum = 0; 00062 RXStateFlags = 0; 00063 00064 /* Set the source ID state (clear all or all but one flag(s)) */ 00065 RXBufferContentSourceID = sourceIDState; 00066 00067 /* Which ever interface we are setting is the one we came from. By definition */ 00068 /* it must be on and we want it to stay on, so just turn off all the others. */ 00069 if(sourceIDState & COM_SET_SCI0_INTERFACE_ID){ 00070 /* Turn off all others here */ 00071 // TODO CAN0CTL1 &= CANCTL1_RX_DISABLE; 00072 // TODO CAN0CTL1 &= CANCTL1_RX_ISR_DISABLE; 00073 /* SPI ? I2C ? SCI1 ? */ 00074 }else if(sourceIDState & COM_SET_CAN0_INTERFACE_ID){ 00075 /* Turn off all others here */ 00076 /* Only SCI for now */ 00077 SCI0CR2 &= SCICR2_RX_DISABLE; 00078 SCI0CR2 &= SCICR2_RX_ISR_DISABLE; 00079 /* SPI ? I2C ? SCI1 ? */ 00080 }else{ /* If clearing all flags then enable RX on all interfaces */ 00081 /* Only SCI for now */ 00082 SCI0CR2 |= SCICR2_RX_ENABLE; 00083 SCI0CR2 |= SCICR2_RX_ISR_ENABLE; 00084 // TODO CAN0CTL1 |= CANCTL1_RX_ENABLE; 00085 // TODO CAN0CTL1 |= CANCTL1_RX_ISR_ENABLE; 00086 /* SPI ? I2C ? SCI1 ? */ 00087 } 00088 } 00089 00090 00091 /* SCI0 ISR handles all interrupts for SCI0 by reading the flag registers and acting appropriately. */ 00092 void SCI0ISR(void){ 00093 /* Read the flags register */ 00094 unsigned char flags = SCI0SR1; 00095 /* Note: Combined with reading or writing the data register this also clears the flags. */ 00096 00097 /* Start counting */ 00098 unsigned short start = TCNT; 00099 00100 /* If the RX interrupt is enabled check RX related flags */ 00101 if(SCI0CR2 & SCICR2_RX_ISR_ENABLE){ 00102 /* Grab the received byte from the register */ 00103 unsigned char rawByte = SCI0DRL; 00104 00105 PORTB |= BIT0; 00106 00107 /* Record error conditions always */ 00108 unsigned char resetOnError = 0; 00109 /* If there is noise on the receive line record it */ 00110 if(flags & SCISR1_RX_NOISE){ 00111 Counters.serialNoiseErrors++; 00112 resetOnError++; 00113 }/* If an overrun occurs record it */ 00114 if(flags & SCISR1_RX_OVERRUN){ 00115 Counters.serialOverrunErrors++; 00116 resetOnError++; 00117 }/* If a framing error occurs record it */ 00118 if(flags & SCISR1_RX_FRAMING){ 00119 Counters.serialFramingErrors++; 00120 resetOnError++; 00121 }/* If a parity error occurs record it */ 00122 if(flags & SCISR1_RX_PARITY){ 00123 Counters.serialParityErrors++; 00124 resetOnError++; 00125 } 00126 00127 /* Drop out because of error flags */ 00128 if(resetOnError){ 00129 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS); 00130 PORTB |= BIT1; 00131 return; 00132 } 00133 00134 /* If there is data waiting to be received */ 00135 if(flags & SCISR1_RX_REGISTER_FULL){ 00136 PORTB |= BIT2; 00137 /* Look for a start bresetReceiveStateyte to indicate a new packet */ 00138 if(rawByte == START_BYTE){ 00139 PORTB |= BIT3; 00140 /* If another interface is using it (Note, clear flag, not normal) */ 00141 if(RXBufferContentSourceID & COM_CLEAR_SCI0_INTERFACE_ID){ 00142 /* Turn off our reception */ 00143 SCI0CR2 &= SCICR2_RX_DISABLE; 00144 SCI0CR2 &= SCICR2_RX_ISR_DISABLE; 00145 PORTB |= BIT4; 00146 }else{ 00147 PORTB |= BIT5; 00148 /* If we are using it */ 00149 if(RXBufferContentSourceID & COM_SET_SCI0_INTERFACE_ID){ 00150 /* Increment the counter */ 00151 Counters.serialStartsInsideAPacket++; 00152 } 00153 /* Reset to us using it unless someone else was */ 00154 resetReceiveState(COM_SET_SCI0_INTERFACE_ID); 00155 } 00156 }else if(RXPacketLengthReceived >= RX_BUFFER_SIZE){ 00157 /* Buffer was full, record and reset */ 00158 Counters.serialPacketsOverLength++; 00159 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS); 00160 PORTB |= BIT6; 00161 }else if(RXBufferContentSourceID & COM_SET_SCI0_INTERFACE_ID){ 00162 if(RXStateFlags & RX_SCI_ESCAPED_NEXT){ 00163 PORTB |= BIT7; 00164 /* Clear escaped byte next flag, thanks Karsten! ((~ != !) == (! ~= ~)) == LOL */ 00165 RXStateFlags &= RX_SCI_NOT_ESCAPED_NEXT; 00166 00167 if(rawByte == ESCAPED_ESCAPE_BYTE){ 00168 /* Store and checksum escape byte */ 00169 receiveAndIncrement(ESCAPE_BYTE); 00170 }else if(rawByte == ESCAPED_START_BYTE){ 00171 /* Store and checksum start byte */ 00172 receiveAndIncrement(START_BYTE); 00173 }else if(rawByte == ESCAPED_STOP_BYTE){ 00174 /* Store and checksum stop byte */ 00175 receiveAndIncrement(STOP_BYTE); 00176 }else{ 00177 /* Otherwise reset and record as data is bad */ 00178 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS); 00179 Counters.serialEscapePairMismatches++; 00180 } 00181 }else if(rawByte == ESCAPE_BYTE){ 00182 PORTA |= BIT0; 00183 /* Set flag to indicate that the next byte should be un-escaped. */ 00184 RXStateFlags |= RX_SCI_ESCAPED_NEXT; 00185 }else if(rawByte == STOP_BYTE){ 00186 PORTA |= BIT1; 00187 /* Turn off reception */ 00188 SCI0CR2 &= SCICR2_RX_DISABLE; 00189 SCI0CR2 &= SCICR2_RX_ISR_DISABLE; 00190 00191 /* Bring the checksum back to where it should be */ 00192 unsigned char RXReceivedChecksum = (unsigned char)*(RXBufferCurrentPosition - 1); 00193 RXCalculatedChecksum -= RXReceivedChecksum; 00194 00195 /* Check that the checksum matches */ 00196 if(RXCalculatedChecksum == RXReceivedChecksum){ 00197 /* If it's OK set process flag */ 00198 RXStateFlags |= RX_READY_TO_PROCESS; 00199 PORTA |= BIT2; 00200 }else{ 00201 PORTA |= BIT3; 00202 /* Otherwise reset the state and record it */ 00203 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS); 00204 Counters.commsChecksumMismatches++; 00205 } 00206 }else{ 00207 PORTA |= BIT4; 00208 /* If it isn't special process it! */ 00209 receiveAndIncrement(rawByte); 00210 } 00211 }else{ 00212 /* Do nothing : drop the byte */ 00213 PORTA |= BIT5; 00214 } 00215 } 00216 } 00217 00218 /* If the TX interrupt is enabled check the register empty flag. */ 00219 if((SCI0CR2 & SCICR2_TX_ISR_ENABLE) && (flags & SCISR1_TX_REGISTER_EMPTY)){ 00220 /* Get the byte to be sent from the buffer */ 00221 unsigned char rawValue = *TXBufferCurrentPositionSCI0; 00222 00223 if(TXPacketLengthToSendSCI0 > 0){ 00224 if(TXByteEscaped == 0){ 00225 /* If the raw value needs to be escaped */ 00226 if(rawValue == ESCAPE_BYTE){ 00227 SCI0DRL = ESCAPE_BYTE; 00228 TXByteEscaped = ESCAPED_ESCAPE_BYTE; 00229 }else if(rawValue == START_BYTE){ 00230 SCI0DRL = ESCAPE_BYTE; 00231 TXByteEscaped = ESCAPED_START_BYTE; 00232 }else if(rawValue == STOP_BYTE){ 00233 SCI0DRL = ESCAPE_BYTE; 00234 TXByteEscaped = ESCAPED_STOP_BYTE; 00235 }else{ /* Otherwise just send it */ 00236 sendAndIncrement(rawValue); 00237 } 00238 }else{ 00239 sendAndIncrement(TXByteEscaped); 00240 TXByteEscaped = 0; 00241 } 00242 }else{ /* Length is zero */ 00243 /* Turn off transmission interrupt */ 00244 SCI0CR2 &= SCICR2_TX_ISR_DISABLE; 00245 /* Send the stop byte */ 00246 SCI0DRL = STOP_BYTE; 00247 /* Clear the TX in progress flag */ 00248 TXBufferInUseFlags &= COM_CLEAR_SCI0_INTERFACE_ID; 00249 } 00250 } 00251 00252 /* Record how long the operation took */ 00253 RuntimeVars.serialISRRuntime = TCNT - start; 00254 }