Omron FINS protocol realization at PC side using Qt(C++) [ Driver ]

5.7k views Asked by At

I am working for a cross-platform desktop application . I develop it in C++ with usage of Qt and already implemented PC side Omron FINS TCP protocol driver via sockets ( QTcpSocket ). When I read from register via FINS protocol - I receive right response within 30ms ok , but when I write to plc's registers - there is no response from the plc - socket timeout error ( QAbstractSocket error code = 5 ).

Code for reading from register ( function receives reg_addr - address of a register and updates value ): bool fins_read_reg(int reg_addr,int *value); -->


static unsigned char fins_cmnd[MAX_MSG], fins_resp[MAX_MSG],fins_tcp_header[MAX_HEADER];
static unsigned char fins_send_frame[34], fins_receive_frame[32];
static int sendlen, recvlen;
//char sid = 0;
if(sid > 0xFF)
    sid = 0;
if(f!=0)
{

    fprintf(f,"BEGIN TO READ \n");
    fprintf(f," reg_addr = %d \n",reg_addr);
    fprintf(f," value = %d \n",*value);

}
/* SEND FINS/TCP COMMAND*/
/*
* GENERATE FINS COMMAND FRAME
*/
fins_send_frame[0] = 'F'; /* Header */
fins_send_frame[1] = 'I';
fins_send_frame[2] = 'N';
fins_send_frame[3] = 'S';
fins_send_frame[4] = 0x00; /* Length */
fins_send_frame[5] = 0x00;
fins_send_frame[6] = 0x00;
fins_send_frame[7] = 18+8; /*Length of data from Command up to end of FINS frame */  
fins_send_frame[8] = 0x00; /* Command */
fins_send_frame[9] = 0x00;
fins_send_frame[10] = 0x00;
fins_send_frame[11] = 0x02;
fins_send_frame[12] = 0x00; /* Error Code */
fins_send_frame[13] = 0x00;
fins_send_frame[14] = 0x00;
fins_send_frame[15] = 0x00;
//command:
fins_send_frame[16] = 0x80; /* ICF */ //put 0x00 - response required //was 0x80
fins_send_frame[17] = 0x00; /* RSV */
fins_send_frame[18] = 0x03; /* GCT */
fins_send_frame[19] = 0x00; /* DNA */
fins_send_frame[20] = srv_node_no; /* DA1 *//* Ethernet Unit FINS NODE NUMBER*/
fins_send_frame[21] = 0x00; /* DA2 */
fins_send_frame[22] = 0x00; /* SNA */
fins_send_frame[23] = cli_node_no; /* SA1 *//* WS FINS NODE NUMBER OBTAINED
AUTOMATICALLY*/
fins_send_frame[24] = 0x00; /* SA2 */
fins_send_frame[25] = sid; //++sid; /* SID */
fins_send_frame[26] = 0x01; /* MRC */ //1
fins_send_frame[27] = 0x01; /* SRC */ //read
// change to read:
fins_send_frame[28] = memory_area_designation_code(reg_addr); /* VARIABLE TYPE: DM*/
if(f!=0)
{
    fprintf(f,"FINS/TCP memory area designation code =  %d \n",fins_cmnd[28]);
}
if(memory_area_designation_code(reg_addr) == 0xB0) //-0x0c000
{
fins_send_frame[29] = (unsigned char)((reg_addr-0x0C000)>>8);     
fins_send_frame[30] = (unsigned char)((reg_addr-0x0C000)&0xFF); //low register
if(f!=0)
{
 fprintf(f,"fins_send_frame[29] =  %d \n",fins_send_frame[29]);
 fprintf(f,"fins_send_frame[30] = %d \n",fins_send_frame[30]);
}


}
if(memory_area_designation_code(reg_addr) == 0xB1) //-0x0DE00
{
    fins_send_frame[29] = (unsigned char)((reg_addr-0x0DE00)>>8); 
    fins_send_frame[30] = (unsigned char)((reg_addr-0x0DE00)&0xFF);
    if(f!=0)
    {
     fprintf(f,"fins_send_frame[29] =  %d \n",fins_send_frame[29]);

     fprintf(f,"fins_send_frame[30] = %d \n",fins_send_frame[30]);
    }
}
if(memory_area_designation_code(reg_addr) == 0x82) //-0x10000
{
    fins_send_frame[29] = (unsigned char)((reg_addr-0x10000)>>8); 
    fins_send_frame[30] = (unsigned char)((reg_addr-0x10000)&0xFF);
    if(f!=0)
    {
     fprintf(f,"fins_send_frame[29] =  %d \n",fins_send_frame[29]);

     fprintf(f,"fins_send_frame[30] = %d \n",fins_send_frame[30]);
    }
}
if(memory_area_designation_code(reg_addr) == 0xB3) //-0x0BA00
{
    fins_send_frame[29] = (unsigned char)((reg_addr-0x0BA00)>>8);
    fins_send_frame[30] = (unsigned char)((reg_addr-0x0BA00)&0xFF);
    if(f!=0)
    {
     fprintf(f,"fins_send_frame[29] =  %d \n",fins_send_frame[29]);

     fprintf(f,"fins_send_frame[30] = %d \n",fins_send_frame[30]);
    }
}
fins_send_frame[31] = 0x00;//bit number
//number of words to read:
fins_send_frame[32] = 0x00; /* WORDS READ: 1*/
fins_send_frame[33] = 0x01;
/* SEND FINS/TCP COMMAND*/
sendlen = 34;
sc.write((const char*)fins_send_frame,sendlen);
if(sc.waitForBytesWritten(RESP_TIMEOUT))
{

}
else
{
    if(f!=0)
    {
        fprintf(f,"2.error in sending FINS send frame of command %d \n",sc.error());
    }
    return false;
}
 //lets try to get response here
