Satellite Observers Workbench. NOT yet complete, just published for forum posters to \"cherry pick\" pieces of code as requiered as an example.
pccomms.c
00001 /**************************************************************************** 00002 * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd 00003 * 00004 * This file is part of the Satellite Observers Workbench (SOWB). 00005 * 00006 * SOWB is free software: you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation, either version 3 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * SOWB is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with SOWB. If not, see <http://www.gnu.org/licenses/>. 00018 * 00019 * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ 00020 * 00021 ***************************************************************************/ 00022 00023 /* 00024 Packet format <MMMMLLLLCF>......... 00025 Where:- 00026 < is the "start of packet header" character. 00027 MMMM is a hex string representation of the uint16_t mode. 00028 LLLL is a hex string representation of the uint16_t length (payload length). 00029 C is a two's complement checksum of the header from < to > inclusive. 00030 F is a char flag. Normally zero. 00031 > is the "end of packet header" character. 00032 .... is the packet payload, a series of bytes, the number defined by length LLLL 00033 00034 Note, the C checksum should be added by the sender. This is the two's complement of 00035 all the ascii chars from < to > inclusive. Once inserted by the sender, the header 00036 packet can be checked by summing all the charachers, from < to > inclusive and the 00037 result should be zero. 00038 00039 Once a complete header is received the IRQ is told how many bytes to read into the 00040 RX buffer before changing the state to PCCOMMS_PACKET_READ. After this any future 00041 characters received will be sent to dev/null until the current packet is handled. 00042 00043 The handling is done by the _process() function. Basically, once we have a packet 00044 the MMMM mode decides what to do with it. The _process() function will call the list 00045 of handler functions passing a pointer to the packet header. Each handler can 00046 accept the header and then empty the payload RX buffer. Handlers can get the payload 00047 by simply calling Uart1_getc(), which will eventually return -1 when the RX buffer 00048 is empty (which should match the LLLL length of the payload. 00049 00050 If a handler returns PCCOMMS_PACKET_ACCEPTED then we clear out the header and reset 00051 the serial system to begin listening for a new packet. Note, if a handler needs to 00052 keep a copy of any data (header or payload) it should do so before it returns 00053 PCCOMMS_PACKET_ACCEPTED because the engine here will ensure all buffers get reset 00054 before going back into reception mode. 00055 00056 If no handler accepts the packet then the packet is dropped, the serial engine is 00057 reset and basically everything is reset to begin looking for a new packet header. */ 00058 00059 #include "sowb.h" 00060 #include "debug.h" 00061 #include "pccomms.h" 00062 #include "utils.h" 00063 00064 /* Globals used for the packet reception engine. */ 00065 int pccomms_state; 00066 BASE_PACKET_A header_packet_ascii; 00067 unsigned char header_packet_in; 00068 BASE_PACKET_B header_packet; 00069 uint16_t packet_char_counter; 00070 00071 /* Payload buffers. */ 00072 volatile char uart3txBuffer[UART3_TX_BUFFER_SIZE]; 00073 volatile char uart3rxBuffer[UART3_RX_BUFFER_SIZE]; 00074 volatile unsigned char uart3txBufferIn, uart3txBufferOut; 00075 volatile unsigned char uart3rxBufferIn, uart3rxBufferOut; 00076 volatile bool uart3txBufferFull, uart3rxBufferFull, uart3rxBufferOverflow; 00077 00078 /* Used to reset the PC COMMS system. */ 00079 static void pccomms_reset(void) { 00080 pccomms_state = PCCOMMS_STATE_WAITING; 00081 header_packet_in = 0; 00082 uart3txBufferIn = uart3txBufferOut = 0; 00083 memset((char *)uart3txBuffer, 0, UART3_TX_BUFFER_SIZE); 00084 uart3rxBufferIn = uart3rxBufferOut = 0; 00085 memset((char *)uart3txBuffer, 0, UART3_RX_BUFFER_SIZE); 00086 uart3txBufferFull = uart3rxBufferFull = false; 00087 uart3rxBufferOverflow = false; 00088 } 00089 00090 /** pccomms_init 00091 */ 00092 void pccomms_init(void) { 00093 DEBUG_INIT_START; 00094 pccomms_reset(); 00095 Uart3_init(); 00096 DEBUG_INIT_END; 00097 } 00098 00099 /* We declare the packet handler functions prototypes here. */ 00100 int pccomms_mode1_handler(BASE_PACKET_B *b, BASE_PACKET_A *a); 00101 00102 /** pccomms_process 00103 */ 00104 void pccomms_process(void) { 00105 00106 /* If the IRQ system has flagged a packet reception complete handle it. */ 00107 if (pccomms_state == PCCOMMS_PACKET_READ) { 00108 switch(header_packet.mode) { 00109 case 1: 00110 pccomms_mode1_handler(&header_packet, &header_packet_ascii); 00111 break; 00112 } 00113 00114 pccomms_reset(); 00115 } 00116 } 00117 00118 /** base_packet_a2b 00119 * 00120 * Convert a header packet in ASCII format to the internal 00121 * binary form. 00122 * 00123 * @param BASE_PACKET_B *b The dst of the conversion 00124 * @param BASE_PACKET_A *a The src of the conversion 00125 */ 00126 void base_packet_a2b(BASE_PACKET_B *b, BASE_PACKET_A *a) { 00127 b->mode = (uint16_t)hex2bin(a->mode, 4); 00128 b->length = (uint16_t)hex2bin(a->length, 4); 00129 } 00130 00131 /** base_packet_b2a 00132 * 00133 * Convert an internal header packet in binary format to the external 00134 * ASCII form. 00135 * 00136 * @param BASE_PACKET_A *a The dst of the conversion 00137 * @param BASE_PACKET_B *b The src of the conversion 00138 */ 00139 void base_packet_b2a(BASE_PACKET_A *a, BASE_PACKET_B *b) { 00140 bin2hex((uint32_t)b->mode, 4, a->mode); 00141 bin2hex((uint32_t)b->length, 4, a->length); 00142 a->lead_char = '<'; 00143 a->trail_char = '>'; 00144 a->csum = '\0'; 00145 a->csum = strcsuml((char *)a, BASE_PACKET_A_LEN); 00146 } 00147 00148 /** Uart3_putc 00149 * 00150 * Put a character out the UART1 serial port. 00151 * Note, if the THR register is not empty AND the output buffer is not empty 00152 * then place the character into the output buffer and enable interrupt to 00153 * flush the buffer. 00154 * 00155 * Additionally, if the TX buffer is full this function will BLOCK! 00156 * Be aware of this blocking! 00157 * 00158 * @param char c The character to send out of UART1. 00159 */ 00160 void Uart3_putc(char c) { 00161 if ((LPC_UART3->LSR & 0x20) && (uart3txBufferIn == uart3txBufferOut && !uart3txBufferFull)) { 00162 LPC_UART3->THR = (uint8_t)c; 00163 } 00164 else { 00165 while (uart3txBufferFull) ; /* Blocks!!! */ 00166 uart3txBuffer[uart3txBufferIn++] = c; 00167 uart3txBufferIn &= (UART3_TX_BUFFER_SIZE - 1); 00168 if (uart3txBufferIn == uart3txBufferOut && !uart3txBufferFull) uart3txBufferFull = true; 00169 LPC_UART3->IER = 0x3; 00170 } 00171 } 00172 00173 /** Uart3_getc 00174 * 00175 * Used to get a character from Uart1. If the passed arg "block" is non-zero 00176 * then this function will block (wait) for user input. Otherwise if a char 00177 * is available return it, otherwise return -1 to show buffer was empty. 00178 * 00179 * @param int block Should we block? 00180 * @return int Cast char to int for char or -1 if non-blocking and no char. 00181 */ 00182 int Uart3_getc(int block) { 00183 char c; 00184 00185 if (block) while (uart3rxBufferOut == uart3rxBufferIn && !uart3rxBufferFull) ; /* Blocks! */ 00186 else if (uart3rxBufferIn == uart3rxBufferOut && !uart3rxBufferFull) return -1; 00187 00188 c = uart3rxBuffer[uart3rxBufferOut++]; 00189 uart3rxBufferOut &= (UART3_RX_BUFFER_SIZE - 1); 00190 if (uart3rxBufferFull) uart3rxBufferFull = false; 00191 return (int)c; 00192 } 00193 00194 /** UART3_IRQHandler 00195 */ 00196 extern "C" void UART3_IRQHandler(void) __irq { 00197 uint32_t iir; 00198 char c, *p; 00199 00200 iir = LPC_UART3->IIR; 00201 00202 if (iir & 1) return; 00203 00204 iir = (iir >> 1) & 0x3; 00205 00206 if (iir == 2) { 00207 c = (char)LPC_UART3->RBR; 00208 if (pccomms_state == PCCOMMS_STATE_WAITING) { 00209 p = (char *)&header_packet_ascii; 00210 if (c == '<') { 00211 header_packet_in = 0; 00212 p[header_packet_in++] = c; 00213 BASE_PACKET_WRAP; 00214 } 00215 else if (c == '>') { 00216 p[header_packet_in++] = c; 00217 BASE_PACKET_WRAP; 00218 if (strsuml(p, BASE_PACKET_A_LEN) == 0) { 00219 base_packet_a2b(&header_packet, &header_packet_ascii); 00220 packet_char_counter = header_packet.length; 00221 pccomms_state = PCCOMMS_BASE_PACKET_READ; 00222 } 00223 else { 00224 pccomms_state = PCCOMMS_BASE_PACKET_BAD_CSUM; 00225 header_packet_in = 0; 00226 } 00227 } 00228 else { 00229 p[header_packet_in++] = c; 00230 BASE_PACKET_WRAP; 00231 } 00232 } 00233 else if (pccomms_state == PCCOMMS_BASE_PACKET_READ) { 00234 if (uart3rxBufferIn == uart3rxBufferOut && uart3rxBufferFull) { 00235 uart3rxBufferOverflow = true; 00236 } 00237 else { 00238 uart3rxBuffer[uart3rxBufferIn++] = c; 00239 uart3rxBufferIn &= (UART3_RX_BUFFER_SIZE - 1); 00240 if (uart3rxBufferIn == uart3rxBufferOut) uart3rxBufferFull = true; 00241 if (packet_char_counter) packet_char_counter--; 00242 if (packet_char_counter == 0) { 00243 pccomms_state = PCCOMMS_PACKET_READ; 00244 } 00245 } 00246 00247 } 00248 else { 00249 /* Unknown state, send char to /dev/null */ 00250 } 00251 } 00252 00253 if (iir == 1) { 00254 if (uart3txBufferIn != uart3txBufferOut || uart3txBufferFull) { 00255 LPC_UART3->THR = (uint8_t)(uart3txBuffer[uart3txBufferOut++]); 00256 uart3txBufferOut &= (UART3_TX_BUFFER_SIZE - 1); 00257 uart3txBufferFull = false; 00258 } 00259 else { 00260 LPC_UART3->IER = 0x1; 00261 } 00262 } 00263 } 00264 00265 /** Uart3_init 00266 */ 00267 void Uart3_init(void) { 00268 00269 LPC_SC->PCONP |= (1UL << 25); 00270 LPC_SC->PCLKSEL1 &= ~(3UL << 18); 00271 LPC_SC->PCLKSEL1 |= (1UL << 18); 00272 LPC_PINCON->PINSEL0 &= ~((2UL << 0) | (2UL << 2)); 00273 LPC_PINCON->PINSEL0 |= ((2UL << 0) | (2UL << 2)); 00274 LPC_UART1->LCR = 0x80; 00275 LPC_UART1->DLM = 0x0; // 0x00 for 115200 baud, for 9600 use 0x2; 00276 LPC_UART1->DLL = 0x34; // 0x34 for 115200 baud, for 9600 use 0x71; 00277 LPC_UART1->LCR = 0x3; 00278 LPC_UART1->FCR = 0x7; 00279 00280 NVIC_SetVector(UART3_IRQn, (uint32_t)UART3_IRQHandler); 00281 NVIC_EnableIRQ(UART3_IRQn); 00282 00283 /* Enable UART1 RX and TX interrupt. */ 00284 LPC_UART3->IER = 0x3; 00285 }
Generated on Tue Jul 12 2022 18:05:35 by 1.7.2