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

Dependencies:   mbed

Committer:
AjK
Date:
Mon Oct 11 10:34:55 2010 +0000
Revision:
0:0a841b89d614
Totally Alpha quality as this project isn\t completed. Just publishing it as it answers many questions asked in the forums

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AjK 0:0a841b89d614 1 /****************************************************************************
AjK 0:0a841b89d614 2 * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd
AjK 0:0a841b89d614 3 *
AjK 0:0a841b89d614 4 * This file is part of the Satellite Observers Workbench (SOWB).
AjK 0:0a841b89d614 5 *
AjK 0:0a841b89d614 6 * SOWB is free software: you can redistribute it and/or modify
AjK 0:0a841b89d614 7 * it under the terms of the GNU General Public License as published by
AjK 0:0a841b89d614 8 * the Free Software Foundation, either version 3 of the License, or
AjK 0:0a841b89d614 9 * (at your option) any later version.
AjK 0:0a841b89d614 10 *
AjK 0:0a841b89d614 11 * SOWB is distributed in the hope that it will be useful,
AjK 0:0a841b89d614 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
AjK 0:0a841b89d614 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
AjK 0:0a841b89d614 14 * GNU General Public License for more details.
AjK 0:0a841b89d614 15 *
AjK 0:0a841b89d614 16 * You should have received a copy of the GNU General Public License
AjK 0:0a841b89d614 17 * along with SOWB. If not, see <http://www.gnu.org/licenses/>.
AjK 0:0a841b89d614 18 *
AjK 0:0a841b89d614 19 * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $
AjK 0:0a841b89d614 20 *
AjK 0:0a841b89d614 21 ***************************************************************************/
AjK 0:0a841b89d614 22
AjK 0:0a841b89d614 23 /*
AjK 0:0a841b89d614 24 Packet format <MMMMLLLLCF>.........
AjK 0:0a841b89d614 25 Where:-
AjK 0:0a841b89d614 26 < is the "start of packet header" character.
AjK 0:0a841b89d614 27 MMMM is a hex string representation of the uint16_t mode.
AjK 0:0a841b89d614 28 LLLL is a hex string representation of the uint16_t length (payload length).
AjK 0:0a841b89d614 29 C is a two's complement checksum of the header from < to > inclusive.
AjK 0:0a841b89d614 30 F is a char flag. Normally zero.
AjK 0:0a841b89d614 31 > is the "end of packet header" character.
AjK 0:0a841b89d614 32 .... is the packet payload, a series of bytes, the number defined by length LLLL
AjK 0:0a841b89d614 33
AjK 0:0a841b89d614 34 Note, the C checksum should be added by the sender. This is the two's complement of
AjK 0:0a841b89d614 35 all the ascii chars from < to > inclusive. Once inserted by the sender, the header
AjK 0:0a841b89d614 36 packet can be checked by summing all the charachers, from < to > inclusive and the
AjK 0:0a841b89d614 37 result should be zero.
AjK 0:0a841b89d614 38
AjK 0:0a841b89d614 39 Once a complete header is received the IRQ is told how many bytes to read into the
AjK 0:0a841b89d614 40 RX buffer before changing the state to PCCOMMS_PACKET_READ. After this any future
AjK 0:0a841b89d614 41 characters received will be sent to dev/null until the current packet is handled.
AjK 0:0a841b89d614 42
AjK 0:0a841b89d614 43 The handling is done by the _process() function. Basically, once we have a packet
AjK 0:0a841b89d614 44 the MMMM mode decides what to do with it. The _process() function will call the list
AjK 0:0a841b89d614 45 of handler functions passing a pointer to the packet header. Each handler can
AjK 0:0a841b89d614 46 accept the header and then empty the payload RX buffer. Handlers can get the payload
AjK 0:0a841b89d614 47 by simply calling Uart1_getc(), which will eventually return -1 when the RX buffer
AjK 0:0a841b89d614 48 is empty (which should match the LLLL length of the payload.
AjK 0:0a841b89d614 49
AjK 0:0a841b89d614 50 If a handler returns PCCOMMS_PACKET_ACCEPTED then we clear out the header and reset
AjK 0:0a841b89d614 51 the serial system to begin listening for a new packet. Note, if a handler needs to
AjK 0:0a841b89d614 52 keep a copy of any data (header or payload) it should do so before it returns
AjK 0:0a841b89d614 53 PCCOMMS_PACKET_ACCEPTED because the engine here will ensure all buffers get reset
AjK 0:0a841b89d614 54 before going back into reception mode.
AjK 0:0a841b89d614 55
AjK 0:0a841b89d614 56 If no handler accepts the packet then the packet is dropped, the serial engine is
AjK 0:0a841b89d614 57 reset and basically everything is reset to begin looking for a new packet header. */
AjK 0:0a841b89d614 58
AjK 0:0a841b89d614 59 #include "sowb.h"
AjK 0:0a841b89d614 60 #include "debug.h"
AjK 0:0a841b89d614 61 #include "pccomms.h"
AjK 0:0a841b89d614 62 #include "utils.h"
AjK 0:0a841b89d614 63
AjK 0:0a841b89d614 64 /* Globals used for the packet reception engine. */
AjK 0:0a841b89d614 65 int pccomms_state;
AjK 0:0a841b89d614 66 BASE_PACKET_A header_packet_ascii;
AjK 0:0a841b89d614 67 unsigned char header_packet_in;
AjK 0:0a841b89d614 68 BASE_PACKET_B header_packet;
AjK 0:0a841b89d614 69 uint16_t packet_char_counter;
AjK 0:0a841b89d614 70
AjK 0:0a841b89d614 71 /* Payload buffers. */
AjK 0:0a841b89d614 72 volatile char uart3txBuffer[UART3_TX_BUFFER_SIZE];
AjK 0:0a841b89d614 73 volatile char uart3rxBuffer[UART3_RX_BUFFER_SIZE];
AjK 0:0a841b89d614 74 volatile unsigned char uart3txBufferIn, uart3txBufferOut;
AjK 0:0a841b89d614 75 volatile unsigned char uart3rxBufferIn, uart3rxBufferOut;
AjK 0:0a841b89d614 76 volatile bool uart3txBufferFull, uart3rxBufferFull, uart3rxBufferOverflow;
AjK 0:0a841b89d614 77
AjK 0:0a841b89d614 78 /* Used to reset the PC COMMS system. */
AjK 0:0a841b89d614 79 static void pccomms_reset(void) {
AjK 0:0a841b89d614 80 pccomms_state = PCCOMMS_STATE_WAITING;
AjK 0:0a841b89d614 81 header_packet_in = 0;
AjK 0:0a841b89d614 82 uart3txBufferIn = uart3txBufferOut = 0;
AjK 0:0a841b89d614 83 memset((char *)uart3txBuffer, 0, UART3_TX_BUFFER_SIZE);
AjK 0:0a841b89d614 84 uart3rxBufferIn = uart3rxBufferOut = 0;
AjK 0:0a841b89d614 85 memset((char *)uart3txBuffer, 0, UART3_RX_BUFFER_SIZE);
AjK 0:0a841b89d614 86 uart3txBufferFull = uart3rxBufferFull = false;
AjK 0:0a841b89d614 87 uart3rxBufferOverflow = false;
AjK 0:0a841b89d614 88 }
AjK 0:0a841b89d614 89
AjK 0:0a841b89d614 90 /** pccomms_init
AjK 0:0a841b89d614 91 */
AjK 0:0a841b89d614 92 void pccomms_init(void) {
AjK 0:0a841b89d614 93 DEBUG_INIT_START;
AjK 0:0a841b89d614 94 pccomms_reset();
AjK 0:0a841b89d614 95 Uart3_init();
AjK 0:0a841b89d614 96 DEBUG_INIT_END;
AjK 0:0a841b89d614 97 }
AjK 0:0a841b89d614 98
AjK 0:0a841b89d614 99 /* We declare the packet handler functions prototypes here. */
AjK 0:0a841b89d614 100 int pccomms_mode1_handler(BASE_PACKET_B *b, BASE_PACKET_A *a);
AjK 0:0a841b89d614 101
AjK 0:0a841b89d614 102 /** pccomms_process
AjK 0:0a841b89d614 103 */
AjK 0:0a841b89d614 104 void pccomms_process(void) {
AjK 0:0a841b89d614 105
AjK 0:0a841b89d614 106 /* If the IRQ system has flagged a packet reception complete handle it. */
AjK 0:0a841b89d614 107 if (pccomms_state == PCCOMMS_PACKET_READ) {
AjK 0:0a841b89d614 108 switch(header_packet.mode) {
AjK 0:0a841b89d614 109 case 1:
AjK 0:0a841b89d614 110 pccomms_mode1_handler(&header_packet, &header_packet_ascii);
AjK 0:0a841b89d614 111 break;
AjK 0:0a841b89d614 112 }
AjK 0:0a841b89d614 113
AjK 0:0a841b89d614 114 pccomms_reset();
AjK 0:0a841b89d614 115 }
AjK 0:0a841b89d614 116 }
AjK 0:0a841b89d614 117
AjK 0:0a841b89d614 118 /** base_packet_a2b
AjK 0:0a841b89d614 119 *
AjK 0:0a841b89d614 120 * Convert a header packet in ASCII format to the internal
AjK 0:0a841b89d614 121 * binary form.
AjK 0:0a841b89d614 122 *
AjK 0:0a841b89d614 123 * @param BASE_PACKET_B *b The dst of the conversion
AjK 0:0a841b89d614 124 * @param BASE_PACKET_A *a The src of the conversion
AjK 0:0a841b89d614 125 */
AjK 0:0a841b89d614 126 void base_packet_a2b(BASE_PACKET_B *b, BASE_PACKET_A *a) {
AjK 0:0a841b89d614 127 b->mode = (uint16_t)hex2bin(a->mode, 4);
AjK 0:0a841b89d614 128 b->length = (uint16_t)hex2bin(a->length, 4);
AjK 0:0a841b89d614 129 }
AjK 0:0a841b89d614 130
AjK 0:0a841b89d614 131 /** base_packet_b2a
AjK 0:0a841b89d614 132 *
AjK 0:0a841b89d614 133 * Convert an internal header packet in binary format to the external
AjK 0:0a841b89d614 134 * ASCII form.
AjK 0:0a841b89d614 135 *
AjK 0:0a841b89d614 136 * @param BASE_PACKET_A *a The dst of the conversion
AjK 0:0a841b89d614 137 * @param BASE_PACKET_B *b The src of the conversion
AjK 0:0a841b89d614 138 */
AjK 0:0a841b89d614 139 void base_packet_b2a(BASE_PACKET_A *a, BASE_PACKET_B *b) {
AjK 0:0a841b89d614 140 bin2hex((uint32_t)b->mode, 4, a->mode);
AjK 0:0a841b89d614 141 bin2hex((uint32_t)b->length, 4, a->length);
AjK 0:0a841b89d614 142 a->lead_char = '<';
AjK 0:0a841b89d614 143 a->trail_char = '>';
AjK 0:0a841b89d614 144 a->csum = '\0';
AjK 0:0a841b89d614 145 a->csum = strcsuml((char *)a, BASE_PACKET_A_LEN);
AjK 0:0a841b89d614 146 }
AjK 0:0a841b89d614 147
AjK 0:0a841b89d614 148 /** Uart3_putc
AjK 0:0a841b89d614 149 *
AjK 0:0a841b89d614 150 * Put a character out the UART1 serial port.
AjK 0:0a841b89d614 151 * Note, if the THR register is not empty AND the output buffer is not empty
AjK 0:0a841b89d614 152 * then place the character into the output buffer and enable interrupt to
AjK 0:0a841b89d614 153 * flush the buffer.
AjK 0:0a841b89d614 154 *
AjK 0:0a841b89d614 155 * Additionally, if the TX buffer is full this function will BLOCK!
AjK 0:0a841b89d614 156 * Be aware of this blocking!
AjK 0:0a841b89d614 157 *
AjK 0:0a841b89d614 158 * @param char c The character to send out of UART1.
AjK 0:0a841b89d614 159 */
AjK 0:0a841b89d614 160 void Uart3_putc(char c) {
AjK 0:0a841b89d614 161 if ((LPC_UART3->LSR & 0x20) && (uart3txBufferIn == uart3txBufferOut && !uart3txBufferFull)) {
AjK 0:0a841b89d614 162 LPC_UART3->THR = (uint8_t)c;
AjK 0:0a841b89d614 163 }
AjK 0:0a841b89d614 164 else {
AjK 0:0a841b89d614 165 while (uart3txBufferFull) ; /* Blocks!!! */
AjK 0:0a841b89d614 166 uart3txBuffer[uart3txBufferIn++] = c;
AjK 0:0a841b89d614 167 uart3txBufferIn &= (UART3_TX_BUFFER_SIZE - 1);
AjK 0:0a841b89d614 168 if (uart3txBufferIn == uart3txBufferOut && !uart3txBufferFull) uart3txBufferFull = true;
AjK 0:0a841b89d614 169 LPC_UART3->IER = 0x3;
AjK 0:0a841b89d614 170 }
AjK 0:0a841b89d614 171 }
AjK 0:0a841b89d614 172
AjK 0:0a841b89d614 173 /** Uart3_getc
AjK 0:0a841b89d614 174 *
AjK 0:0a841b89d614 175 * Used to get a character from Uart1. If the passed arg "block" is non-zero
AjK 0:0a841b89d614 176 * then this function will block (wait) for user input. Otherwise if a char
AjK 0:0a841b89d614 177 * is available return it, otherwise return -1 to show buffer was empty.
AjK 0:0a841b89d614 178 *
AjK 0:0a841b89d614 179 * @param int block Should we block?
AjK 0:0a841b89d614 180 * @return int Cast char to int for char or -1 if non-blocking and no char.
AjK 0:0a841b89d614 181 */
AjK 0:0a841b89d614 182 int Uart3_getc(int block) {
AjK 0:0a841b89d614 183 char c;
AjK 0:0a841b89d614 184
AjK 0:0a841b89d614 185 if (block) while (uart3rxBufferOut == uart3rxBufferIn && !uart3rxBufferFull) ; /* Blocks! */
AjK 0:0a841b89d614 186 else if (uart3rxBufferIn == uart3rxBufferOut && !uart3rxBufferFull) return -1;
AjK 0:0a841b89d614 187
AjK 0:0a841b89d614 188 c = uart3rxBuffer[uart3rxBufferOut++];
AjK 0:0a841b89d614 189 uart3rxBufferOut &= (UART3_RX_BUFFER_SIZE - 1);
AjK 0:0a841b89d614 190 if (uart3rxBufferFull) uart3rxBufferFull = false;
AjK 0:0a841b89d614 191 return (int)c;
AjK 0:0a841b89d614 192 }
AjK 0:0a841b89d614 193
AjK 0:0a841b89d614 194 /** UART3_IRQHandler
AjK 0:0a841b89d614 195 */
AjK 0:0a841b89d614 196 extern "C" void UART3_IRQHandler(void) __irq {
AjK 0:0a841b89d614 197 uint32_t iir;
AjK 0:0a841b89d614 198 char c, *p;
AjK 0:0a841b89d614 199
AjK 0:0a841b89d614 200 iir = LPC_UART3->IIR;
AjK 0:0a841b89d614 201
AjK 0:0a841b89d614 202 if (iir & 1) return;
AjK 0:0a841b89d614 203
AjK 0:0a841b89d614 204 iir = (iir >> 1) & 0x3;
AjK 0:0a841b89d614 205
AjK 0:0a841b89d614 206 if (iir == 2) {
AjK 0:0a841b89d614 207 c = (char)LPC_UART3->RBR;
AjK 0:0a841b89d614 208 if (pccomms_state == PCCOMMS_STATE_WAITING) {
AjK 0:0a841b89d614 209 p = (char *)&header_packet_ascii;
AjK 0:0a841b89d614 210 if (c == '<') {
AjK 0:0a841b89d614 211 header_packet_in = 0;
AjK 0:0a841b89d614 212 p[header_packet_in++] = c;
AjK 0:0a841b89d614 213 BASE_PACKET_WRAP;
AjK 0:0a841b89d614 214 }
AjK 0:0a841b89d614 215 else if (c == '>') {
AjK 0:0a841b89d614 216 p[header_packet_in++] = c;
AjK 0:0a841b89d614 217 BASE_PACKET_WRAP;
AjK 0:0a841b89d614 218 if (strsuml(p, BASE_PACKET_A_LEN) == 0) {
AjK 0:0a841b89d614 219 base_packet_a2b(&header_packet, &header_packet_ascii);
AjK 0:0a841b89d614 220 packet_char_counter = header_packet.length;
AjK 0:0a841b89d614 221 pccomms_state = PCCOMMS_BASE_PACKET_READ;
AjK 0:0a841b89d614 222 }
AjK 0:0a841b89d614 223 else {
AjK 0:0a841b89d614 224 pccomms_state = PCCOMMS_BASE_PACKET_BAD_CSUM;
AjK 0:0a841b89d614 225 header_packet_in = 0;
AjK 0:0a841b89d614 226 }
AjK 0:0a841b89d614 227 }
AjK 0:0a841b89d614 228 else {
AjK 0:0a841b89d614 229 p[header_packet_in++] = c;
AjK 0:0a841b89d614 230 BASE_PACKET_WRAP;
AjK 0:0a841b89d614 231 }
AjK 0:0a841b89d614 232 }
AjK 0:0a841b89d614 233 else if (pccomms_state == PCCOMMS_BASE_PACKET_READ) {
AjK 0:0a841b89d614 234 if (uart3rxBufferIn == uart3rxBufferOut && uart3rxBufferFull) {
AjK 0:0a841b89d614 235 uart3rxBufferOverflow = true;
AjK 0:0a841b89d614 236 }
AjK 0:0a841b89d614 237 else {
AjK 0:0a841b89d614 238 uart3rxBuffer[uart3rxBufferIn++] = c;
AjK 0:0a841b89d614 239 uart3rxBufferIn &= (UART3_RX_BUFFER_SIZE - 1);
AjK 0:0a841b89d614 240 if (uart3rxBufferIn == uart3rxBufferOut) uart3rxBufferFull = true;
AjK 0:0a841b89d614 241 if (packet_char_counter) packet_char_counter--;
AjK 0:0a841b89d614 242 if (packet_char_counter == 0) {
AjK 0:0a841b89d614 243 pccomms_state = PCCOMMS_PACKET_READ;
AjK 0:0a841b89d614 244 }
AjK 0:0a841b89d614 245 }
AjK 0:0a841b89d614 246
AjK 0:0a841b89d614 247 }
AjK 0:0a841b89d614 248 else {
AjK 0:0a841b89d614 249 /* Unknown state, send char to /dev/null */
AjK 0:0a841b89d614 250 }
AjK 0:0a841b89d614 251 }
AjK 0:0a841b89d614 252
AjK 0:0a841b89d614 253 if (iir == 1) {
AjK 0:0a841b89d614 254 if (uart3txBufferIn != uart3txBufferOut || uart3txBufferFull) {
AjK 0:0a841b89d614 255 LPC_UART3->THR = (uint8_t)(uart3txBuffer[uart3txBufferOut++]);
AjK 0:0a841b89d614 256 uart3txBufferOut &= (UART3_TX_BUFFER_SIZE - 1);
AjK 0:0a841b89d614 257 uart3txBufferFull = false;
AjK 0:0a841b89d614 258 }
AjK 0:0a841b89d614 259 else {
AjK 0:0a841b89d614 260 LPC_UART3->IER = 0x1;
AjK 0:0a841b89d614 261 }
AjK 0:0a841b89d614 262 }
AjK 0:0a841b89d614 263 }
AjK 0:0a841b89d614 264
AjK 0:0a841b89d614 265 /** Uart3_init
AjK 0:0a841b89d614 266 */
AjK 0:0a841b89d614 267 void Uart3_init(void) {
AjK 0:0a841b89d614 268
AjK 0:0a841b89d614 269 LPC_SC->PCONP |= (1UL << 25);
AjK 0:0a841b89d614 270 LPC_SC->PCLKSEL1 &= ~(3UL << 18);
AjK 0:0a841b89d614 271 LPC_SC->PCLKSEL1 |= (1UL << 18);
AjK 0:0a841b89d614 272 LPC_PINCON->PINSEL0 &= ~((2UL << 0) | (2UL << 2));
AjK 0:0a841b89d614 273 LPC_PINCON->PINSEL0 |= ((2UL << 0) | (2UL << 2));
AjK 0:0a841b89d614 274 LPC_UART1->LCR = 0x80;
AjK 0:0a841b89d614 275 LPC_UART1->DLM = 0x0; // 0x00 for 115200 baud, for 9600 use 0x2;
AjK 0:0a841b89d614 276 LPC_UART1->DLL = 0x34; // 0x34 for 115200 baud, for 9600 use 0x71;
AjK 0:0a841b89d614 277 LPC_UART1->LCR = 0x3;
AjK 0:0a841b89d614 278 LPC_UART1->FCR = 0x7;
AjK 0:0a841b89d614 279
AjK 0:0a841b89d614 280 NVIC_SetVector(UART3_IRQn, (uint32_t)UART3_IRQHandler);
AjK 0:0a841b89d614 281 NVIC_EnableIRQ(UART3_IRQn);
AjK 0:0a841b89d614 282
AjK 0:0a841b89d614 283 /* Enable UART1 RX and TX interrupt. */
AjK 0:0a841b89d614 284 LPC_UART3->IER = 0x3;
AjK 0:0a841b89d614 285 }