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 Aug 28 19:53:42 2012 +0000
Revision:
1:df4e9da66448
Parent:
0:66a099b01e08
Child:
2:de090b60d543
can retrieve values, still needs CRC and byte stuffing

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
morten_opprud 0:66a099b01e08 46 /*const char getNodeReqStr[41] =
morten_opprud 0:66a099b01e08 47 { 0x7E, 0xFF, 0x03, 0x00, 0x02, 0x12, 0x03, 0x1D, 0x13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
morten_opprud 0:66a099b01e08 48 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
morten_opprud 0:66a099b01e08 49 0xFF, 0xC9, 0x35, 0x7E };
morten_opprud 0:66a099b01e08 50 */
morten_opprud 0:66a099b01e08 51 /*
morten_opprud 0:66a099b01e08 52 const char getNodeReqStr[41] =
morten_opprud 0:66a099b01e08 53 { 0x7E, 0xFF, 0x03, 0x00, 0x02, 0x12, 0x03, 0x1D, 0x13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
morten_opprud 0:66a099b01e08 54 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
morten_opprud 0:66a099b01e08 55 0xFF, 0xC9, 0x35, 0x7E };
morten_opprud 0:66a099b01e08 56 */
morten_opprud 0:66a099b01e08 57
morten_opprud 0:66a099b01e08 58 char pingAllStrWoCrc[12] =
morten_opprud 0:66a099b01e08 59 { 0x7E, 0xFF, 0x03, 0x00, 0x02, 0xFF, 0xFF, 0x00, 0x15, 0, 0, 0x7E };
morten_opprud 0:66a099b01e08 60 //{ 0x7E, 0xFF, 0x03, 0x00, 0x02, 0x12, 0x03, 0x00, 0x15, 0, 0, 0x7E };
morten_opprud 0:66a099b01e08 61 /* func code 0x13*/
morten_opprud 0:66a099b01e08 62
morten_opprud 0:66a099b01e08 63 char getNodeReqStrWoCrc[41] = {
morten_opprud 0:66a099b01e08 64 0x7E, 0xFF, 0x03, 0x00, 0x02, 0x28, 0xD7, 0x1D, 0x13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
morten_opprud 0:66a099b01e08 65 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
morten_opprud 0:66a099b01e08 66 0xFF, 0x00, 0x00, 0x7E
morten_opprud 0:66a099b01e08 67 };
morten_opprud 0:66a099b01e08 68
morten_opprud 0:66a099b01e08 69 char getNodeParamStrWoCrc[41] =
morten_opprud 0:66a099b01e08 70 { 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 71
morten_opprud 0:66a099b01e08 72
morten_opprud 0:66a099b01e08 73 char tx[40];
morten_opprud 0:66a099b01e08 74
morten_opprud 0:66a099b01e08 75 void rs485init(void)
morten_opprud 0:66a099b01e08 76 {
morten_opprud 0:66a099b01e08 77 rs485.baud(19200);
morten_opprud 1:df4e9da66448 78 #ifdef DEBUG
morten_opprud 0:66a099b01e08 79 pc.baud(115200);
morten_opprud 1:df4e9da66448 80 #endif
morten_opprud 0:66a099b01e08 81 LPC_PINCON->PINSEL4 &= 0x0ffff;
morten_opprud 0:66a099b01e08 82 LPC_PINCON->PINSEL4 |= 0x0AAAA;
morten_opprud 0:66a099b01e08 83
morten_opprud 0:66a099b01e08 84 LPC_UART1->RS485DLY = 128;
morten_opprud 0:66a099b01e08 85
morten_opprud 0:66a099b01e08 86 LPC_UART1->RS485CTRL &=~(1<<1); //Receiver enabled
morten_opprud 0:66a099b01e08 87 LPC_UART1->RS485CTRL &=~(1<<2); //AAD disabled
morten_opprud 0:66a099b01e08 88 LPC_UART1->RS485CTRL |= (1<<3); //DTR used for direction control
morten_opprud 0:66a099b01e08 89 LPC_UART1->RS485CTRL |= (1<<4); //direction control enabled
morten_opprud 0:66a099b01e08 90 LPC_UART1->RS485CTRL |= (1<<5); //DTR=1 when transmitting
morten_opprud 0:66a099b01e08 91 }
morten_opprud 0:66a099b01e08 92
morten_opprud 1:df4e9da66448 93 static void rs485write(char* str, int len)
morten_opprud 0:66a099b01e08 94 {
morten_opprud 0:66a099b01e08 95 int i;
morten_opprud 0:66a099b01e08 96 i=0;
morten_opprud 1:df4e9da66448 97 while(i < len) {
morten_opprud 0:66a099b01e08 98 rs485.putc(*(str +i));
morten_opprud 0:66a099b01e08 99 i++;
morten_opprud 1:df4e9da66448 100 //TODO byte stuff
morten_opprud 1:df4e9da66448 101
morten_opprud 0:66a099b01e08 102 }
morten_opprud 0:66a099b01e08 103 }
morten_opprud 0:66a099b01e08 104
morten_opprud 0:66a099b01e08 105 static void rs485read(char* str, int len)
morten_opprud 0:66a099b01e08 106 {
morten_opprud 0:66a099b01e08 107 int i;
morten_opprud 0:66a099b01e08 108 i=0;
morten_opprud 0:66a099b01e08 109 while(i < len) {
morten_opprud 0:66a099b01e08 110 (*(str +i)) = rs485.getc();
morten_opprud 0:66a099b01e08 111 i++;
morten_opprud 1:df4e9da66448 112 //TODO byte unstuff
morten_opprud 0:66a099b01e08 113 //TODO add timeout
morten_opprud 0:66a099b01e08 114 }
morten_opprud 0:66a099b01e08 115 }
morten_opprud 0:66a099b01e08 116
morten_opprud 1:df4e9da66448 117 /*
morten_opprud 1:df4e9da66448 118 Get node info, serial no etc...
morten_opprud 1:df4e9da66448 119 currently kept in local variables insode function.
morten_opprud 1:df4e9da66448 120 */
morten_opprud 0:66a099b01e08 121 void getNodeInfo(void)
morten_opprud 0:66a099b01e08 122 {
morten_opprud 0:66a099b01e08 123 /* data of interest TODO MAKE GLOBAL AVAILIBLE */
morten_opprud 0:66a099b01e08 124 char network, subnet, address;
morten_opprud 0:66a099b01e08 125
morten_opprud 0:66a099b01e08 126 /*local variables*/
morten_opprud 0:66a099b01e08 127 char rx[42];
morten_opprud 0:66a099b01e08 128 short fcs;
morten_opprud 0:66a099b01e08 129 /* fill in address */
morten_opprud 0:66a099b01e08 130 getNodeReqStrWoCrc[5] = MY_ADDR0;
morten_opprud 0:66a099b01e08 131 getNodeReqStrWoCrc[6] = MY_ADDR1;
morten_opprud 0:66a099b01e08 132 /* calculate CRC and fill in string */
morten_opprud 0:66a099b01e08 133 fcs = pppfcs16( PPPINITFCS16, &getNodeReqStrWoCrc[1], 37 );
morten_opprud 0:66a099b01e08 134 fcs ^= 0xFFFF;
morten_opprud 0:66a099b01e08 135 getNodeReqStrWoCrc[38] = (unsigned char)(fcs & 0xFF);
morten_opprud 0:66a099b01e08 136 getNodeReqStrWoCrc[39] = (unsigned char)((fcs>>8) & 0xFF);
morten_opprud 0:66a099b01e08 137 /* send request */
morten_opprud 0:66a099b01e08 138 rs485write(getNodeReqStrWoCrc,41);
morten_opprud 0:66a099b01e08 139 /* retrieve response */
morten_opprud 0:66a099b01e08 140 rs485read(rx,41);
morten_opprud 1:df4e9da66448 141 //TODO CRC
morten_opprud 0:66a099b01e08 142 /* extract data*/
morten_opprud 0:66a099b01e08 143 network = rx[33];
morten_opprud 0:66a099b01e08 144 subnet = rx[34];
morten_opprud 0:66a099b01e08 145 address = rx[35];
morten_opprud 1:df4e9da66448 146
morten_opprud 0:66a099b01e08 147 //pc.printf("Network: %X Subnet: %X Address: %X",network,subnet, address);
morten_opprud 0:66a099b01e08 148 }
morten_opprud 0:66a099b01e08 149
morten_opprud 1:df4e9da66448 150 /*
morten_opprud 1:df4e9da66448 151 read a parameter from the inverter
morten_opprud 1:df4e9da66448 152 @param param_idx "index" used to retrieve parameter values
morten_opprud 1:df4e9da66448 153 @param param_sub_idx "sub-index" used to retrieve parameter values
morten_opprud 1:df4e9da66448 154 */
morten_opprud 1:df4e9da66448 155 int readParameter(int param_idx, int param_sub_idx, int dest)
morten_opprud 0:66a099b01e08 156 {
morten_opprud 1:df4e9da66448 157 short fcs;
morten_opprud 1:df4e9da66448 158 short u16val;
morten_opprud 1:df4e9da66448 159 int u32val;
morten_opprud 1:df4e9da66448 160 char rx[24];
morten_opprud 1:df4e9da66448 161 char flags;
morten_opprud 0:66a099b01e08 162
morten_opprud 0:66a099b01e08 163
morten_opprud 1:df4e9da66448 164 /* fill in address */
morten_opprud 1:df4e9da66448 165 getNodeParamStrWoCrc[5] = MY_ADDR0;
morten_opprud 1:df4e9da66448 166 getNodeParamStrWoCrc[6] = MY_ADDR1;
morten_opprud 1:df4e9da66448 167
morten_opprud 1:df4e9da66448 168 getNodeParamStrWoCrc[10] = dest;//0x04;//0D;//
morten_opprud 1:df4e9da66448 169 getNodeParamStrWoCrc[11] = 0xD0;//((source<<4) | page);
morten_opprud 1:df4e9da66448 170 getNodeParamStrWoCrc[12] = (param_idx);
morten_opprud 1:df4e9da66448 171 getNodeParamStrWoCrc[13] = (param_sub_idx);
morten_opprud 1:df4e9da66448 172 getNodeParamStrWoCrc[14] = 0x80;// we want reply (DO_REPLY | IM_REQUEST | TYPE_U16);
morten_opprud 1:df4e9da66448 173 getNodeParamStrWoCrc[15] = 0;
morten_opprud 1:df4e9da66448 174 getNodeParamStrWoCrc[16] = 0;
morten_opprud 1:df4e9da66448 175 getNodeParamStrWoCrc[17] = 0;
morten_opprud 1:df4e9da66448 176 getNodeParamStrWoCrc[18] = 0;
morten_opprud 1:df4e9da66448 177
morten_opprud 1:df4e9da66448 178 /* calculate VRC and fill in string */
morten_opprud 1:df4e9da66448 179 fcs = pppfcs16( PPPINITFCS16, &getNodeParamStrWoCrc[1], 18 );
morten_opprud 1:df4e9da66448 180 fcs ^= 0xFFFF;
morten_opprud 1:df4e9da66448 181 getNodeParamStrWoCrc[19] = (unsigned char)(fcs & 0xFF);
morten_opprud 1:df4e9da66448 182 getNodeParamStrWoCrc[20] = (unsigned char)((fcs>>8) & 0xFF);
morten_opprud 0:66a099b01e08 183
morten_opprud 1:df4e9da66448 184 /* send request */
morten_opprud 1:df4e9da66448 185 rs485write(getNodeParamStrWoCrc,22);
morten_opprud 1:df4e9da66448 186 /* retrieve response */
morten_opprud 1:df4e9da66448 187 rs485read(rx,22);
morten_opprud 1:df4e9da66448 188 //TODO CRC
morten_opprud 1:df4e9da66448 189 /* extract data*/
morten_opprud 1:df4e9da66448 190 flags = rx[14];
morten_opprud 0:66a099b01e08 191
morten_opprud 1:df4e9da66448 192 switch (flags & 0x0F) {
morten_opprud 1:df4e9da66448 193 case 0x06: //decode U16
morten_opprud 1:df4e9da66448 194 u16val = ((rx[16]<<8)+rx[15]);
morten_opprud 1:df4e9da66448 195 return (int)u16val;
morten_opprud 1:df4e9da66448 196 break;
morten_opprud 1:df4e9da66448 197 case 0x07: //decode U32
morten_opprud 1:df4e9da66448 198 u32val = ((rx[18]<<24)+(rx[17]<<16)+(rx[16]<<8)+rx[15]);
morten_opprud 1:df4e9da66448 199 return u32val;
morten_opprud 1:df4e9da66448 200 break;
morten_opprud 1:df4e9da66448 201 default:
morten_opprud 1:df4e9da66448 202 #ifdef DEBUG
morten_opprud 1:df4e9da66448 203 com.printf("You got work to do !! Flags are: %X" ,rx[14]);
morten_opprud 1:df4e9da66448 204 #endif
morten_opprud 1:df4e9da66448 205 break;
morten_opprud 0:66a099b01e08 206 }
morten_opprud 0:66a099b01e08 207 }
morten_opprud 0:66a099b01e08 208
morten_opprud 0:66a099b01e08 209 void ping(void)
morten_opprud 0:66a099b01e08 210 {
morten_opprud 0:66a099b01e08 211 int rxcnt = 0;
morten_opprud 0:66a099b01e08 212 char rx[14];
morten_opprud 0:66a099b01e08 213 short fcs;
morten_opprud 0:66a099b01e08 214
morten_opprud 0:66a099b01e08 215 for(int i=0; i < 12; i++) {
morten_opprud 0:66a099b01e08 216 rs485.putc(pingAllStr[i]);
morten_opprud 0:66a099b01e08 217 }
morten_opprud 0:66a099b01e08 218 while(1) {
morten_opprud 0:66a099b01e08 219 if(rs485.readable()) {
morten_opprud 0:66a099b01e08 220 rx[rxcnt++] = rs485.getc();
morten_opprud 0:66a099b01e08 221 }
morten_opprud 0:66a099b01e08 222 /* reached stop 0x7E ? todo, timeout & CRC*/
morten_opprud 0:66a099b01e08 223 if( rxcnt > 10)
morten_opprud 0:66a099b01e08 224 if(rx[rxcnt] == 0x7E)
morten_opprud 0:66a099b01e08 225 break;
morten_opprud 0:66a099b01e08 226 if( rxcnt == 11)
morten_opprud 0:66a099b01e08 227 break;
morten_opprud 0:66a099b01e08 228 }
morten_opprud 0:66a099b01e08 229 }