FreeEMS  0.2.0-SNAPSHOT-285-g028e24c
commsISRs.c
Go to the documentation of this file.
1 /* FreeEMS - the open source engine management system
2  *
3  * Copyright 2008-2012 Fred Cooke
4  *
5  * This file is part of the FreeEMS project.
6  *
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.
11  *
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.
16  *
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/
19  *
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!
22  *
23  * Thank you for choosing FreeEMS to run your engine!
24  */
25 
26 
27 /** @file
28  *
29  * @ingroup interruptHandlers
30  * @ingroup communicationsFiles
31  *
32  * @brief Send and receive bytes serially
33  *
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.
38  *
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.
40  */
41 
42 
43 #define COMMSISRS_C
44 #include "inc/freeEMS.h"
45 #include "inc/interrupts.h"
46 #include "inc/utils.h"
47 #include "inc/commsCore.h"
48 #include "inc/commsISRs.h"
49 
50 
51 /* The C89 standard is used in the 3.3.6 GCC compiler, please *
52  * see the following URL for more info on inline functions : *
53  * http://gcc.gnu.org/onlinedocs/gcc-3.3.6/Inline.html#Inline */
54 
55 
56 /** @brief Reset Receive State
57  *
58  * Reset communications reception to the state provided.
59  *
60  * @todo TODO this is in the wrong file!! Either move the header declaration or move the function!
61  *
62  * @param sourceIDState is the state to apply to the RX buffer state variable.
63  */
64 void resetReceiveState(unsigned char sourceIDState){
65  /* Set the receive buffer pointer to the beginning */
66  RXBufferCurrentPosition = (unsigned char*)&RXBuffer;
67 
68  /* Zero the flags */
69  RXStateFlags = 0;
70 
71  /* Set the source ID state (clear all or all but one flag(s)) */
72  RXBufferContentSourceID = sourceIDState;
73 
74  /* Which ever interface we are setting is the one we came from. By definition */
75  /* it must be on and we want it to stay on, so just turn off all the others. */
76  if(sourceIDState & COM_SET_SCI0_INTERFACE_ID){
77  /* Turn off all others here */
78  /// @todo TODO CAN0CTL1 &= CANCTL1_RX_DISABLE;
79  /// @todo TODO CAN0CTL1 &= CANCTL1_RX_ISR_DISABLE;
80  /* SPI ? I2C ? SCI1 ? */
81  }else if(sourceIDState & COM_SET_CAN0_INTERFACE_ID){
82  /* Turn off all others here */
83  /* Only SCI for now */
85  /* SPI ? I2C ? SCI1 ? */
86  }else{ /* If clearing all flags then enable RX on all interfaces */
87  /* Only SCI for now */
88  unsigned char devnull; // Is there a better way to do this?
89  devnull = SCI0SR1; // Reading the flags combined with...
90  devnull = SCI0DRL; // ...reading the data clears the flags
92  /// @todo TODO CAN0CTL1 |= CANCTL1_RX_ENABLE;
93  /// @todo TODO CAN0CTL1 |= CANCTL1_RX_ISR_ENABLE;
94  /* SPI ? I2C ? SCI1 ? */
95  }
96 }
97 
98 
99 /** @brief Serial Communication Interface 0 ISR
100  *
101  * SCI0 ISR handles all interrupts for SCI0 by reading flags and acting
102  * appropriately. Its functions are to send raw bytes out over the wire from a
103  * buffer and to receive bytes from the wire un-escape them, checksum them and
104  * store them in a buffer.
105  *
106  * @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.
107  * @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?
108  */
109 void SCI0ISR(){
110  // OK before flag reading because cleared when SCI0DRL accessed (R or W)
112 
113  /* Read the flags register */
114  unsigned char flags = SCI0SR1;
115  /* Note: Combined with reading or writing the data register this also clears the flags. */
116 
117  /* If either of these flags is set, we need to read the data to clear the flag */
119  /* Grab the received byte from the register to clear the flag, whether we want the data or not */
120  unsigned char rawByte = SCI0DRL;
121 
122  /* If the RX interrupt is enabled do something useful */
125  /* If there is noise on the receive line record it */
126  if(flags & SCISR1_RX_NOISE){
129  }
130 
131  /* If a framing error occurs record it */
132  if(flags & SCISR1_RX_FRAMING){
135  }
136 
137  /* If a parity error occurs record it */
138  if(flags & SCISR1_RX_PARITY){
141  }
142 
143  /* If an overrun occurs record it */
144  if(flags & SCISR1_RX_OVERRUN){
147  }
148 
150  }else{ // Process the received data
151  /* Look for a start byte to indicate a new packet */
152  if(rawByte == START_BYTE){
153  /* If another interface is using it (Note, clear flag, not normal) */
155  /* Turn off our reception */
157  }else{
158  /* If we are using it */
160  /* Increment the counter */
163  }
164  /* Reset to us using it unless someone else was */
165  resetReceiveState(COM_SET_SCI0_INTERFACE_ID);
166  }
167  }else if((unsigned short)RXBufferCurrentPosition >= ((unsigned short)&RXBuffer + RX_BUFFER_SIZE)){
168  /* Buffer was full, record and reset */
174  /* Clear escaped byte next flag, thanks Karsten! ((~ != !) == (! ~= ~)) == LOL */
176 
177  if(rawByte == ESCAPED_ESCAPE_BYTE){
179  }else if(rawByte == ESCAPED_START_BYTE){
181  }else if(rawByte == ESCAPED_STOP_BYTE){
183  }else{
184  /* Otherwise reset and record as data is bad */
188  }
189  }else if(rawByte == ESCAPE_BYTE){
190  /* Drop the escape and set the flag to indicate that the next byte should be un-escaped. */
192  }else if(rawByte == STOP_BYTE){
193  /* Turn off reception */
196  }else{
197  *RXBufferCurrentPosition++ = rawByte;
198  }
199  } /* ELSE: Do nothing : drop the byte */
200  }
201  }
202  }
203 
204  /* If the TX interrupt is enabled check the register empty flag. */
206  /* Get the byte to be sent from the buffer */
207  unsigned char rawValue = *TXBufferCurrentPositionSCI0;
208 
210  if(TXByteEscaped == 0){
211  /* If the raw value needs to be escaped */
212  if(rawValue == ESCAPE_BYTE){
215  }else if(rawValue == START_BYTE){
218  }else if(rawValue == STOP_BYTE){
221  }else{ /* Otherwise just send it */
222  SCI0DRL = rawValue;
224  }
225  }else{
228  TXByteEscaped = 0;
229  }
230  }else{ /* Length is zero */
231  if(coreStatusA & BIT7){
232  /* Turn off transmission interrupt */
234  /* Clear the TX in progress flag */
236  coreStatusA &= NBIT7;
237  }else{
238  coreStatusA |= BIT7;
239  /* Send the stop byte */
240  SCI0DRL = STOP_BYTE;
241  }
242  }
243  }
244 
246 }