Index: webserver/example/EnergyMeters/Source/EnergyMeters/SolarCountUART.c =================================================================== --- webserver/example/EnergyMeters/Source/EnergyMeters/SolarCountUART.c (revision 34) +++ webserver/example/EnergyMeters/Source/EnergyMeters/SolarCountUART.c (revision 34) @@ -0,0 +1,528 @@ + + +#include "LPC23xx.h" + +// Pin I/O LED Control Maskbit +#define DIR_RS485 0x00080000 // P1.19(0000 0000 0000 x000 0000 0000 0000 0000) +#define RXD_RS485() IOCLR1 = DIR_RS485 // RS485 Direction = 0 (Receive) +#define TXD_RS485() IOSET1 = DIR_RS485 // RS485 Direction = 1 (Transmit) + +#define RX_UART3_BUF_SIZE 100 +#if RX_UART3_BUF_SIZE > 254 +# error "RX_UART3_BUF_SIZE too large!" +#endif + + +#define SOL_NO_INIT 0 /* no init yet */ +#define SOL_SENT_INIT 1 /* sent init string */ +#define SOL_CHAN 2 /* querying channel currentChannel */ +#define SOL_CHAN_WAIT_REPLY 3 /* waiting for reply on channel currentChannel = 0; */ +#define SOL_FINISHED 10 /* finished */ +//#define SOL_ +//#define SOL_ + + +unsigned int rxBuf3NextFreeRxPos = 0; + +unsigned char currentChannel; /* the SolarCount channel we currently query (here: 0 to 3) */ + +static int solarState = SOL_NO_INIT; /* state of the SolarCount communication state machine */ + + +unsigned char rxUART3[RX_UART3_BUF_SIZE]; +int uart3_buf[50]; + + +//char init1[] = "abcdef"; +const unsigned char init1[] = "\x02\xB0\xF0\x04\x00\x21\x00\xCC\x35\x03"; // 1. init seq to SolarCount +const unsigned char init1_rsp[] = "\x02\xf0\xb0\x08\x00\x84\x09\x0c\x04\x0a\x26\x86\xcd\x00\x03"; /* exp. init seq response */ +const unsigned char init1_r_m[] = "\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff"; /* exp. init seq response mask */ + + +const unsigned char reqchan0[] = "\x02\xB0\xF0\x04\x00\x20\x00\xFD\x06\x03"; // request channel 0 +const unsigned char reqchan1[] = "\x02\xB0\xF0\x04\x00\x20\x01\xDC\x16\x03"; // request channel 1 +const unsigned char reqchan2[] = "\x02\xB0\xF0\x04\x00\x20\x02\xBF\x26\x03"; // request channel 2 +const unsigned char reqchan3[] = "\x02\xB0\xF0\x04\x00\x20\x03\x9E\x36\x03"; // request channel 3 +const unsigned char reqchan4[] = "\x02\xB0\xF0\x04\x00\x20\x04\x79\x46\x03"; // request channel 4 +const unsigned char reqchan5[] = "\x02\xB0\xF0\x04\x00\x20\x05\x58\x56\x03"; // request channel 5 +const unsigned char init3[] = "\x02\xF0\xB0\x0A\x00"; // 3. init seq. to SolarCount + + +const unsigned char init_after_all_chan[] = "\x02\xb0\xf0\x04\x00\x21\x00\xcc\x35\x03"; // send to SC after all channels have been scanned + +const unsigned char init_after_all_chan_rsp[] = "\x02\xf0\xb0\x09\x00\xa1\xfd\x03\x00\x00\x00\x00\x07\x21\x03"; // response from SC to init_after_all_chan[] +const unsigned char init_after_all_chan_r_m[] = "\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff"; // mask for init_after_all_chan_rsp + +const unsigned char reqchan0_rsp[] = "\x02\xf0\xb0\x0a\x00\xa0\x00\x87\x00\x00\x00\xec\x00\xf2\x3f\x03"; // response to request channel 0 +const unsigned char reqchan0_r_m[] = "\xff\xff\xff\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff"; // response to request channel 0: mask +const unsigned char reqchan1_rsp[] = "\x02\xf0\xb0\x0a\x00\xa0\x01\x87\x00\x00\x00\xec\x00\xf2\x3f\x03"; // response to request channel 1 +const unsigned char reqchan1_r_m[] = "\xff\xff\xff\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff"; // response to request channel 1: mask +const unsigned char reqchan2_rsp[] = "\x02\xf0\xb0\x0a\x00\xa0\x02\x87\x00\x00\x00\xec\x00\xf2\x3f\x03"; // response to request channel 2 +const unsigned char reqchan2_r_m[] = "\xff\xff\xff\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff"; // response to request channel 2: mask +const unsigned char reqchan3_rsp[] = "\x02\xf0\xb0\x0a\x00\xa0\x03\x87\x00\x00\x00\xec\x00\xf2\x3f\x03"; // response to request channel 3 +const unsigned char reqchan3_r_m[] = "\xff\xff\xff\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff"; // response to request channel 3: mask +const unsigned char reqchan4_rsp[] = "\x02\xf0\xb0\x0a\x00\xa0\x04\x87\x00\x00\x00\xec\x00\xf2\x3f\x03"; // response to request channel 4: +const unsigned char reqchan4_r_m[] = "\xff\xff\xff\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff"; // response to request channel 4: mask +const unsigned char reqchan5_rsp[] = "\x02\xf0\xb0\x0a\x00\xa0\x05\x87\x00\x00\x00\xec\x00\xf2\x3f\x03"; // response to request channel 5 +const unsigned char reqchan5_r_m[] = "\xff\xff\xff\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\xff"; // response to request channel 5: mask + + + +unsigned char chanVolt[6]; /* holds the voltages measured on channel 0 to 5 */ +int chanWatt[6]; /* holds the wattages measured on channel 0 to 5 */ + + +/* pototype section */ + +void init_serial3 (void); // Init UART-3 + + +void putchar3(unsigned char ch); // Put Char To UART-3 +unsigned char getchar3(unsigned char * rxTrue); // Get Char From UART-3 +void send_uart3(char * data, int length); // Print String to UART3 +void delay(unsigned long int); // Delay Time Function +void solarFSM(void); +unsigned char checkUart3Received( + const unsigned char * compareBuf, + const unsigned char * compareBufMask, + int lengthCompare); + + + +void testUART3(void) +{ + int k; + int RxBuf; // one rx char + int uart_data; // Character Receive Buffer + k = 0; + + + solarState = SOL_NO_INIT; + while (1) + { + + solarFSM(); + + if (solarState == SOL_FINISHED) + { + solarState = SOL_NO_INIT; + } /* if */ + } /* while */ + +} + +/* Clear Uart3 RxBuf and pointer to next Rx element */ +void resetUart3RxBuf(void) +{ + int i; + for (i = 0; i < RX_UART3_BUF_SIZE; i++) + { + rxUART3[i] = 0; // clear byte + } + rxBuf3NextFreeRxPos = 0; // buffer empty +} + + +/* Get data from Uart3 RxBuf if there is any, copy it to rxUART3 buffer */ +void getUart3RxData(void) +{ + + unsigned char RxBuf; // one rx char, or 0x100 if no data + unsigned char rxTrue; // did we receive a byte? + + while (rxBuf3NextFreeRxPos + 1 < RX_UART3_BUF_SIZE) + { + /* while not overran */ + + RxBuf = getchar3(&rxTrue); + if (rxTrue == 1) + { + // if data available + rxUART3[rxBuf3NextFreeRxPos] = RxBuf; + rxBuf3NextFreeRxPos++; + } /* if */ + else + { + break; /* no more data. break the while loop, finished. */ + } /* else */ + } /* while */ +} /* resetUart3RxBuf */ + + +/* Remove the first n bytes of Uart3 RxBuf, also adjust pointer to next Rx element */ +void chopUart3RxBuf(int n) +{ + int i; + + if (n > RX_UART3_BUF_SIZE) + { + /* n too large */ + resetUart3RxBuf (); + return; + } + /* move end part of the buffer (after n) to front */ + for (i = 0; i < n; i++) + { + rxUART3[i] = rxUART3[i+n]; // move byte + } + /* write 0 to now unused elements */ + for (i = n; i < RX_UART3_BUF_SIZE; i++) + { + rxUART3[i] = 0; // clear byte + } + /* adjust rxBuf3NextFreeRxPos */ + if (n >= rxBuf3NextFreeRxPos) + { + /* remove more elements than are in the buffer */ + rxBuf3NextFreeRxPos = 0; // buffer empty + } + else + { + rxBuf3NextFreeRxPos -= n; + } +} /* chopUart3RxBuf */ + + + + +/* + * checkUart3Received + * + * This routine checks if the bit pattern specified in compareBuf was received. Only bytes with the value + * 0xff in the corresponding index of compareBufMask are compared, others are don't care. + * lengthCompare bytes are compared. Comparison is always done from byte 0 of compareBuf and CompareBufMask. + * + * + */ +unsigned char checkUart3Received(const unsigned char * compareBuf, const unsigned char * compareBufMask, int lengthCompare) +{ + + /* first check if we received enough bytes */ + int numRxBytes; + int k; + int result; + volatile unsigned char * testRx; + volatile unsigned const char * testCmp; + volatile unsigned const char * testMask; + + numRxBytes = rxBuf3NextFreeRxPos; + + result = 0; /* begin: no mismatch */ + if (numRxBytes >= lengthCompare ) + { + /* we have received enough bytes */ + for (k = 0; k < lengthCompare; k++) + { + if ( (compareBufMask[k] == 0xff) && (compareBuf[k] != rxUART3[k]) ) + { + testRx = &(rxUART3[0]); + testCmp = &(compareBuf[0]); + testMask = &(compareBufMask[0]); + result = 1; /* we compare this bit (mask 0xff), and a mismatch occurred */ + break; + } + else + { + /* nothing, compare further */ ; + } /* else */ + } /* for */ + if (result == 1) + { + return k; /* mismatch, return first index that did not match */ + } + else + { + return 0; /* no mismatch, we got the desired byte pattern */ + } + + } /* if */ + else + { + /* we have not received enough bytes (yet) */ + return 0xff; + } /* else */ + +} /* checkUart3Received */ + + +void solarFSM(void) +{ + int cmpResult; + + /* always get Rx data */ + getUart3RxData(); + + switch (solarState) + { + case SOL_NO_INIT: + init_serial3(); + resetUart3RxBuf(); /* init */ + currentChannel = 0; /* the channel we query first */ + + TXD_RS485(); + /* send init 1 */ + send_uart3((unsigned char *)init1, sizeof(init1)); + RXD_RS485(); + solarState = SOL_SENT_INIT; /* now wait for reply */ + break; + + case SOL_SENT_INIT: + /* wait for reply to init, check if full response has arrived */ + cmpResult = checkUart3Received(init1_rsp, init1_r_m, sizeof(init1_rsp)-1); + if (cmpResult == 0) + { + /* we have got a match! */ + + /* copy Rx data */ + /* TODO */ + + + /* finally, discard data from buffer */ + resetUart3RxBuf(); + + /* now ready to query channel 0 data in next state */ + solarState = SOL_CHAN; + } + else + { + /* no match (yet), stay in state */ + } + + + break; + + case SOL_CHAN: + /* send query for channel number currentChannel */ + + TXD_RS485(); + switch ( currentChannel ) + { + case 0: + send_uart3((unsigned char *) reqchan0, sizeof(reqchan0)); + break; + case 1: + send_uart3((unsigned char *) reqchan1, sizeof(reqchan1)); + break; + case 2: + send_uart3((unsigned char *) reqchan2, sizeof(reqchan2)); + break; + case 3: + send_uart3((unsigned char *) reqchan3, sizeof(reqchan3)); + break; + case 4: + send_uart3((unsigned char *) reqchan4, sizeof(reqchan4)); + break; + case 5: + send_uart3((unsigned char *) reqchan5, sizeof(reqchan5)); + break; + case 6: + /* we are through with all the channels, send the final init */ + send_uart3((unsigned char *)init_after_all_chan, sizeof(init_after_all_chan)); + solarState = SOL_FINISHED; + break; + default: + ; /* do nothing */ + } /* switch */ + RXD_RS485(); + if (solarState != SOL_FINISHED) + { + solarState = SOL_CHAN_WAIT_REPLY; + } /* if */ + break; + + case SOL_CHAN_WAIT_REPLY: + + switch ( currentChannel ) + { + case 0: + cmpResult = checkUart3Received(reqchan0_rsp, reqchan0_r_m, sizeof(reqchan0_rsp)-1); + break; + case 1: + cmpResult = checkUart3Received(reqchan1_rsp, reqchan1_r_m, sizeof(reqchan1_rsp)-1); + break; + case 2: + cmpResult = checkUart3Received(reqchan2_rsp, reqchan2_r_m, sizeof(reqchan2_rsp)-1); + break; + case 3: + cmpResult = checkUart3Received(reqchan3_rsp, reqchan3_r_m, sizeof(reqchan3_rsp)-1); + break; + case 4: + cmpResult = checkUart3Received(reqchan4_rsp, reqchan4_r_m, sizeof(reqchan4_rsp)-1); + break; + case 5: + cmpResult = checkUart3Received(reqchan5_rsp, reqchan5_r_m, sizeof(reqchan5_rsp)-1); + break; + case 6: + /* wait for the response to the finishing init */ + cmpResult = checkUart3Received(init_after_all_chan_rsp, init_after_all_chan_r_m, sizeof(init_after_all_chan_rsp)-1); + break; + default: + /* unknown channel */ + break; + } /* switch */ + + + /* wait for reply to request, check if full response has arrived */ + if (cmpResult == 0) + { + /* we have got a match! */ + + /* copy Rx data */ + /* TODO */ + if ((currentChannel >= 0) && (currentChannel < 6)) + { + chanVolt[currentChannel] = rxUART3[11]; + chanWatt[currentChannel] = (int)rxUART3[7] | (((int)(rxUART3[6])) << 8) /* index 7: LSB, index 6: MSB */; + } /* if */ + /* finally, discard data from buffer */ + resetUart3RxBuf(); + + /* switch to next channel */ + currentChannel++; + /* now ready to query channel data for next channel */ + solarState = SOL_CHAN; + } + else + { + /* no match (yet), stay in state */ + } + break; + + + + } /* switch */ + + +} /* solarFSM */ + + + + +/********************************/ +/* Initial UART3 = 115200,N,8,1 */ +/********************************/ +void init_serial3 (void) +{ + unsigned int baud = 57600; + unsigned int divisor = get_uart_clk(3, OSCILLATOR_CLOCK_FREQUENCY) / (16 * baud); + + + int i; + + for (i = 0; i < RX_UART3_BUF_SIZE; i++) + { + rxUART3[i] = 0; + } + + + // xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1010 + PINSEL0 &= 0xFFFFFFF0; // Reset P0.0,P0.1 Pin Config + PINSEL0 |= 0x00000002; // Select P0.0 = TxD(UART3) + PINSEL0 |= 0x00000008; // Select P0.1 = RxD(UART3) + + // Config P1.19 = Output Control Direction RS485 + // P1.19 = "0" = Receive RS485 + // P1.19 = "1" = Transmit RS485 + // xxxx xxxx xxxx xxxx 00xx xxxx xxxx xxxx + PINSEL3 &= 0xFFFF3FFF; // P1.19 = GPIO + IODIR1 = DIR_RS485; // Pin Control Direction RS485 = Output + RXD_RS485(); // Default RS485 Direction + + //PCLKSEL1 = 0; /* UART3 frequency */ + + + // xxxx xx1x xxxx xxxx xxxx xxxx xxxx xxxx + PCONP |= 0x02000000; // UART3 Power-ON + + + +/* Configure UART */ + + + U3LCR = 0x83; // 8 bits, no Parity, 1 Stop bit + + U3DLL = divisor & 0xFF; + + U3DLM = (divisor >> 8) & 0xFF; + U3LCR = 0x03; // DLAB = 0 + +// Baud Rate Calculator: http://prototalk.net/forums/showthread.php?t=11 + +#if 0 + U3LCR = 0x83; // 8 bits, no Parity, 1 Stop bit + U3DLL = 0x0C; // Baud 57600BPS for 12MHz PCLK Clock + U3FDR = 0xC1; // Fractional Divider (0x67 = 115200 , 0xCE = 57600 ????), + U3DLM = 0; + + U3LCR = 0x03; // DLAB = 0 +#endif + + + +} + + + + +/***************************/ +/* Print String to UART[3] */ +/***************************/ +void send_uart3(char * data, int length) +{ + int i = 0; // Pointer Buffer + + TXD_RS485(); // Swap RS485 Direction = Transmit + delay(50000); + + + for (i = 0; i < length-1; i++) // Get char & Print Until null + { + /* go only through length-1 because we do not send the terminating \x00 of the c-string in data */ + putchar3(data[i]); // Write char to UART // Next char + } + + delay(50000); + RXD_RS485(); // Swap RS485 Direction = Receive + + return; +} + + +/***********************/ +/* Delay Time Function */ +/* 1-4294967296 */ +/***********************/ +void delay(unsigned long int count1) +{ + while(count1 > 0) {count1--;} // Loop Decrease Counter +} + +/******************************/ +/* Write Character To UART[3] */ +/******************************/ +void putchar3 (unsigned char ch) +{ + + while (!(U3LSR & 0x20)); // Wait TXD Buffer Empty + U3THR = ch; +} + + +/******************************/ +/* Get character From UART[3] */ +/******************************/ +unsigned char getchar3(unsigned char * rxTrue) +{ + + if (!(U3LSR & 0x01)) // Check RXD Receive Data Ready + { + *rxTrue = 0; /* no data received */ + return 0; // no data available + } + else + { + *rxTrue = 1; /* a byte was received */ + return (U3RBR); // Get Receive Data & Return + } +} +