#include <locale.h>
#include <libintl.h>
#define _(x) gettext(x)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __WIN32__
#include <winsock2.h>
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#endif
#include <errno.h>
#include <time.h>
#include "classicladder.h"
#include "global.h"
#include "socket_modbus_master.h"
#include "protocol_modbus_master.h"
#include "serial_common.h"
#ifdef __WIN32__
#define SOCK_FD SOCKET
#define SOCK_INVALID SOCKET_ERROR
HANDLE ThreadHandleClient = NULL;
DWORD ThreadIdClient;
#else
#define SOCK_FD unsigned int
#define SOCK_INVALID -1
pthread_t thread_socket_client;
#endif
#define BUF_SIZE 512
#define NBR_CLIENTS_MAX NBR_MODBUS_MASTER_REQ
int ClientSocketRunning = 0;
int ClientSocketOpened[ NBR_CLIENTS_MAX ]; SOCK_FD ClientSockDescrip[ NBR_CLIENTS_MAX ];
SOCK_FD client_s;
int CptErrors = 0;
int NbrFrames = 0;
void InitSocketModbusMaster( )
{
int Error;
int ScanClientSock;
for( ScanClientSock=0; ScanClientSock<NBR_CLIENTS_MAX; ScanClientSock++ )
{
ClientSocketOpened[ ScanClientSock ] = -1;
ClientSockDescrip[ ScanClientSock ] = SOCK_INVALID;
}
ClientSocketRunning = 1;
#ifdef __WIN32__
ThreadHandleClient = CreateThread( NULL, 16*1024L,
(LPTHREAD_START_ROUTINE)SocketModbusMasterLoop,
NULL,
THREAD_QUERY_INFORMATION,
&ThreadIdClient);
if ( ThreadHandleClient==NULL )
#else
Error = pthread_create( &thread_socket_client, NULL, (void *(*)(void *))SocketModbusMasterLoop, (void *)NULL );
if (Error)
#endif
{
printf(_("ERROR CLASSICLADDER- Failed to create thread I/O modbus master...\n"));
CloseSocketModbusMaster( );
}
else
{
Error = 0;
if ( ModbusSerialPortNameUsed[ 0 ]!='\0' )
{
if ( !SerialOpen( ModbusSerialPortNameUsed, ModbusSerialSpeed ) )
Error = -1;
printf(_("INFO CLASSICLADDER---I/O modbus master Data bits %i Stop bits %i Parity %i\n"),ModbusSerialDataBits,ModbusSerialStopBits,ModbusSerialParity);
}
if ( Error!=-1 )
printf(_("INFO CLASSICLADDER---I/O modbus master (%s) init ok !\n"), ModbusSerialPortNameUsed[ 0 ]!='\0'?_("Serial"):_("Ethernet"));
}
}
char VerifyTcpConnection( char * SlaveAdr )
{
char AlreadyConnected = FALSE;
char FreeOneFound = FALSE;
int ScanClientSock = 0;
do
{
if ( ClientSocketOpened[ ScanClientSock ]!=-1 )
{
if ( strcmp( SlaveAdr, ModbusMasterReq[ ClientSocketOpened[ ScanClientSock ] ].SlaveAdr )==0 )
{
AlreadyConnected = TRUE;
}
}
if ( !AlreadyConnected )
ScanClientSock++;
}
while( !AlreadyConnected && ScanClientSock<NBR_CLIENTS_MAX );
if ( !AlreadyConnected )
{
ScanClientSock = 0;
do
{
if ( ClientSocketOpened[ ScanClientSock ]==-1 )
FreeOneFound = TRUE;
else
ScanClientSock++;
}
while( !FreeOneFound && ScanClientSock<NBR_CLIENTS_MAX );
if ( FreeOneFound )
{
struct sockaddr_in io_module_addr;
if( ModbusDebugLevel>=2 )
printf(_("Init socket for I/O module (%d)...\n"), ScanClientSock);
client_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ( client_s==SOCK_INVALID )
{
printf(_("Failed to open I/O socket master...\n"));
}
else
{
int NumPort = 502; char * PosiSep;
memset(&io_module_addr, 0, sizeof(io_module_addr));
io_module_addr.sin_family = AF_INET;
PosiSep = strchr( SlaveAdr, ':' );
if ( PosiSep==NULL )
{
io_module_addr.sin_addr.s_addr = inet_addr( SlaveAdr );
}
else
{
static char Address[ 50 ];
strcpy( Address, SlaveAdr );
Address[ PosiSep-SlaveAdr ] = '\0';
NumPort = atoi( PosiSep+1 );
io_module_addr.sin_addr.s_addr = inet_addr( Address );
}
io_module_addr.sin_port = htons( NumPort );
if( ModbusDebugLevel>=2 )
printf(_("Connecting I/O module...\n"));
if (connect(client_s, (struct sockaddr *) &io_module_addr, sizeof(io_module_addr)) >= 0)
{
int ScanModbusTableForIpAddr = 0;
int OffsetIpAdrFound = -1;
do
{
if ( strcmp( SlaveAdr, ModbusMasterReq[ ScanModbusTableForIpAddr ].SlaveAdr )==0 )
OffsetIpAdrFound = ScanModbusTableForIpAddr;
else
ScanModbusTableForIpAddr++;
}
while( OffsetIpAdrFound==-1 && ScanModbusTableForIpAddr<NBR_MODBUS_MASTER_REQ );
if ( OffsetIpAdrFound!=-1 )
{
AlreadyConnected = TRUE;
ClientSocketOpened[ ScanClientSock ] = OffsetIpAdrFound;
ClientSockDescrip[ ScanClientSock ] = client_s;
}
else
{
printf(_("Not able to retrieve IP address in modbus table, huhh?!!!\n"));
}
}
else
{
printf(_("Failed to connect to I/O module\n"));
}
}
}
else
{
printf(_("Too much IP connections under run...\n"));
}
}
else
{
client_s = ClientSockDescrip[ ScanClientSock ];
}
return AlreadyConnected;
}
int SendSocketModbusMaster( char * SlaveAdr, int NumPort, char * Frame, int LgtFrame )
{
int Status = -1;
int LgtSend;
if ( VerifyTcpConnection( SlaveAdr ) )
{
if( ModbusDebugLevel>=2 )
printf(_("INFO CLASSICLADDER- Sending frame to I/O module...\n"));
LgtSend = send(client_s, Frame, LgtFrame, 0);
if ( LgtSend==LgtFrame )
Status = 0;
else
printf(_("ERROR CLASSICLADDER- FAILED TO SEND ON SOCKET !!!(LgtSend=%d)\n"),LgtSend);
}
return Status;
}
int WaitRespSocketModbusMaster( char * Buff, int BuffSize, int TimeOutResponseMilliSecs )
{
int ResponseSize = 0;
int recep_descrip;
fd_set myset;
struct timeval tv;
FD_ZERO( &myset);
FD_SET( client_s, &myset );
tv.tv_sec = 0; tv.tv_usec = TimeOutResponseMilliSecs*1000; recep_descrip = select( 16, &myset, NULL, NULL, &tv );
if ( recep_descrip>0 )
{
int bytesRcvd;
if( ModbusDebugLevel>=2 ) {printf(_("INFO CLASSICLADDER- waiting for slave response...\n"));}
if ((bytesRcvd = recv(client_s, Buff, BuffSize, 0)) > 0) {ResponseSize = bytesRcvd;}
}
return ResponseSize;
}
void CloseSocketModbusMaster( void )
{
int ScanClientSock;
ClientSocketRunning = 0;
#ifdef __WIN32__
if ( ThreadHandleClient )
TerminateThread( ThreadHandleClient, 0);
#endif
for( ScanClientSock=0; ScanClientSock<NBR_CLIENTS_MAX; ScanClientSock++ )
{
if ( ClientSocketOpened[ ScanClientSock ]!=-1 )
{
#ifdef __WIN32__
closesocket( ClientSockDescrip[ ScanClientSock ] );
#else
close( ClientSockDescrip[ ScanClientSock ] );
#endif
}
ClientSocketOpened[ ScanClientSock ] = -1;
ClientSockDescrip[ ScanClientSock ] = SOCK_INVALID;
}
if ( ModbusSerialPortNameUsed[ 0 ]!='\0' )
SerialClose( );
printf(_("INFO CLASSICLADDER---I/O modbus master closed!\n"));
}
void SocketModbusMasterLoop( void )
{
char AdrIP[ 30 ];
int SizeQuestionToAsk;
static char QuestionFrame[ 800 ];
int ResponseSize;
static char ResponseFrame[ 800 ];
int SendResultStatus = 0;
#ifdef __XENO__
pthread_set_name_np(pthread_self(), __FUNCTION__);
#endif
while( ClientSocketRunning )
{
if (InfosGene->LadderState!=STATE_RUN)
{
DoPauseMilliSecs( ModbusTimeInterFrame );
}
else
{
SizeQuestionToAsk = ModbusMasterAsk( (unsigned char*)AdrIP, (unsigned char*)QuestionFrame );
if ( SizeQuestionToAsk>0 )
{
if ( ModbusSerialPortNameUsed[ 0 ]=='\0' )
{
SendResultStatus = SendSocketModbusMaster( AdrIP, 502, QuestionFrame, SizeQuestionToAsk );
}
else
{
SerialSetResponseSize( 1+GetModbusResponseLenghtToReceive()+2, ModbusTimeOutReceipt );
SerialSend( QuestionFrame, SizeQuestionToAsk );
}
if ( SendResultStatus==0 )
{
if ( ModbusTimeAfterTransmit>0 )
{
if( ModbusDebugLevel>=3 )
printf(_("INFO CLASSICLADDER- after transmit delay now...%i milliseconds\n"),ModbusTimeAfterTransmit);
DoPauseMilliSecs( ModbusTimeAfterTransmit );
}
if ( ModbusSerialPortNameUsed[ 0 ]=='\0' )
ResponseSize = WaitRespSocketModbusMaster( ResponseFrame, 800, ModbusTimeOutReceipt );
else
ResponseSize = SerialReceive( ResponseFrame, 800, ModbusTimeOutReceipt );
NbrFrames++;
if ( ResponseSize==0 )
printf(_("ERROR CLASSICLADDER- MODBUS NO RESPONSE (Errs=%d/%d) !?\n"), ++CptErrors, NbrFrames);
if ( !TreatModbusMasterResponse( (unsigned char *)ResponseFrame, ResponseSize ) )
{
if ( ModbusSerialPortNameUsed[ 0 ]!='\0' )
SerialFlush( );
}
}
DoPauseMilliSecs( ModbusTimeInterFrame );
}
else
{
DoPauseMilliSecs( 1000 );
}
}
}
#ifndef __WIN32__
pthread_exit(NULL);
#endif
}