Ditch a bunch of superfluous lines that were always unused and made hex interpretatio...
[freeems-vanilla.git] / src / commsISRs.c
blob4528f4377022ba69f816edd7148b88f6aac70be1
1 /* FreeEMS - the open source engine management system
3 * Copyright 2008-2011 Fred Cooke
5 * This file is part of the FreeEMS project.
7 * FreeEMS software is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * FreeEMS software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with any FreeEMS software. If not, see http://www.gnu.org/licenses/
20 * We ask that if you make any changes to this file you email them upstream to
21 * us at admin(at)diyefi(dot)org or, even better, fork the code on github.com!
23 * Thank you for choosing FreeEMS to run your engine!
27 /** @file
29 * @ingroup interruptHandlers
30 * @ingroup communicationsFiles
32 * @brief Send and receive bytes serially
34 * This file contains the code for both send and receive of serial bytes
35 * through the UART SCI0 device. It is purely interrupt driven and controlled
36 * by a set of register and non-register flags that are toggled both inside
37 * and outside this file. Some additional helper functions are also kept here.
39 * @todo TODO SCI0ISR() needs to be split into some hash defines and an include file that formats it to be the ISR for a specific channel.
41 * @author Fred Cooke
45 #define COMMSISRS_C
46 #include "inc/freeEMS.h"
47 #include "inc/interrupts.h"
48 #include "inc/utils.h"
49 #include "inc/commsCore.h"
50 #include "inc/commsISRs.h"
53 /* The C89 standard is used in the 3.3.6 GCC compiler, please *
54 * see the following URL for more info on inline functions : *
55 * http://gcc.gnu.org/onlinedocs/gcc-3.3.6/Inline.html#Inline */
58 /** @brief Reset Receive State
60 * Reset communications reception to the state provided.
62 * @author Fred Cooke
64 * @todo TODO this is in the wrong file!! Either move the header declaration or move the function!
66 * @param sourceIDState is the state to apply to the RX buffer state variable.
68 void resetReceiveState(unsigned char sourceIDState){
69 /* Set the receive buffer pointer to the beginning */
70 RXBufferCurrentPosition = (unsigned char*)&RXBuffer;
72 /* Zero the flags */
73 RXStateFlags = 0;
75 /* Set the source ID state (clear all or all but one flag(s)) */
76 RXBufferContentSourceID = sourceIDState;
78 /* Which ever interface we are setting is the one we came from. By definition */
79 /* it must be on and we want it to stay on, so just turn off all the others. */
80 if(sourceIDState & COM_SET_SCI0_INTERFACE_ID){
81 /* Turn off all others here */
82 /// @todo TODO CAN0CTL1 &= CANCTL1_RX_DISABLE;
83 /// @todo TODO CAN0CTL1 &= CANCTL1_RX_ISR_DISABLE;
84 /* SPI ? I2C ? SCI1 ? */
85 }else if(sourceIDState & COM_SET_CAN0_INTERFACE_ID){
86 /* Turn off all others here */
87 /* Only SCI for now */
88 SCI0CR2 &= SCICR2_RX_ISR_DISABLE;
89 /* SPI ? I2C ? SCI1 ? */
90 }else{ /* If clearing all flags then enable RX on all interfaces */
91 /* Only SCI for now */
92 unsigned char devnull; // Is there a better way to do this?
93 devnull = SCI0SR1; // Reading the flags combined with...
94 devnull = SCI0DRL; // ...reading the data clears the flags
95 SCI0CR2 |= SCICR2_RX_ISR_ENABLE;
96 /// @todo TODO CAN0CTL1 |= CANCTL1_RX_ENABLE;
97 /// @todo TODO CAN0CTL1 |= CANCTL1_RX_ISR_ENABLE;
98 /* SPI ? I2C ? SCI1 ? */
103 /** @brief Serial Communication Interface 0 ISR
105 * SCI0 ISR handles all interrupts for SCI0 by reading flags and acting
106 * appropriately. Its functions are to send raw bytes out over the wire from a
107 * buffer and to receive bytes from the wire un-escape them, checksum them and
108 * store them in a buffer.
110 * @author Fred Cooke
112 * @todo 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.
113 * @todo TODO Fix the init code such that this doesn't run at boot without a serail device attached. Clear buffer maybe? or flag clearing/isr enabling ordering?
115 void SCI0ISR(){
116 // OK before flag reading because cleared when SCI0DRL accessed (R or W)
117 DEBUG_TURN_PIN_ON(DECODER_BENCHMARKS, BIT4, PORTB);
119 /* Read the flags register */
120 unsigned char flags = SCI0SR1;
121 /* Note: Combined with reading or writing the data register this also clears the flags. */
123 /* If either of these flags is set, we need to read the data to clear the flag */
124 if(flags & (SCISR1_RX_REGISTER_FULL | SCISR1_RX_OVERRUN)){
125 /* Grab the received byte from the register to clear the flag, whether we want the data or not */
126 unsigned char rawByte = SCI0DRL;
128 /* If the RX interrupt is enabled do something useful */
129 if(SCI0CR2 & SCICR2_RX_ISR_ENABLE){
130 if(flags & (SCISR1_RX_NOISE | SCISR1_RX_FRAMING | SCISR1_RX_PARITY | SCISR1_RX_OVERRUN)){
131 /* If there is noise on the receive line record it */
132 if(flags & SCISR1_RX_NOISE){
133 FLAG_AND_INC_FLAGGABLE(FLAG_SERIAL_NOISE_ERRORS_OFFSET);
134 KeyUserDebugs.serialHardwareErrors++;
137 /* If a framing error occurs record it */
138 if(flags & SCISR1_RX_FRAMING){
139 FLAG_AND_INC_FLAGGABLE(FLAG_SERIAL_FRAMING_ERRORS_OFFSET);
140 KeyUserDebugs.serialHardwareErrors++;
143 /* If a parity error occurs record it */
144 if(flags & SCISR1_RX_PARITY){
145 FLAG_AND_INC_FLAGGABLE(FLAG_SERIAL_PARITY_ERRORS_OFFSET);
146 KeyUserDebugs.serialHardwareErrors++;
149 /* If an overrun occurs record it */
150 if(flags & SCISR1_RX_OVERRUN){
151 FLAG_AND_INC_FLAGGABLE(FLAG_SERIAL_OVERRUN_ERRORS_OFFSET);
152 KeyUserDebugs.serialOverrunErrors++;
155 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
156 }else{ // Process the received data
157 /* Look for a start byte to indicate a new packet */
158 if(rawByte == START_BYTE){
159 /* If another interface is using it (Note, clear flag, not normal) */
160 if(RXBufferContentSourceID & COM_CLEAR_SCI0_INTERFACE_ID){
161 /* Turn off our reception */
162 SCI0CR2 &= SCICR2_RX_ISR_DISABLE;
163 }else{
164 /* If we are using it */
165 if(RXBufferContentSourceID & COM_SET_SCI0_INTERFACE_ID){
166 /* Increment the counter */
167 FLAG_AND_INC_FLAGGABLE(FLAG_SERIAL_STARTS_INSIDE_A_PACKET_OFFSET);
168 KeyUserDebugs.serialAndCommsCodeErrors++;
170 /* Reset to us using it unless someone else was */
171 resetReceiveState(COM_SET_SCI0_INTERFACE_ID);
173 }else if((unsigned short)RXBufferCurrentPosition >= ((unsigned short)&RXBuffer + RX_BUFFER_SIZE)){
174 /* Buffer was full, record and reset */
175 FLAG_AND_INC_FLAGGABLE(FLAG_SERIAL_PACKETS_OVER_LENGTH_OFFSET);
176 KeyUserDebugs.serialAndCommsCodeErrors++;
177 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
178 }else if(RXBufferContentSourceID & COM_SET_SCI0_INTERFACE_ID){
179 if(RXStateFlags & RX_SCI_ESCAPED_NEXT){
180 /* Clear escaped byte next flag, thanks Karsten! ((~ != !) == (! ~= ~)) == LOL */
181 RXStateFlags &= RX_SCI_NOT_ESCAPED_NEXT;
183 if(rawByte == ESCAPED_ESCAPE_BYTE){
184 *RXBufferCurrentPosition++ = ESCAPE_BYTE;
185 }else if(rawByte == ESCAPED_START_BYTE){
186 *RXBufferCurrentPosition++ = START_BYTE;
187 }else if(rawByte == ESCAPED_STOP_BYTE){
188 *RXBufferCurrentPosition++ = STOP_BYTE;
189 }else{
190 /* Otherwise reset and record as data is bad */
191 resetReceiveState(CLEAR_ALL_SOURCE_ID_FLAGS);
192 FLAG_AND_INC_FLAGGABLE(FLAG_SERIAL_ESCAPE_PAIR_MISMATCHES_OFFSET);
193 KeyUserDebugs.serialAndCommsCodeErrors++;
195 }else if(rawByte == ESCAPE_BYTE){
196 /* Drop the escape and set the flag to indicate that the next byte should be un-escaped. */
197 RXStateFlags |= RX_SCI_ESCAPED_NEXT;
198 }else if(rawByte == STOP_BYTE){
199 /* Turn off reception */
200 SCI0CR2 &= SCICR2_RX_ISR_DISABLE;
201 RXStateFlags |= RX_READY_TO_PROCESS;
202 }else{
203 *RXBufferCurrentPosition++ = rawByte;
205 } /* ELSE: Do nothing : drop the byte */
210 /* If the TX interrupt is enabled check the register empty flag. */
211 if((SCI0CR2 & SCICR2_TX_ISR_ENABLE) && (flags & SCISR1_TX_REGISTER_EMPTY)){
212 /* Get the byte to be sent from the buffer */
213 unsigned char rawValue = *TXBufferCurrentPositionSCI0;
215 if(TXBufferCurrentPositionSCI0 <= TXBufferCurrentPositionHandler){
216 if(TXByteEscaped == 0){
217 /* If the raw value needs to be escaped */
218 if(rawValue == ESCAPE_BYTE){
219 SCI0DRL = ESCAPE_BYTE;
220 TXByteEscaped = ESCAPED_ESCAPE_BYTE;
221 }else if(rawValue == START_BYTE){
222 SCI0DRL = ESCAPE_BYTE;
223 TXByteEscaped = ESCAPED_START_BYTE;
224 }else if(rawValue == STOP_BYTE){
225 SCI0DRL = ESCAPE_BYTE;
226 TXByteEscaped = ESCAPED_STOP_BYTE;
227 }else{ /* Otherwise just send it */
228 SCI0DRL = rawValue;
229 TXBufferCurrentPositionSCI0++;
231 }else{
232 SCI0DRL = TXByteEscaped;
233 TXBufferCurrentPositionSCI0++;
234 TXByteEscaped = 0;
236 }else{ /* Length is zero */
237 if(coreStatusA & BIT7){
238 /* Turn off transmission interrupt */
239 SCI0CR2 &= (SCICR2_TX_ISR_DISABLE & SCICR2_TX_DISABLE);
240 /* Clear the TX in progress flag */
241 TXBufferInUseFlags &= COM_CLEAR_SCI0_INTERFACE_ID;
242 coreStatusA &= NBIT7;
243 }else{
244 coreStatusA |= BIT7;
245 /* Send the stop byte */
246 SCI0DRL = STOP_BYTE;
251 DEBUG_TURN_PIN_OFF(DECODER_BENCHMARKS, NBIT4, PORTB);