Files
sics/site_ansto/hardsup/modbustcp.c
2014-05-16 17:23:44 +10:00

138 lines
4.0 KiB
C

/*---------------------------------------------------------------------------
M O D B U S T C P . C
Paul Barron, January 2008
RTU Modbus functions designed for use with the WEST4100 Temperature Controller.
If another modbus device is required at ANSTO sections of this code will need
to be modified.
MBAP: Modbus Application Protocol Header
PDU: Protocol Data Unit
Modbus TCP Packet Format
| MBAP | PDU |
|Transact Identifier|Protocol Identifier|Length Field|Unit ID|Funct Code|Data|
| 2 Bytes | 2 Bytes | 2 Bytes | 1 Byte| 1 Byte | n |
Paul Barron, January 2008
----------------------------------------------------------------------------*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "obdes.h"
#include "conman.h"
#include "rs232controller.h"
#include "modbustcp.h"
/*-------------------------------------------------------------------------*/
int ModbusTCPException(unsigned char *response);
int MsgGenModbusTCP(unsigned char *ModbusMsg, int ModbusMsgLength, unsigned char *TcpPacket,
int *TcpPacketLength)
{
unsigned char MBAPbyte1 = 1, MBAPbyte2 = 1;
unsigned char lengthByte1, lengthByte2;
int index;
// Check if Device Address is Valid. This is based on RS485 having up to
// 32 devices, since we currently only have one device this won't be a problem.
if ((ModbusMsg[0] > 32) || (ModbusMsg[0] < 1))
{
printf("Error: Modbus Address out of Range: %X\n",ModbusMsg[0]);
return MODBUSTCP_BadDataAddress;
}
// Check if Function code is Valid
if ((ModbusMsg[1] > 16) || (ModbusMsg[1] < 1))
{
printf("Error: Modbus Function Code Invalid: %X\n",ModbusMsg[1]);
return MODBUSTCP_BadFunction;
}
// Calculate Legth Field
// Length should never be greater than 255 but just in case.
if ((ModbusMsgLength)>255){
lengthByte1=ModbusMsgLength/255;
lengthByte2=ModbusMsgLength%255;
}
else{
lengthByte1=0;
lengthByte2=ModbusMsgLength;
}
sprintf((char *)TcpPacket,"%c%c%c%c%c%c",MBAPbyte1,MBAPbyte2,0,0,lengthByte1,lengthByte2);
for(index=0;index<=ModbusMsgLength;index++)sprintf((char *)&TcpPacket[index+6],"%c",ModbusMsg[index]);
*TcpPacketLength=ModbusMsgLength+6;
return 1;
}
/*-------------------------------------------------------------------------*/
int transactModbusTCP(prs232 self, unsigned char *query, int queryLength, unsigned char *response, int responseLength)
{
unsigned char TCPquery[40];
int iRet, index, TCPqueryLength;
// Generate the TCP message
iRet=MsgGenModbusTCP(query,queryLength,TCPquery,&TCPqueryLength);
// Send the message and Read the reply
memset(response,0,responseLength); // puts zeros in reply up until reply length
if ((iRet=transactRS232(self,TCPquery,/*strlen(pCommand)*/12,response,20))<=0)
{
printf("Comms error!\n");
return iRet; // Comms problem
}
// Check that the response transact and protocol identifier are the same
if( (strncmp((char *)TCPquery,(char *)response,3)) == 0)
{
// Check that there is not a modbus error, see page 98 from WEST4100 User manual.
if ( response[7] > 0x80 )
{
iRet=ModbusTCPException(response);
return iRet;
}
else
{
// Return the modbus response minus the TCP Header
for(index=0;index<6;index++)
response[index]=response[index+6];
return 1;
}
return 1; // Success
}
return MODBUSTCP_TCPError;
}
/*-------------------------------------------------------------------------*/
int ModbusTCPException(unsigned char *response)
{
if(response[8] == 0x01){
printf("Exception Code 01h: Illegal Function\n");
return MODBUSTCP_IllegalFunction;
}else if(response[8] == 0x02){
printf("Exception Code 02h: Illegal Data Address\n");
return MODBUSTCP_IllegalDataAddress;
}else if(response[8] == 0x03){
printf("Exception Code 03h: Illegal Data Value\n");
return MODBUSTCP_IllegalDataValue;
}else{
printf("Error code is greater than 81h, 82h or 83h\n");
return MODBUSTCP_UnsupportedError;
}
}
/*-------------------------------------------------------------------------*/