/* MT_X107: Modbus/TCP to Modbus/RTU Master/Slave converter 7188EX + X107 Compiler: BC++ 3.1 Compile mode: large Project: user.c v7000.c ..\LIB\7188EL.Lib ..\LIB\TCPIPL.Lib ..\LIB\VCOM_NNNN.Lib, with NNNN being the lib file's version. ..\LIB\MBT7_NNN.Lib, Modbus/TCP library for 7188E, NNN being the lib's version. Communication: Modbus Master <= Modbus/TCP => RJ-45 of 7188EX <==> [Modbus Kernel] <==> COM Ports of 7188EX <==> Modbus/RTU slave device <==> X-board Hardware: 7188EX + X107 Memory mapping iMemory_DI[00]~[05] <====> X107 DI Ch0~Ch5 iMemory_DO[00]~[06] <====> X107 DO Ch0~Ch6 Note: to use MBT7_NNN.Lib, the project is a little different to Xserver demos. You must remove vModbus.c from this project. [22,Apr,2003] by Kevin [13,Mar,2005] by Kevin Update Xserver library from 3.0.9 to 3.2.1 Needs to add two functions: PortUserStart(in user.c), Port9999Start(in V7000.c). [2006,Feb,17] by Kevin Use new I/O memory mapping method. */ #include #include #include "..\lib\7188e.h" #include "..\lib\vxcomm.h" #include "..\Lib\MBTCP.h" // Modbus/TCP Head file for I-7188E #include "..\Lib\Xboard\X107.h" int iScanCOMPort=1; // of Modbus Kernel int iScanXboardProcess=0; int ScanXboard(int iProcess); //The I/O memory mapping unsigned char far iMemory_DI[100]; unsigned char far iMemory_DO[100]; int far iMemory_AI[100]; int far iMemory_AO[100]; 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()) // // refer to demo9 for example code } 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) Port502=newport_502; for calling VcomCmdModbus (vModbus.c) [after vcom3002.lib] 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. */ int iRet; //======= Begin of Modbus Kernel ======= iRet=InitModbus(iMemory_DI,iMemory_DO,iMemory_AI,iMemory_AO); if(iRet==0) { // Initial Modbus configuration success. } else { // Initial Modbus configuration failure. } //======= End of Modbus Kernel======= Port9999=0; //Disable listening TCP port 9999 to speed up 7188E. iRet=X107_Init(); } void UserLoopFun(void) { //======= Begin of Modbus Kernel ======= 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>iTotalCOMPort) iScanCOMPort=1; //======= End of Modbus Kernel ======= iScanXboardProcess=ScanXboard(iScanXboardProcess); // Change this if you don't // plug a X board on expansion bus. } int UserCmd(unsigned char *Cmd,unsigned char *Response) { sprintf(Response,"%s",Cmd); 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 */ } //===========================================================// // Functions about Modbus // //===========================================================// /***************************/ /* [ScanXboard] */ /* for 7188E/7188XB */ /* version 1.0.1 */ /* date: 9,Aug,2002 */ /***************************/ int ScanXboard(int iProcess) { /* iProcess: executes which process? return: executes which process next time? This function scans the X board and stores the results to the memory. Thus, users can use Modbus protocol to read the memory to get the values of the Xboard. You should cut the hole scan process to many small processes. That can reduce execution time of this function and speed up the scan rate. Xboard and user's process share the internal registers. To use the internal registers, you must notice don't overlap the registers. For X107 Memory mapping iMemory_DI[00]~[05] <====> X107 DI Ch0~Ch5 iMemory_DO[00]~[06] <====> X107 DO Ch0~Ch6 */ int i,iNextProcess; float fValue; int iValue; switch(iProcess) { case 0: // Digital input ==> memory iValue=X107_Read_All_DI(); for(i=0;i<6;i++) { if((iValue&0x01)!=0) iMemory_DI[i]=1; else iMemory_DI[i]=0; iValue>>=1; } iNextProcess=1; break; case 1: //Memory ==> digital output iValue=0; for(i=0;i<7;i++) if(iMemory_DO[i]!=0) iValue+=(1<"); //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"); }