[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[microblaze-uclinux] Modbus TCP/IP module



Hi all,
here is our modbus TCP/IP module that we use with uClinux. It was
programmed of course under linux. It offers functions 3(read) and
16(write) for multiple holding registers, so as multiple client
connections. The port used is the standard for modbus, the 502.

Hope this heps somehow. One of my problems programming TCP/IP with
uClinux was a big delays(of about 1 or 2 minutes) when communicating two
uClinux via TCP/IP, does somebody has any idea or work around for this?
I looked already the traffic with tcpdump, and actually, it delays.

Best regards,
Raul


/*
File: modbus_slave.c
Last modify: 26.1.2006
Programmer: Raul Camaras(raul.camaras@xxxxxxxxxxxxxxxx)
Comments:
   Simple modbus slave module. Functions 3 and 16 are implemented:
   read and write holding registers.
*/
#include <stdio.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#include "modbus_slave.h"

int modbus_num_regs=0;
short *modbus_regs_buffer=NULL;
int modbus_sockfd=0, modbus_newsockfd=0;

int init_modbus_protocol(int n_regs, short *r_buff)
{
     int sockfd, portno;
     struct sockaddr_in serv_addr;

     modbus_num_regs = n_regs;
     modbus_regs_buffer = r_buff;

     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) return MODBUS_ERROR; 
     bzero((char *) &serv_addr, sizeof(serv_addr));
     portno = MODBUS_TCP_IP_PORT;
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(portno);
     if (bind(sockfd, (struct sockaddr *) &serv_addr,
              sizeof(serv_addr)) < 0) 
               return MODBUS_ERROR;
     listen(sockfd,5);
     modbus_sockfd = sockfd;
     return MODBUS_OK;
}

int wait_connection(void)
{
     int clilen,newsockfd;
     struct sockaddr_in cli_addr;

     if (modbus_sockfd == 0) return MODBUS_ERROR;
     clilen = sizeof(cli_addr);
     newsockfd = accept(modbus_sockfd, 
                 (struct sockaddr *) &cli_addr, 
                 &clilen);
     if (newsockfd < 0) 
          return MODBUS_ERROR;
     modbus_newsockfd=newsockfd;
     return MODBUS_OK;
}

int check_code(unsigned char *buffer)
{
    if ((buffer[MODBUS_CODE_INDEX] == CODE_READ_MULT_REGISTERS) ||
        (buffer[MODBUS_CODE_INDEX] == CODE_WRITE_MULT_REGISTERS))
          return MODBUS_OK;
    return MODBUS_ERROR;
}

int check_quan(unsigned char *buffer)
{
    int quantity_regs;

    quantity_regs = (buffer[MODBUS_QUAN_HI_INDEX]<<8)+buffer[MODBUS_QUAN_LO_INDEX];
    
    switch (buffer[MODBUS_CODE_INDEX])
    {
       case CODE_READ_MULT_REGISTERS:
           if ((quantity_regs < 1) || (quantity_regs > 0x7d)) return MODBUS_ERROR;
           break; 
       case CODE_WRITE_MULT_REGISTERS:
           if ((quantity_regs < 1) || (quantity_regs > 0x7b)) return MODBUS_ERROR;
           if (buffer[MODBUS_BYTE_CNT_INDEX16] != (quantity_regs*2)) return MODBUS_ERROR;
           break;
    }
    return MODBUS_OK;
}

int check_address(unsigned char *buffer)
{
    int start_addr, quantity_regs;

    start_addr = (buffer[MODBUS_ADDR_HI_INDEX]<<8)+buffer[MODBUS_ADDR_LO_INDEX];
    quantity_regs = (buffer[MODBUS_QUAN_HI_INDEX]<<8)+buffer[MODBUS_QUAN_LO_INDEX];
    if ((start_addr + quantity_regs) > modbus_num_regs) return MODBUS_ERROR;

    return MODBUS_OK;
}

