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...

Dependencies:   mbed

Committer:
morten_opprud
Date:
Tue Sep 04 05:48:43 2012 +0000
Revision:
2:de090b60d543
Parent:
1:df4e9da66448
cleaned a bit before comitting, !NOTE! byte stuffing/unstuffing still needs wors, also CRC on incoming data is to be done

Who changed what in which revision?

UserRevisionLine numberNew contents of line
morten_opprud 0:66a099b01e08 1 /**
morten_opprud 0:66a099b01e08 2 * <describing text>
morten_opprud 0:66a099b01e08 3 *
morten_opprud 0:66a099b01e08 4 * @file commlynx_protocol.c.c
morten_opprud 0:66a099b01e08 5 * @ingroup <>
morten_opprud 0:66a099b01e08 6 *
morten_opprud 0:66a099b01e08 7 * @author MortenOJ
morten_opprud 0:66a099b01e08 8 * @date Aug 24, 2012
morten_opprud 0:66a099b01e08 9 *
morten_opprud 0:66a099b01e08 10 */
morten_opprud 0:66a099b01e08 11 #include "mbed.h"
morten_opprud 0:66a099b01e08 12 #include "unilynx.h"
morten_opprud 0:66a099b01e08 13 #include "crc.h"
morten_opprud 0:66a099b01e08 14
morten_opprud 0:66a099b01e08 15
morten_opprud 0:66a099b01e08 16 Serial rs485(p26, p25);
morten_opprud 1:df4e9da66448 17 //#define DEBUG
morten_opprud 1:df4e9da66448 18 #ifdef DEBUG
morten_opprud 0:66a099b01e08 19 Serial pc(USBTX, USBRX);
morten_opprud 1:df4e9da66448 20 #endif
morten_opprud 0:66a099b01e08 21
morten_opprud 0:66a099b01e08 22 // Telegram format
morten_opprud 0:66a099b01e08 23 //----------------------------------------------------------------------------------------------------
morten_opprud 0:66a099b01e08 24 // Start of frame / Header / Data / End of frame
morten_opprud 0:66a099b01e08 25 // Start / Address / Control / Source / Destination / Size / Type / Data / FCS / Stop
morten_opprud 0:66a099b01e08 26 // 1byte / 1byte / 1byte / 2bytes / 2bytes / 1byte / 1byte / 0-255bytes / 2bytes / 1byte
morten_opprud 0:66a099b01e08 27 //----------------------------------------------------------------------------------------------------
morten_opprud 0:66a099b01e08 28 //unsigned char txStr[255];
morten_opprud 0:66a099b01e08 29
morten_opprud 0:66a099b01e08 30 #define MY_ADDR0 0x28
morten_opprud 0:66a099b01e08 31 #define MY_ADDR1 0xD7
morten_opprud 0:66a099b01e08 32
morten_opprud 1:df4e9da66448 33 #define FRAME_START 0x7E
morten_opprud 1:df4e9da66448 34 #define FRAME_STOP 0x7E
morten_opprud 0:66a099b01e08 35 #define FRAME_ADDRESS 0xFF
morten_opprud 0:66a099b01e08 36 #define FRAME_CONTROL 0x03
morten_opprud 0:66a099b01e08 37
morten_opprud 0:66a099b01e08 38 #define PPPINITFCS16 0xFFFF /* Initial FCS value */
morten_opprud 0:66a099b01e08 39 #define PPPGOODFCS16 0xf0b8 /* Good final FCS value */
morten_opprud 0:66a099b01e08 40
morten_opprud 0:66a099b01e08 41 const unsigned char pingAllStr[12] =
morten_opprud 0:66a099b01e08 42 { 0x7E, 0xFF, 0x03, 0x00, 0x02, 0xFF, 0xFF, 0x00, 0x15, 0xB1, 0x8B, 0x7E };
morten_opprud 0:66a099b01e08 43
morten_opprud 0:66a099b01e08 44
morten_opprud 0:66a099b01e08 45 char pingAllStrWoCrc[12] =
morten_opprud 0:66a099b01e08 46 { 0x7E, 0xFF, 0x03, 0x00, 0x02, 0xFF, 0xFF, 0x00, 0x15, 0, 0, 0x7E };
morten_opprud 0:66a099b01e08 47 //{ 0x7E, 0xFF, 0x03, 0x00, 0x02, 0x12, 0x03, 0x00, 0x15, 0, 0, 0x7E };
morten_opprud 0:66a099b01e08 48 /* func code 0x13*/
morten_opprud 0:66a099b01e08 49
morten_opprud 0:66a099b01e08 50 char getNodeReqStrWoCrc[41] = {
morten_opprud 0:66a099b01e08 51 0x7E, 0xFF, 0x03, 0x00, 0x02, 0x28, 0xD7, 0x1D, 0x13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
morten_opprud 0:66a099b01e08 52 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
morten_opprud 0:66a099b01e08 53 0xFF, 0x00, 0x00, 0x7E
morten_opprud 0:66a099b01e08 54 };
morten_opprud 0:66a099b01e08 55
morten_opprud 0:66a099b01e08 56 char getNodeParamStrWoCrc[41] =
morten_opprud 0:66a099b01e08 57 { 0x7E, 0xFF, 0x03, 0x00, 0x02, 0x28, 0xD7, 0x0A, 0x01, 0xC8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x7E };
morten_opprud 0:66a099b01e08 58
morten_opprud 0:66a099b01e08 59
morten_opprud 0:66a099b01e08 60 char tx[40];
morten_opprud 0:66a099b01e08 61
morten_opprud 2:de090b60d543 62 /*
morten_opprud 2:de090b60d543 63 Steup RS 485 ON UART1,using DTR for direction control on RS485
morten_opprud 2:de090b60d543 64 */
morten_opprud 0:66a099b01e08 65 void rs485init(void)
morten_opprud 0:66a099b01e08 66 {
morten_opprud 0:66a099b01e08 67 rs485.baud(19200);
morten_opprud 1:df4e9da66448 68 #ifdef DEBUG
morten_opprud 0:66a099b01e08 69 pc.baud(115200);
morten_opprud 1:df4e9da66448 70 #endif
morten_opprud 0:66a099b01e08 71 LPC_PINCON->PINSEL4 &= 0x0ffff;
morten_opprud 0:66a099b01e08 72 LPC_PINCON->PINSEL4 |= 0x0AAAA;
morten_opprud 0:66a099b01e08 73
morten_opprud 0:66a099b01e08 74 LPC_UART1->RS485DLY = 128;
morten_opprud 0:66a099b01e08 75
morten_opprud 0:66a099b01e08 76 LPC_UART1->RS485CTRL &=~(1<<1); //Receiver enabled
morten_opprud 0:66a099b01e08 77 LPC_UART1->RS485CTRL &=~(1<<2); //AAD disabled
morten_opprud 0:66a099b01e08 78 LPC_UART1->RS485CTRL |= (1<<3); //DTR used for direction control
morten_opprud 0:66a099b01e08 79 LPC_UART1->RS485CTRL |= (1<<4); //direction control enabled
morten_opprud 0:66a099b01e08 80 LPC_UART1->RS485CTRL |= (1<<5); //DTR=1 when transmitting
morten_opprud 0:66a099b01e08 81 }
morten_opprud 0:66a099b01e08 82
morten_opprud 1:df4e9da66448 83 static void rs485write(char* str, int len)
morten_opprud 0:66a099b01e08 84 {
morten_opprud 0:66a099b01e08 85 int i;
morten_opprud 0:66a099b01e08 86 i=0;
morten_opprud 2:de090b60d543 87 while(i < len)
morten_opprud 2:de090b60d543 88 {
morten_opprud 2:de090b60d543 89 /* Byte stuff needed ? */
morten_opprud 2:de090b60d543 90 /* if((*(str +i)) == 0x7E)
morten_opprud 2:de090b60d543 91 {
morten_opprud 2:de090b60d543 92 rs485.putc(0x7D);
morten_opprud 2:de090b60d543 93 rs485.putc(0x5E);
morten_opprud 2:de090b60d543 94 }
morten_opprud 2:de090b60d543 95 else if((*(str +i)) == 0x7D)
morten_opprud 2:de090b60d543 96 {
morten_opprud 2:de090b60d543 97 rs485.putc(0x7D);
morten_opprud 2:de090b60d543 98 rs485.putc(0x5D);
morten_opprud 2:de090b60d543 99 }
morten_opprud 2:de090b60d543 100 /*
morten_opprud 2:de090b60d543 101 /* nope, TX as usual */
morten_opprud 2:de090b60d543 102 //else
morten_opprud 2:de090b60d543 103 rs485.putc(*(str +i));
morten_opprud 2:de090b60d543 104 /* incr. index */
morten_opprud 0:66a099b01e08 105 i++;
morten_opprud 0:66a099b01e08 106 }
morten_opprud 0:66a099b01e08 107 }
morten_opprud 0:66a099b01e08 108
morten_opprud 0:66a099b01e08 109 static void rs485read(char* str, int len)
morten_opprud 0:66a099b01e08 110 {
morten_opprud 0:66a099b01e08 111 int i;
morten_opprud 0:66a099b01e08 112 i=0;
morten_opprud 0:66a099b01e08 113 while(i < len) {
morten_opprud 0:66a099b01e08 114 (*(str +i)) = rs485.getc();
morten_opprud 2:de090b60d543 115
morten_opprud 2:de090b60d543 116 #if 0
morten_opprud 2:de090b60d543 117 /* Byte unstuff needed ? */
morten_opprud 2:de090b60d543 118 if(((*(str +i-1)) == 0x7D) &&((*(str +i)) == 0x5E))
morten_opprud 2:de090b60d543 119 {
morten_opprud 2:de090b60d543 120 /* subtract first bytestuff-byte w 0x7E*/
morten_opprud 2:de090b60d543 121 (*(str +i-1)) = 0x7E;
morten_opprud 2:de090b60d543 122 /*decrement indenx, so next byte will contain next RX char,
morten_opprud 2:de090b60d543 123 and not byte-stuff leftovers..*/
morten_opprud 2:de090b60d543 124 i--;
morten_opprud 2:de090b60d543 125 /*and btw. we need read one more char, since byte stuff has added one...*/
morten_opprud 2:de090b60d543 126 len++;
morten_opprud 2:de090b60d543 127 }
morten_opprud 2:de090b60d543 128 else if(((*(str +i-1)) == 0x7D) &&((*(str +i)) == 0x5D))
morten_opprud 2:de090b60d543 129
morten_opprud 2:de090b60d543 130 {
morten_opprud 2:de090b60d543 131 (*(str +i-1)) = 0x7D;
morten_opprud 2:de090b60d543 132 i--;
morten_opprud 2:de090b60d543 133 len++;
morten_opprud 2:de090b60d543 134 }
morten_opprud 2:de090b60d543 135 #endif
morten_opprud 0:66a099b01e08 136 i++;
morten_opprud 0:66a099b01e08 137 //TODO add timeout
morten_opprud 0:66a099b01e08 138 }
morten_opprud 0:66a099b01e08 139 }
morten_opprud 0:66a099b01e08 140
morten_opprud 1:df4e9da66448 141 /*
morten_opprud 1:df4e9da66448 142 Get node info, serial no etc...
morten_opprud 1:df4e9da66448 143 currently kept in local variables insode function.
morten_opprud 1:df4e9da66448 144 */
morten_opprud 0:66a099b01e08 145 void getNodeInfo(void)
morten_opprud 0:66a099b01e08 146 {
morten_opprud 0:66a099b01e08 147 /* data of interest TODO MAKE GLOBAL AVAILIBLE */
morten_opprud 0:66a099b01e08 148 char network, subnet, address;
morten_opprud 0:66a099b01e08 149
morten_opprud 0:66a099b01e08 150 /*local variables*/
morten_opprud 0:66a099b01e08 151 char rx[42];
morten_opprud 0:66a099b01e08 152 short fcs;
morten_opprud 0:66a099b01e08 153 /* fill in address */
morten_opprud 0:66a099b01e08 154 getNodeReqStrWoCrc[5] = MY_ADDR0;
morten_opprud 0:66a099b01e08 155 getNodeReqStrWoCrc[6] = MY_ADDR1;
morten_opprud 0:66a099b01e08 156 /* calculate CRC and fill in string */
morten_opprud 0:66a099b01e08 157 fcs = pppfcs16( PPPINITFCS16, &getNodeReqStrWoCrc[1], 37 );
morten_opprud 0:66a099b01e08 158 fcs ^= 0xFFFF;
morten_opprud 0:66a099b01e08 159 getNodeReqStrWoCrc[38] = (unsigned char)(fcs & 0xFF);
morten_opprud 0:66a099b01e08 160 getNodeReqStrWoCrc[39] = (unsigned char)((fcs>>8) & 0xFF);
morten_opprud 0:66a099b01e08 161 /* send request */
morten_opprud 0:66a099b01e08 162 rs485write(getNodeReqStrWoCrc,41);
morten_opprud 0:66a099b01e08 163 /* retrieve response */
morten_opprud 0:66a099b01e08 164 rs485read(rx,41);
morten_opprud 1:df4e9da66448 165 //TODO CRC
morten_opprud 0:66a099b01e08 166 /* extract data*/
morten_opprud 0:66a099b01e08 167 network = rx[33];
morten_opprud 0:66a099b01e08 168 subnet = rx[34];
morten_opprud 0:66a099b01e08 169 address = rx[35];
morten_opprud 1:df4e9da66448 170
morten_opprud 0:66a099b01e08 171 //pc.printf("Network: %X Subnet: %X Address: %X",network,subnet, address);
morten_opprud 0:66a099b01e08 172 }
morten_opprud 0:66a099b01e08 173
morten_opprud 1:df4e9da66448 174 /*
morten_opprud 1:df4e9da66448 175 read a parameter from the inverter
morten_opprud 1:df4e9da66448 176 @param param_idx "index" used to retrieve parameter values
morten_opprud 1:df4e9da66448 177 @param param_sub_idx "sub-index" used to retrieve parameter values
morten_opprud 1:df4e9da66448 178 */
morten_opprud 1:df4e9da66448 179 int readParameter(int param_idx, int param_sub_idx, int dest)
morten_opprud 0:66a099b01e08 180 {
morten_opprud 1:df4e9da66448 181 short fcs;
morten_opprud 1:df4e9da66448 182 short u16val;
morten_opprud 1:df4e9da66448 183 int u32val;
morten_opprud 1:df4e9da66448 184 char rx[24];
morten_opprud 1:df4e9da66448 185 char flags;
morten_opprud 0:66a099b01e08 186
morten_opprud 0:66a099b01e08 187
morten_opprud 1:df4e9da66448 188 /* fill in address */
morten_opprud 1:df4e9da66448 189 getNodeParamStrWoCrc[5] = MY_ADDR0;
morten_opprud 1:df4e9da66448 190 getNodeParamStrWoCrc[6] = MY_ADDR1;
morten_opprud 1:df4e9da66448 191
morten_opprud 1:df4e9da66448 192 getNodeParamStrWoCrc[10] = dest;//0x04;//0D;//
morten_opprud 1:df4e9da66448 193 getNodeParamStrWoCrc[11] = 0xD0;//((source<<4) | page);
morten_opprud 1:df4e9da66448 194 getNodeParamStrWoCrc[12] = (param_idx);
morten_opprud 1:df4e9da66448 195 getNodeParamStrWoCrc[13] = (param_sub_idx);
morten_opprud 2:de090b60d543 196 getNodeParamStrWoCrc[14] = 0x80;// we want reply (DO_REPLY | IM_REQUEST | TYPE_U16);
morten_opprud 1:df4e9da66448 197 getNodeParamStrWoCrc[15] = 0;
morten_opprud 1:df4e9da66448 198 getNodeParamStrWoCrc[16] = 0;
morten_opprud 1:df4e9da66448 199 getNodeParamStrWoCrc[17] = 0;
morten_opprud 1:df4e9da66448 200 getNodeParamStrWoCrc[18] = 0;
morten_opprud 1:df4e9da66448 201
morten_opprud 1:df4e9da66448 202 /* calculate VRC and fill in string */
morten_opprud 1:df4e9da66448 203 fcs = pppfcs16( PPPINITFCS16, &getNodeParamStrWoCrc[1], 18 );
morten_opprud 1:df4e9da66448 204 fcs ^= 0xFFFF;
morten_opprud 1:df4e9da66448 205 getNodeParamStrWoCrc[19] = (unsigned char)(fcs & 0xFF);
morten_opprud 1:df4e9da66448 206 getNodeParamStrWoCrc[20] = (unsigned char)((fcs>>8) & 0xFF);
morten_opprud 0:66a099b01e08 207
morten_opprud 1:df4e9da66448 208 /* send request */
morten_opprud 1:df4e9da66448 209 rs485write(getNodeParamStrWoCrc,22);
morten_opprud 1:df4e9da66448 210 /* retrieve response */
morten_opprud 1:df4e9da66448 211 rs485read(rx,22);
morten_opprud 1:df4e9da66448 212 //TODO CRC
morten_opprud 1:df4e9da66448 213 /* extract data*/
morten_opprud 1:df4e9da66448 214 flags = rx[14];
morten_opprud 0:66a099b01e08 215
morten_opprud 1:df4e9da66448 216 switch (flags & 0x0F) {
morten_opprud 2:de090b60d543 217 case 0x06: //decode U16
morten_opprud 1:df4e9da66448 218 u16val = ((rx[16]<<8)+rx[15]);
morten_opprud 1:df4e9da66448 219 return (int)u16val;
morten_opprud 1:df4e9da66448 220 break;
morten_opprud 2:de090b60d543 221 case 0x07: //decode U32
morten_opprud 1:df4e9da66448 222 u32val = ((rx[18]<<24)+(rx[17]<<16)+(rx[16]<<8)+rx[15]);
morten_opprud 1:df4e9da66448 223 return u32val;
morten_opprud 1:df4e9da66448 224 break;
morten_opprud 1:df4e9da66448 225 default:
morten_opprud 1:df4e9da66448 226 #ifdef DEBUG
morten_opprud 1:df4e9da66448 227 com.printf("You got work to do !! Flags are: %X" ,rx[14]);
morten_opprud 1:df4e9da66448 228 #endif
morten_opprud 1:df4e9da66448 229 break;
morten_opprud 0:66a099b01e08 230 }
morten_opprud 0:66a099b01e08 231 }
morten_opprud 0:66a099b01e08 232
morten_opprud 0:66a099b01e08 233 void ping(void)
morten_opprud 0:66a099b01e08 234 {
morten_opprud 0:66a099b01e08 235 int rxcnt = 0;
morten_opprud 0:66a099b01e08 236 char rx[14];
morten_opprud 0:66a099b01e08 237 short fcs;
morten_opprud 0:66a099b01e08 238
morten_opprud 0:66a099b01e08 239 for(int i=0; i < 12; i++) {
morten_opprud 0:66a099b01e08 240 rs485.putc(pingAllStr[i]);
morten_opprud 0:66a099b01e08 241 }
morten_opprud 0:66a099b01e08 242 while(1) {
morten_opprud 0:66a099b01e08 243 if(rs485.readable()) {
morten_opprud 0:66a099b01e08 244 rx[rxcnt++] = rs485.getc();
morten_opprud 0:66a099b01e08 245 }
morten_opprud 0:66a099b01e08 246 /* reached stop 0x7E ? todo, timeout & CRC*/
morten_opprud 0:66a099b01e08 247 if( rxcnt > 10)
morten_opprud 0:66a099b01e08 248 if(rx[rxcnt] == 0x7E)
morten_opprud 0:66a099b01e08 249 break;
morten_opprud 0:66a099b01e08 250 if( rxcnt == 11)
morten_opprud 0:66a099b01e08 251 break;
morten_opprud 0:66a099b01e08 252 }
morten_opprud 0:66a099b01e08 253 }