/* MTDemo55: Be a Modbus/TCP master to connect to one Modbus/TCP slave device. Compiler: BC++ 3.1 Compile mode: large Project: user.c v7000.c ..\LIB\8000L.Lib ..\LIB\TCPIPL.Lib ..\LIB\XS8_NNNN.Lib, with NNNN being the lib's version. ..\Lib\MBT8_NNN.Lib, Modbus/TCP library with NNN being the lib's version. ..\Lib\8017HL.Lib, Modbus Library doesn't include 8017HL.Lib, this project should include it. ..\Lib\8024L.Lib, Modbus Library doesn't include 8024L.Lib, this project should include it. ..\Lib\8080L.Lib, Modbus Library doesn't include 8080L.Lib, this project should include it. ..\Lib\8090L.Lib, Modbus Library doesn't include 8090L.Lib, this project should include it. Using function ModbusTCP_Init,ModbusTCP_Master2Slave, ModbusTCP_Close I-8000 can controll Modbus/TCP slave devices through the ethernet. Please refer to MBTCP_8E.h for more information. Hardware: 8000E + Modbus/TCP slave device Refer 8000\843x883x\TCP\Doc\[Big5|Eng|Gb2312]\Vxcomm.htm 8000\843x883x\TCP\Xserver\Xserver.htm 8000\843x883x\TCP\Xserver\Function.htm to get more information. Note: to use MBT8_NNN.Lib, the project is a little different. You must remove vModbus.c from this project. [23/Aug/2005] first release by Kevin */ #include #include #include #include "module1.h" #include "MBTCP.h" // Modbus/TCP Head file for I-8000E #include "io_scan.h" //#include "..\Lib\8017H.h" // IOScan Library already include 8017H.h //#include "..\Lib\8024.h" // IOScan Library already include 8024.h //#include "..\Lib\8080.h" // IOScan Library already include 8080.h //#include "..\Lib\8090.h" // IOScan Library already include 8090.h int iModbusTCP_Process[8]={0,0,0,0,0,0,0,0}; int iScanCOMPort=1; // of Modbus Kernel //The I/O memory mapping unsigned char far iMemory_DI[800]; unsigned char far iMemory_DO[800]; int far iMemory_AI[800]; int far iMemory_AO[800]; void UserCount(void) { // user's timer trigger function // // In this function cannot use any function that will use the hardware signal "clock", // Such as: // 1. ClockHigh(),ClockLow(), ClockHighLow(), // 2. Any EEPROM functions. // 3. Any 5DigitLed functions. // 4. Any NVRAM function. // 5. Any RTC function.(GetTime(),SetTime(),GetDate(),SetDate()) } void UserInit(void) { /* In this function, user CAN: 1. initialize user's program. 2. set time interval for calling UserCount(). 3. set initial value of I/O or variables for UserLoopFun(). 4. set initial value of I/O or variables for another functions. 5. change the default TCP PORT 10000/9999/502 to others value. [after vcom3004.lib] Syntax: Port10000=newport_10000; for calling UserCmd (user.c) Port9999=newport_9999; for calling VcomCmd7000 (v7000.c) PortUser=newport_User; for calling VcomCmdUser (user.c) [after vcom3005.lib] Default port value: Port10000=10000; Port9999=9999; Port502=502; PortUser=0; If the port value is 0, Xserver will not listen that port. That means the port will be disable. Please refer to demo9 & demo11 for example code */ //InitLib(); // InitModbus() already includes InitLib();. //======= Begin Modbus Kernel ======= int iRet,i; extern int _CpuSpeed; //40=40M, others=80M for(i=0;i<800;i++) { iMemory_DO[i]=0; iMemory_AO[i]=0; } iRet=InitModbus(iMemory_DI,iMemory_DO,iMemory_AI,iMemory_AO); if(iRet!=0) { // Initial Modbus library error. } else { // Initial Modbus library ok. } Init_IO_Scan(iMemory_DI,iMemory_DO,iMemory_AI,iMemory_AO); //======= End Modbus Kernel ======= if(iTotalCOMPort==4) if(_CpuSpeed==40) EnableMonitorCom4(); ModbusTCP_Init(0,"192.168.255.100",502,1500,8000); } void PortUserStart(int skt) { /* XS8_3200.Lib Version 3.2.00 (20,Apr,2004) or later version supports this function. When a TCP/IP client connects to the 7188E/8000E TCP port 10000, the Xserver calls the function once. You can use function VcomSendSocket to send a message to the client when a connection is established. For example: VcomSendSocket(skt,"Connection is established.",26); //return 26 bytes. skt: socket number assigned to the TCP/IP client. */ skt=skt; //do nothing } int iNet_Status=0,iOffset_Status=0; unsigned long lStart_TimeTick; //To record when the 7188E/8000E do //Ethernet communication. void UserLoopFun(void) { int i,iRet; //======= Begin of Modbus Kernel ======= UpdateIOModule(); if(mtModbusPort[iScanCOMPort].EnableMode==_ModbusRTU_Slave) CheckModbusRTURequest(iScanCOMPort); // Is any request from Modbus/RTU Master ? if(mtModbusPort[iScanCOMPort].EnableMode==_ModbusASCII_Slave) CheckModbusASCIIRequest(iScanCOMPort); // Is any request from Modbus/ASCII Master ? if(mtModbusPort[iScanCOMPort].EnableMode==_ModbusRTU_Gateway) { SendModbusRequest(iScanCOMPort); // Passes request to modbus slave device. CheckResponseTimeout(iScanCOMPort); // If response timeout, sets iModbusAction // to IDLE status. CheckModbusResponse(iScanCOMPort); // Is any response from modbus slave device? SendModbusResponse(iScanCOMPort); // Passes response to Modbus/RTU Master. } iScanCOMPort++; if(iScanCOMPort==2) iScanCOMPort=3; if(iScanCOMPort>iTotalCOMPort) iScanCOMPort=1; if(iOffset_Status==0) iNet_Status=SMMI_Net_CheckIn(); if(iNet_Status==0) iOffset_Status=SMMI_Offset_CheckIn(); //======= End of Modbus Kernel ======= if((*TimeTicks-lStart_TimeTick)>100) //Do ethernet communication every 100 ms. { lStart_TimeTick=*TimeTicks; switch(iModbusTCP_Process[0]) { case 0: iRet=ModbusTCP_Master2Slave(0,1,2,iTotal_DINum,0,5,4000); //Modbus/TCP slave (0) (IP=192.168.255.100) //NetID=1 //Function Code = 2 = Read DI //beginning index of register of I-8000 is iDINum //beginning index of register of Modub/TCP slave device is 0 //I/O channel = 5 //Timeout=4000 ms if(iRet==0) { printCom1("[192.168.255.100] Process[0]==> DI ok\n\r"); printCom1(" "); for(i=0;i<5;i++) { printCom1("DI[%02x]=%d ",iTotal_DINum+i,iMemory_DI[iTotal_DINum+i]); } printCom1("\n\r"); iModbusTCP_Process[0]=1; //Change to process 1. } else { printCom1("[192.168.255.100] Process[0]==> DI error code=%d\n\r",iRet); } break; case 1: iMemory_DO[iTotal_DONum+0]=1; iMemory_DO[iTotal_DONum+1]=0; iMemory_DO[iTotal_DONum+2]=1; iMemory_DO[iTotal_DONum+3]=0; iMemory_DO[iTotal_DONum+4]=1; iRet=ModbusTCP_Master2Slave(0,1,15,iTotal_DONum,0,5,4000); //Modbus/TCP slave (0) (IP=192.168.255.100) //NetID=1 //Function Code = 15 = Write DO //beginning index of register of I-8000 is iDONum, //beginning index of register of Modub/RTU slave device is 0 //I/O channel = 5 //Timeout=4000 ms if(iRet==0) { printCom1("[192.168.255.100] Process[1]==> DO ok\n\r"); iModbusTCP_Process[0]=2; //Change to process 2. } else { printCom1("[192.168.255.100] Process[1]==> DO error code=%d\n\r",iRet); } break; case 2: iRet=ModbusTCP_Master2Slave(0,1,4,iTotal_AINum,0,2,4000); //Modbus/TCP slave (0) (IP=192.168.255.100) //NetID=1 //Function Code = 4 = Read AI //beginning index of register of I-8000 is iAINum //beginning index of register of Modub/TCP slave device is 0 //I/O channel = 2 //Timeout=4000 ms if(iRet==0) { printCom1("[192.168.255.100] Process[2]==> AI ok\n\r"); printCom1(" "); for(i=0;i<2;i++) { printCom1("AI[%02X]=%04X ",iTotal_AINum+i,iMemory_AI[iTotal_AINum+i]); } printCom1("\n\r"); iModbusTCP_Process[0]=3; //Change to process 3. } else { printCom1("[192.168.255.100] Process[2]==> AI error code=%d\n\r",iRet); } break; case 3: iMemory_AO[iTotal_AONum+0]=0x0000; iMemory_AO[iTotal_AONum+1]=0x1111; iMemory_AO[iTotal_AONum+2]=0x2222; iMemory_AO[iTotal_AONum+3]=0x3333; iMemory_AO[iTotal_AONum+4]=0x4444; iRet=ModbusTCP_Master2Slave(0,1,16,iTotal_AONum,0,5,4000); //Modbus/TCP slave (0) (IP=192.168.255.100) //NetID=1 //Function Code = 16 = Write AO //beginning index of register of I-8000 is iAONum, //beginning index of register of Modub/RTU slave device is 0 //I/O channel = 5 //Timeout=4000 ms if(iRet==0) { printCom1("[192.168.255.100] Process[3]==> AO ok\n\r\n\r"); iModbusTCP_Process[0]=0; //Change to process 0. } else { printCom1("[192.168.255.100] Process[3]==> AO error code=%d\n\r",iRet); } break; default: iModbusTCP_Process[0]=0; //Change to process 0. break; } } } int UserCmd(unsigned char *Cmd,unsigned char *Response) { int iRet; //======= Begin Modbus Kernel ======= if(Cmd[0]=='!') { iRet=Configuration(Cmd,Response); if(iRet==0) return 1; /* return ok */ else return 0; /* return ERROR */ } //======= End Modbus ======= else return 1; /* return ok */ } int VcomUserBinaryCmd(TCPREADDATA *p) { /* VXCOMM.EXE 2.6.12(09/04/2001) or later will support this function. TCP PORT 10000, command 23 will call this function. user can get the following message: p->ReadUartChar : the buffer store the command data(include "23") p->Length : the command data length(include the two byte "23") p->Socket : the socket number that receive the command, that is when the user function want return message to the client, just use the socket to send data. use: VcomSendSocket(p->Socket,pdata,datalength); */ VcomSendSocket(p->Socket,"User-defined command(23)",24); // return 24 bytes. return 1; /* any value will be accept */ } int VcomCmdUser(TCPREADDATA *p) { /* VCOM3005 (Feb,22,2002) or later will call this function for PortUser. When packets received by TCP PORT PortUser(user defined) of 7188E/8000E, Xserver will call this function. user can get the following message: p->ReadUartChar : the buffer store the command data. Maximum length of p->ReadUartChar is 32767 bytes. p->Length : the command data length. p->Socket : the socket number that receive the command, that is when the user function wants return message to the client, just use the socket to send data. usage: VcomSendSocket(p->Socket,pdata,datalength); */ /* here just send back the command to the client. */ VcomSendSocket(p->Socket,p->ReadUartChar,p->Length); return 1; /* any value will be accept */ } void UserEnd(void) { //Print("Call UserEnd().\r\n"); StopUserTimerFun(); } void Modbus_Request_Event(char* CommandData,int* CommandLength) { /* Modbus_Request_Event is supported since version 1.6.8 [2007,03,13]. char* CommandData: For Modbus/TCP, it includes 6 leading bytes. (needful) For Modbus/RTU, it includes 6 leading bytes. (needless) int* CommandLength: For Modbus/TCP, it includes 6 leading bytes. For Modbus/RTU, it includes 6 leading bytes. */ /* Example code */ //int i; //printCom1("FC:%2d StartAddress:%3d IOCount:%4d\n\r",iModbusRequest_Fun, iModbusRequest_Addr,iModbusRequest_IOCount); //printCom1("Modbus Request\n\r In==>"); //for(i=0;i<*CommandLength;i++) // //printCom1("[%02X] ",CommandData[i]&0xFF); } void Modbus_Response_Event(char* ResponseData,int* ResponseLength) { /* char* ResponseData: For Modbus/TCP, it includes 6 leading bytes. For Modbus/RTU, it doesn't include 6 leading bytes int* CommandLength: For Modbus/TCP, it includes 6 leading bytes. For Modbus/RTU, it doesn't include 6 leading bytes */ //If you want to change the content of the ResponseData, //you have to do 2 steps for Modbus/TCP or Modbus/RTU. //Step1: Change content (Note:you must know the modbus protocol well) //ResponseData[6]=0x19; //ResponseData[7]=0x75; //ResponseData[8]=0x04; //ResponseData[9]=0x01; //Step2: Update data length //*ResponseLength=10; //int i; //printCom1("\n\r Out==>"); //for(i=0;i<*ResponseLength;i++) // //printCom1("[%02X] ",ResponseData[i]&0xFF); //printCom1("\n\r"); }