int build_response(unsigned char *buffer)
{
    int i,j,start_addr, quantity_regs,data_reg;
    int n_bytes;
      
    start_addr = (buffer[MODBUS_ADDR_HI_INDEX]<<8)+buffer[MODBUS_ADDR_LO_INDEX];
    quantity_regs = (buffer[MODBUS_QUAN_HI_INDEX]<<8)+buffer[MODBUS_QUAN_LO_INDEX];  
    switch(buffer[MODBUS_CODE_INDEX])
    {
       case CODE_READ_MULT_REGISTERS:
          buffer[MODBUS_BYTE_CNT_INDEX]=3+2*quantity_regs;
          buffer[MODBUS_BYTE_CNT2_INDEX]=2*quantity_regs;
          for (j=0,i=start_addr;j<quantity_regs;i++,j++)
          {              
             buffer[MODBUS_DATA_BASE_INDEX3+(2*j)]=modbus_regs_buffer[i]>>8;
             buffer[MODBUS_DATA_BASE_INDEX3+(2*j)+1]=modbus_regs_buffer[i]&0x00ff;
          }
          n_bytes=(9+2*quantity_regs);
          break;

       case CODE_WRITE_MULT_REGISTERS:
          buffer[MODBUS_BYTE_CNT_INDEX]=6;
          for (j=0,i=start_addr;j<quantity_regs;i++,j++)
          {
            modbus_regs_buffer[i]=(buffer[MODBUS_DATA_BASE_INDEX16+(2*j)]<<8)+buffer[MODBUS_DATA_BASE_INDEX16+(2*j)+1];
          }
          n_bytes=12;  
          break;
    }
    return n_bytes;
}

int send_exception(unsigned char *buffer, unsigned char exc_code)
{
   int n;
   buffer[MODBUS_BYTE_CNT_INDEX]=3;
   buffer[MODBUS_CODE_INDEX]=buffer[MODBUS_CODE_INDEX] | 0x80;
   buffer[MODBUS_EXCEP_CODE_INDEX]=exc_code;
   n=9;
   n=write(modbus_newsockfd,buffer,n);
   if (n < 0) return MODBUS_ERROR;
   return MODBUS_OK;
}

int process_request(void)
{
    int n;
    unsigned char buffer[512];

    bzero(buffer, 512);
    n = read(modbus_newsockfd,buffer,512);
    if (n <= 0) return MODBUS_ERROR;
    if (check_code(buffer) == MODBUS_ERROR)
       return (send_exception(buffer, MODBUS_CODE_EXCEPTION));
    if (check_quan(buffer) == MODBUS_ERROR)
       return (send_exception(buffer, MODBUS_QUAN_EXCEPTION));
    if (check_address(buffer) == MODBUS_ERROR)
       return (send_exception(buffer, MODBUS_ADDR_EXCEPTION));
    n=build_response(buffer);
    n=write(modbus_newsockfd,buffer,n);
    if (n < 0) return MODBUS_ERROR;

    return MODBUS_OK; 
}
/*
File: modbus_slave.h
Last modify: 26.1.2006
Programmer: Raul Camaras(raul.camaras@xxxxxxxxxxxxxxxx).
Comments:
   Simple modbus slave module. Functions 3 and 16 are implemented:
   read and write holding registers.
*/

#ifndef MODBUS_H
#define MODBUS_H

/*
Public definitions.
*/

#define MODBUS_TCP_IP_PORT    (502)
#define MODBUS_OK               (1)
#define MODBUS_ERROR            (0)

/*
Functions return MODBUS_OK when success and MOBDUS_ERROR when error.
*/
int init_modbus_protocol(int n_regs, short *r_buff);
int wait_connection(void);
int process_request(void);

/*
END Public definitions.
*/


#define MODBUS_BYTE_CNT_INDEX     (5)
#define MODBUS_ID_INDEX           (6)
#define MODBUS_CODE_INDEX         (7)
#define MODBUS_ADDR_HI_INDEX      (8)
#define MODBUS_ADDR_LO_INDEX      (9)
#define MODBUS_QUAN_HI_INDEX     (10)
#define MODBUS_QUAN_LO_INDEX     (11)
#define MODBUS_BYTE_CNT2_INDEX    (8)
#define MODBUS_DATA_BASE_INDEX3   (9)
#define MODBUS_DATA_BASE_INDEX16 (13)
#define MODBUS_BYTE_CNT_INDEX16  (12)

#define MODBUS_EXCEP_CODE_INDEX   (8)
#define MODBUS_CODE_EXCEPTION     (1)
#define MODBUS_QUAN_EXCEPTION     (3)
#define MODBUS_ADDR_EXCEPTION     (2)

#define CODE_READ_MULT_REGISTERS   0x03
#define CODE_WRITE_MULT_REGISTERS  0x10

#endif
/*
File: slave.c
Last modify: 26.1.2006
Programmer: Raul Camaras(raul.camaras@xxxxxxxxxxxxxxxx)
Comments:
   Simple modbus slave using modbus slave module.
*/

#include <stdio.h>
#include <unistd.h>

#include "modbus_slave.h"

short my_regs[200];

int main()
{
 int i;

 init_modbus_protocol(200,my_regs);
 
 for(i=0;i<200;i++) my_regs[i]=i;

 do{ 
    printf("Waiting connection...");
    wait_connection();
    printf("OK.\n");
    if (fork() == 0)
    {    
       while (process_request() != MODBUS_ERROR);
       exit(0);
    }
 } while(1);
 return 0;
}