if(sc.waitForReadyRead(RESP_TIMEOUT))
{
    if(f!=0)
    {
        fprintf(f,"2.received  %d \n",recvlen = sc.bytesAvailable());
    }
    sc.read((char*)fins_receive_frame,recvlen);
    //print received header:
    if(f!=0)
    {

    for(int i =0;i<recvlen;i++)
    {

    }
    }
    //check for errors:
    if(((int)fins_receive_frame[28] == 0) && ((int)fins_receive_frame[29] == 0) )
    {
        //command sent ok
        sid++;
        //lets get value:
        *value = (int)((0x0000|fins_receive_frame[30])<<8) + (int) 

         (0x00FF&fins_receive_frame[31]);

        if(f!=0)
        {
             //lets get value:
             fprintf(f,"2.* value = %d \n",value);

        }
            return true;
    }
    else
    {
        //there were errors when sending
        *value = 0;
        if(f!=0)
        {
             //lets get value:
             fprintf(f,"fields 28 and 29 are not null \n");
        }
        return false;
    }
}
else
{
    //can't get response - error:
    //no response:
            if(f!=0)
            {
                fprintf(f,"2.no response  %d \n",sc.error());
            }
            return true;
}




***
Code snippet of writing to register ( function receives reg_addr - address of a register    and value to put to that register ):

bool fins_write_reg(int reg_addr,const int value); -->

static unsigned char fins_cmnd[MAX_MSG], fins_resp[MAX_MSG],fins_tcp_header[MAX_HEADER];
static unsigned char fins_send_frame[36], fins_receive_frame[30];
static unsigned char srv_node_no, cli_node_no;
static int sendlen, recvlen;
// char sid = 0;
if(sid > 0xFF)
    sid = 0;

 if(f!=0)
 {
     fprintf(f,"BEGIN TO WRITE \n");
     fprintf(f," reg_addr = %d \n",reg_addr);
     fprintf(f," value = %d \n",value);
 }
/* SEND FINS/TCP COMMAND*/
/*
* GENERATE FINS COMMAND FRAME
*/
 //fins header body
