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

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;
    }
}