implementation of parts of the unilynx protocol, for communicating with danfos photovoltaic inverters. Still BETA ! needs byte stuff/unstuff fixed, and some CRC are left out for niw...
unilynx.cpp
- Committer:
- morten_opprud
- Date:
- 2012-09-04
- Revision:
- 2:de090b60d543
- Parent:
- 1:df4e9da66448
File content as of revision 2:de090b60d543:
/** * <describing text> * * @file commlynx_protocol.c.c * @ingroup <> * * @author MortenOJ * @date Aug 24, 2012 * */ #include "mbed.h" #include "unilynx.h" #include "crc.h" Serial rs485(p26, p25); //#define DEBUG #ifdef DEBUG Serial pc(USBTX, USBRX); #endif // Telegram format //---------------------------------------------------------------------------------------------------- // Start of frame / Header / Data / End of frame // Start / Address / Control / Source / Destination / Size / Type / Data / FCS / Stop // 1byte / 1byte / 1byte / 2bytes / 2bytes / 1byte / 1byte / 0-255bytes / 2bytes / 1byte //---------------------------------------------------------------------------------------------------- //unsigned char txStr[255]; #define MY_ADDR0 0x28 #define MY_ADDR1 0xD7 #define FRAME_START 0x7E #define FRAME_STOP 0x7E #define FRAME_ADDRESS 0xFF #define FRAME_CONTROL 0x03 #define PPPINITFCS16 0xFFFF /* Initial FCS value */ #define PPPGOODFCS16 0xf0b8 /* Good final FCS value */ const unsigned char pingAllStr[12] = { 0x7E, 0xFF, 0x03, 0x00, 0x02, 0xFF, 0xFF, 0x00, 0x15, 0xB1, 0x8B, 0x7E }; char pingAllStrWoCrc[12] = { 0x7E, 0xFF, 0x03, 0x00, 0x02, 0xFF, 0xFF, 0x00, 0x15, 0, 0, 0x7E }; //{ 0x7E, 0xFF, 0x03, 0x00, 0x02, 0x12, 0x03, 0x00, 0x15, 0, 0, 0x7E }; /* func code 0x13*/ char getNodeReqStrWoCrc[41] = { 0x7E, 0xFF, 0x03, 0x00, 0x02, 0x28, 0xD7, 0x1D, 0x13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x7E }; char getNodeParamStrWoCrc[41] = { 0x7E, 0xFF, 0x03, 0x00, 0x02, 0x28, 0xD7, 0x0A, 0x01, 0xC8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x7E }; char tx[40]; /* Steup RS 485 ON UART1,using DTR for direction control on RS485 */ void rs485init(void) { rs485.baud(19200); #ifdef DEBUG pc.baud(115200); #endif LPC_PINCON->PINSEL4 &= 0x0ffff; LPC_PINCON->PINSEL4 |= 0x0AAAA; LPC_UART1->RS485DLY = 128; LPC_UART1->RS485CTRL &=~(1<<1); //Receiver enabled LPC_UART1->RS485CTRL &=~(1<<2); //AAD disabled LPC_UART1->RS485CTRL |= (1<<3); //DTR used for direction control LPC_UART1->RS485CTRL |= (1<<4); //direction control enabled LPC_UART1->RS485CTRL |= (1<<5); //DTR=1 when transmitting } static void rs485write(char* str, int len) { int i; i=0; while(i < len) { /* Byte stuff needed ? */ /* if((*(str +i)) == 0x7E) { rs485.putc(0x7D); rs485.putc(0x5E); } else if((*(str +i)) == 0x7D) { rs485.putc(0x7D); rs485.putc(0x5D); } /* /* nope, TX as usual */ //else rs485.putc(*(str +i)); /* incr. index */ i++; } } static void rs485read(char* str, int len) { int i; i=0; while(i < len) { (*(str +i)) = rs485.getc(); #if 0 /* Byte unstuff needed ? */ if(((*(str +i-1)) == 0x7D) &&((*(str +i)) == 0x5E)) { /* subtract first bytestuff-byte w 0x7E*/ (*(str +i-1)) = 0x7E; /*decrement indenx, so next byte will contain next RX char, and not byte-stuff leftovers..*/ i--; /*and btw. we need read one more char, since byte stuff has added one...*/ len++; } else if(((*(str +i-1)) == 0x7D) &&((*(str +i)) == 0x5D)) { (*(str +i-1)) = 0x7D; i--; len++; } #endif i++; //TODO add timeout } } /* Get node info, serial no etc... currently kept in local variables insode function. */ void getNodeInfo(void) { /* data of interest TODO MAKE GLOBAL AVAILIBLE */ char network, subnet, address; /*local variables*/ char rx[42]; short fcs; /* fill in address */ getNodeReqStrWoCrc[5] = MY_ADDR0; getNodeReqStrWoCrc[6] = MY_ADDR1; /* calculate CRC and fill in string */ fcs = pppfcs16( PPPINITFCS16, &getNodeReqStrWoCrc[1], 37 ); fcs ^= 0xFFFF; getNodeReqStrWoCrc[38] = (unsigned char)(fcs & 0xFF); getNodeReqStrWoCrc[39] = (unsigned char)((fcs>>8) & 0xFF); /* send request */ rs485write(getNodeReqStrWoCrc,41); /* retrieve response */ rs485read(rx,41); //TODO CRC /* extract data*/ network = rx[33]; subnet = rx[34]; address = rx[35]; //pc.printf("Network: %X Subnet: %X Address: %X",network,subnet, address); } /* read a parameter from the inverter @param param_idx "index" used to retrieve parameter values @param param_sub_idx "sub-index" used to retrieve parameter values */ int readParameter(int param_idx, int param_sub_idx, int dest) { short fcs; short u16val; int u32val; char rx[24]; char flags; /* fill in address */ getNodeParamStrWoCrc[5] = MY_ADDR0; getNodeParamStrWoCrc[6] = MY_ADDR1; getNodeParamStrWoCrc[10] = dest;//0x04;//0D;// getNodeParamStrWoCrc[11] = 0xD0;//((source<<4) | page); getNodeParamStrWoCrc[12] = (param_idx); getNodeParamStrWoCrc[13] = (param_sub_idx); getNodeParamStrWoCrc[14] = 0x80;// we want reply (DO_REPLY | IM_REQUEST | TYPE_U16); getNodeParamStrWoCrc[15] = 0; getNodeParamStrWoCrc[16] = 0; getNodeParamStrWoCrc[17] = 0; getNodeParamStrWoCrc[18] = 0; /* calculate VRC and fill in string */ fcs = pppfcs16( PPPINITFCS16, &getNodeParamStrWoCrc[1], 18 ); fcs ^= 0xFFFF; getNodeParamStrWoCrc[19] = (unsigned char)(fcs & 0xFF); getNodeParamStrWoCrc[20] = (unsigned char)((fcs>>8) & 0xFF); /* send request */ rs485write(getNodeParamStrWoCrc,22); /* retrieve response */ rs485read(rx,22); //TODO CRC /* extract data*/ flags = rx[14]; switch (flags & 0x0F) { case 0x06: //decode U16 u16val = ((rx[16]<<8)+rx[15]); return (int)u16val; break; case 0x07: //decode U32 u32val = ((rx[18]<<24)+(rx[17]<<16)+(rx[16]<<8)+rx[15]); return u32val; break; default: #ifdef DEBUG com.printf("You got work to do !! Flags are: %X" ,rx[14]); #endif break; } } void ping(void) { int rxcnt = 0; char rx[14]; short fcs; for(int i=0; i < 12; i++) { rs485.putc(pingAllStr[i]); } while(1) { if(rs485.readable()) { rx[rxcnt++] = rs485.getc(); } /* reached stop 0x7E ? todo, timeout & CRC*/ if( rxcnt > 10) if(rx[rxcnt] == 0x7E) break; if( rxcnt == 11) break; } }