fins_send_frame[0] = 'F'; /* Header */
fins_send_frame[1] = 'I';
fins_send_frame[2] = 'N';
fins_send_frame[3] = 'S';
fins_send_frame[4] = 0x00; /* Length */
fins_send_frame[5] = 0x00;
fins_send_frame[6] = 0x00;
fins_send_frame[7] = 0x1C; //20+8;   
fins_send_frame[8] = 0x00; /* Command */
fins_send_frame[9] = 0x00;
fins_send_frame[10] = 0x00;
fins_send_frame[11] = 0x02;
fins_send_frame[12] = 0x00; /* Error Code */
fins_send_frame[13] = 0x00;
fins_send_frame[14] = 0x00;
fins_send_frame[15] = 0x00;
//fins command body
fins_send_frame[16] = 0x80; /* ICF */ 
fins_send_frame[17] = 0x00; /* RSV */
fins_send_frame[18] = 0x02; /* GCT */
fins_send_frame[19] = 0x00; /* DNA */
fins_send_frame[20] = srv_node_no; /* DA1 *//* Ethernet Unit FINS NODE NUMBER*/
fins_send_frame[21] = 0x00; /* DA2 */
fins_send_frame[22] = 0x00; /* SNA */
fins_send_frame[23] = cli_node_no; /* SA1 *//* WS FINS NODE NUMBER
AUTOMATICALLY*/
fins_send_frame[24] = 0x00; /* SA2 */
fins_send_frame[25] = sid; /* SID */
fins_send_frame[26] = 0x01; /* MRC */ //1
fins_send_frame[27] = 0x02; /* SRC */ //1 - write
// change to write:
fins_send_frame[28] = memory_area_designation_code(reg_addr); /* VARIABLE TYPE: DM*/
if(f!=0)
{

}
if(memory_area_designation_code(reg_addr) == 0xB0) //-0x0c000
{
fins_send_frame[29] = (unsigned char)((reg_addr - 0x0c000)>>8);     
fins_send_frame[30] = (unsigned char)((reg_addr - 0x0c000)&0xFF);
if(f!=0)
{
 fprintf(f,"fins_send_frame[29] =  %d \n",fins_send_frame[29]);
 fprintf(f,"fins_send_frame[30] = %d \n",fins_send_frame[30]);
}
}
if(memory_area_designation_code(reg_addr) == 0xB1) //-0x0DE00
{
    fins_send_frame[29] = (unsigned char)((reg_addr - 0x0DE00)>>8); 
    fins_send_frame[30] = (unsigned char)((reg_addr - 0x0DE00)&0xFF);
    if(f!=0)
    {
     fprintf(f,"fins_send_frame[29] =  %d \n",fins_send_frame[29]);
     fprintf(f,"fins_send_frame[30] = %d \n",fins_send_frame[30]);
    }
}
if(memory_area_designation_code(reg_addr) == 0x82) //-0x10000
{
    fins_send_frame[29] = (unsigned char)((reg_addr - 0x10000)>>8);
    fins_send_frame[30] = (unsigned char)((reg_addr - 0x10000)&0xFF);
    if(f!=0)
    {
     fprintf(f,"fins_send_frame[29] =  %d \n",fins_send_frame[29]);
     fprintf(f,"fins_send_frame[30] = %d \n",fins_send_frame[30]);
    }
}
if(memory_area_designation_code(reg_addr) == 0xB3) //-0x0BA00
{
    fins_send_frame[29] = (unsigned char)((reg_addr - 0x0BA00)>>8);
    fins_send_frame[30] = (unsigned char)((reg_addr - 0x0BA00)&0xFF);
    if(f!=0)
    {
     fprintf(f,"fins_send_frame[29] =  %d \n",fins_send_frame[29]);
     fprintf(f,"fins_send_frame[30] = %d \n",fins_send_frame[30]);
    }
}
fins_send_frame[31] = 0x00;//bit number
//number of words to read:
fins_send_frame[32] = 0x00; /* number of data words */
fins_send_frame[33] = 0x01;
//putting actual write value:
fins_send_frame[34] = (unsigned char)(value >> 8); //high byte
fins_send_frame[35] = (unsigned char)(value&0xFF); //low byte
//displaying what is written:
if(f!=0)
{
 fprintf(f,"fins_send_frame[34] =  %d \n",fins_send_frame[34]);
 fprintf(f,"fins_send_frame[35] = %d \n",fins_send_frame[35]);
}
sendlen = 36;
/* SEND FINS/TCP COMMAND*/
sc.write((const char*)fins_send_frame,sendlen);
if(sc.waitForBytesWritten(RESP_TIMEOUT))
{
    if(f!=0)
    {

    }
}
else
{
    if(f!=0)
    {
        fprintf(f,"2.error in sending FINS tcp send frame of command %d \n",sc.error());
    }
    return false;
}
//sc.flush();
 //lets try to get response here :
if(sc.waitForReadyRead(RESP_TIMEOUT)) // here it is RESPONSE TIMEOUT ERROR
{
    if(f!=0)
    {
        fprintf(f,"2.received  %d \n",recvlen = sc.bytesAvailable());
    }
    sc.read((char*)fins_receive_frame,recvlen);
    if(f!=0)
    {
    for(int i =0;i<recvlen;i++)
    {
        fprintf(f,"2.received fins_receive_frame[%d] = %d \n",i,fins_receive_frame[i]);
    }
    }
    //basic check - no error
    if(((int)fins_receive_frame[28] == 0) && ((int)fins_receive_frame[29] == 0))
    {
        //command sent ok
        sid++;
        if(f!=0)
        {
           fprintf(f,"receive response does not contain errors");
        }
            return true;
    }
    else
    {
        //there were errors when sending
        if(f!=0)
        {
            fprintf(f,"receive response contains errors");
        }
        return false;
    }
}
else //cannot receive response
{
    if(f!=0)
   {
    fprintf(f,"3.no response  %d \n",sc.error());
   }     
    return true;
}

where f - is some temporary log file pointer sc - QTcpSocket instance that send/receives FINS commands PLC: CP1L-L14DT1-D Ethernet option board : CP1W-CIF41

memory area designation code function:

int FinsOverEthCP::memory_area_designation_code(const int addr)
{
// area codes
if(addr>0x0BFFF&&addr<0x0D800) //B0 , CIO area
    return 0xB0;
if(addr>0x0DDFF&&addr<0xE000) //work area
    return 0xB1; //TODO: clarified code , from memory area designation codes table
if(addr>0xFFFF&&addr<0x18000) //DM area
    return 0x82;
if(addr>0xB9FF&&addr<0xBC00) //A448 - A959
    return 0xB3;
else
    return 0x80; //CIO,LR,HR,AR area
}

When I tested the command using Multiway software - the response is received and value putted to register , but the same with QTcpSocket and the error, why? My question to you: Have you such problem come up when you run your FINS driver? Why no response situation can be while FINS write to register command is formed ok? If yes how to overcome/fix?

1

There are 1 answers

0
Vladimir On

I created and used this library in few industrial project, so it is stable. But lack of documentation. https://bitbucket.org/vladimirek/omronlib