Satellite Observers Workbench. NOT yet complete, just published for forum posters to \"cherry pick\" pieces of code as requiered as an example.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pccomms.c Source File

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 }