/* DEMO4: send/receive command to Xserver File name: user.c Compile mode: large Last time update[yyyy/mm/dd]: [2006/12/20] By: Tim demo item: 1. 加上 UserCount()。[2006/12/20] 2. 如何 DisableCom()/如何使用 COM port。[2006/12/22] 3. 如何加上 tcp server。[2006/12/19] 4. 如何加上 tcp client。[尚未完成] --[版本更新/注意事項]----------------------------------------------------------- 新版 x-server library 採用 XS library 架構。使用上跟原先的 x-server 有些差異。 1. UserInit() 宣告不一樣,加上參數 UserInit(int argc,char *argv[]),預留可以傳 參數進來給 user 程式做設定用。(目前直接傳入命令列參數,但已經被 lib 處理過了, 所以 user 程式還不要用。預計會把 lib處理過的項目拿掉,尚未處理的才傳給 user 程式。) //------------------------------------------------------------------------------ 2.UserLoopFun(void) 跟原先一樣。 //------------------------------------------------------------------------------ 3.使用 UserCount() 時請直接用 InstallUserTimerFunction_ms(UserCount,ms); 來安裝 timer 副程式。 //------------------------------------------------------------------------------ 4.int VcomUserBinaryCmd(TCPREADDATA *p); [port 10000 command 23 處理副程式] 寫法沒變,但要在 UserInit() 加上 pXS_Port10kCmd[23]=VcomUserBinaryCmd; // 設定給 command 23 使用。 //------------------------------------------------------------------------------ 5.UserCmd() [port 10000 command 19 處理副程式] 請改成: int UserCmd19(PTCPREADDATA p) { //接收命令與回應訊息的方式同 VcomUserBinaryCmd。 } 並在 UserInit() 裡頭加上 pXS_Port10kCmd[19]=UserCmd19; // 設定給 command 19 使用。(跟原 x-server 的 command 19 有些不同。) //------------------------------------------------------------------------------ 6.加上使用 COM0 對 87k 模組收送命令的功能。[2006/12/26](以 D/I/O 測試) 對 COM0 來說,是 master mode。 另外由 COM3 接受來自外面的命令,是 slave mode。 COM0 要一直 scan 87K 模組,把 DI/AI 讀回。 COM3 收到的命令如果是要讀 87k 的 DI/AI 就把目前讀回最新的值直接回傳,如果有 D/O 或 A/O 要處理,就要插入一個 D/O 或 A/O 命令。 //------------------------------------------------------------------------------ 7.COM0 使用 DMA 接收87k 回應值。[2007/01/02] 目前使用 OpenCom0UseDMA(); 的方式。 ReadComn_0 由 COM_0.c 裡頭的 MyReadComn_0() 取代。 在送出 87k 命令之前需要先呼叫 Com0SetInputBuf(MyCom.Buf,BUF_SIZE); ResetCom0Cnt(); ** 有關的地方請找註明 "//COM0_DMA" 的地方。 //------------------------------------------------------------------------------ [註] 1.有發現不相容或是缺少什麼變數/副程式請馬上通知 Tim Tsai 修改. 2.xs library 使用方式請看 xs library 的說明。 檔案放在 ftp://ftp.icpdas.com/pub/upload/Tim_XS_093/ 目錄下。 */ /*============================================================================*/ #include #include #include "module1.h" /*----------------------------------------------------------------------------*/ #define USE_MODBUS_TCP 1 #define USE_PORT_9999 1 #define USE_PORT_USER 1 #define USE_USER_TIMER 1 /*----------------------------------------------------------------------------*/ #if USE_MODBUS_TCP >= 1 void DoModbus(int skt ,int mode); TCP_SERVER ModbusTcpServer={ 502, /* port */ -1, /* socket */ 0, /* state */ 0, /* connect */ DoModbus/* CallBackFun */ }; #endif #if USE_PORT_9999 >= 1 void DoPort9999(int skt, int mode); TCP_SERVER Port9999Server={ 9999, /* port */ -1, /* socket */ 0, /* state */ 0, /* connect */ DoPort9999/* CallBackFun */ }; #endif #if USE_PORT_USER >= 1 void DoPortUser(int skt,int mode); TCP_SERVER PortUserServer={ 12345, /* 這裡設定要 listen 的 port */ -1, /* socket */ 0, /* state */ 0, /* connect */ DoPortUser /* CallBackFun */ }; #endif /*----------------------------------------------------------------------------*/ 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 DoCom3SlaveMode(char *cmd); void MyCom3CallBackFun(pCOMPORT pComPort, int mode) { int i; printCom_3("{%d}",mode); switch(mode){ case 0: // 超過 Timeout 時間沒再收到字元 case 1: // 收到 EndChar case 2: // 收到字元個數到達 TriggerLevel case 3: // buffer 已經滿了 //ToComBufn_3(pComPort->Buf,pComPort->Size);//把收到的 data 往回送 pComPort->Buf[pComPort->Size]=0; DoCom3SlaveMode(pComPort->Buf); break; default: printCom_3("{?%d}",mode); // 應該不會出現 break; } pComPort->Size=0; //data 處理完了,要將 size 設成 0。 } /*----------------------------------------------------------------------------*/ void MyCom1CallBackFun(pCOMPORT pComPort, int mode) { int i; printCom_1("{%d}",mode); switch(mode){ case 0: // 超過 Timeout 時間沒再收到字元 case 1: // 收到 EndChar case 2: // 收到字元個數到達 TriggerLevel case 3: // buffer 已經滿了 ToComBufn_1(pComPort->Buf,pComPort->Size);//把收到的 data 往回送 break; default: printCom_1("{?%d}",mode); // 應該不會出現 break; } pComPort->Size=0; //data 處理完了,要將 size 設成 0。 } /*----------------------------------------------------------------------------*/ /* DisableCom(int port) 用來 Disable COM port 對應到 tcp port 功能。 disable 之後,對應的 tcp port server 端已經被移除,所以外面無法連線進來。 com port 端有關的設定應該依需要重新設定。 已經連線到對應的 tcp port 的 socket 會被關掉。也就是已經連線的會被迫斷線。 */ int DisableCom(int Port); /*----------------------------------------------------------------------------*/ /* EnableCom(int port) 用來重新把 COM port 對應到 tcp port 功能。 enable 之後,重新加上對應的 tcp port server 。 com port 端有關的設定會依需要自動設定。 */ int EnableCom(int Port); /*----------------------------------------------------------------------------*/ extern COMPORT MyCom; extern int Com87K; extern long Baud87K; extern int DataBit87K; extern int Parity87K; extern int Stop87K; void Com0_LoopFun(void); int MyReadComn_0(unsigned char *buf,int n); void UserInit(int argc,char *argv[]) { printCom_1("[UserInit,INT8=%p]",IntVect[8]);//測試用 #if USE_MODBUS_TCP >= 1 XS_AddServer(&ModbusTcpServer); #endif #if USE_PORT_9999 >= 1 XS_AddServer(&Port9999Server); #endif #if USE_PORT_USER >= 1 XS_AddServer(&PortUserServer); #endif #if USE_USER_TIMER >= 1 InstallUserTimerFunction_ms(10,UserCount); // every 10 ms will call UserCount() once. #endif /* 如果 user 程式需要使用 com port 時,也就是該 com port 不當 virtual com 使用而另有他用。 也就是原先 X-server 的 DisableCom(Port) 要換成底下的處理方式。 [注意]: 底下 1~4 的 Port: COM1 --> 1,COM2--> 2,... 5 的 port: COM1 --> 0, COM2 --> 1,... 1.呼叫 SetBaudrate_[Port](BaudRate); 設定 baud rate 2.呼叫 SetDataFormat_[Port](DataBit,Parity,StopBit); 設定資料格式 3.設定 COM Port 的 callBack function。 LocalCom[Port].CallbackFun=MyComCallBackFun; 4.設定其他有關的 COM PORT 設定(請參考 XS library 對使用 COMPORT 的說明) LocalCom[Port].TriggerLevel=1; // 只要有 data 就呼叫 call back fun. 處理 5.將 COM port 對應的 tcp server 關掉。 if(VcomServer[port].socket >= 0){ XS_RemoveServer(&VcomServer[port]); XS_CloseSocket(VcomServer[port].socket); VcomServer[port].socket=-1; } 這樣 TCP 就連不上這一個 com port 了。就不會對這個 com port 造成干擾。 底下以 COM3 為範例 */ SetBaudrate_[3](115200); SetDataFormat_[3](8,0,1); LocalCom[3].CallbackFun=MyCom3CallBackFun; LocalCom[3].TriggerLevel=40; LocalCom[3].EndChar='\r'; LocalCom[3].Timeout=1000; DisableCom(3); // Disable COM3 //if(VcomServer[2].socket >= 0){ // 這時候tcp server 尚未啟動,所以 socket 是 -1。 //XS_RemoveServer(&VcomServer[2]); //XS_CloseSocket(VcomServer[2].socket); //VcomServer[2].socket=-1; //} /* 底下以 COM1 為範例 因為 COM1 是 console port,所以有其他設定需要處理。 即使 disable COM1 之後,當 INIT* 接地之後,COM1 還是會變成 console port。 */ // 把 COM1 所要使用的 baud rate,data bit,parity,stop bit 設定好就可以。 ComData[0].baud=115200; ComData[0].databit=8; ComData[0].parity=0; ComData[0].stopbit=1; SetBaudrate_[1](115200); SetDataFormat_[1](8,0,1); LocalCom[1].CallbackFun=MyCom1CallBackFun; LocalCom[1].TriggerLevel=1; DisableCom(1); // Disable COM1 //XS_RemoveServer(&VcomServer[0]); //XS_CloseSocket(VcomServer[0].socket); //VcomServer[0].socket=-1; /* 底下是使用 COM0 有關的設定(有關程式碼在 COM_0.c) */ InstallCom_[Com87K](Baud87K,DataBit87K,Parity87K,Stop87K); OpenCom0UseDMA(); //COM0_DMA MyCom.ReadComn=MyReadComn_0; //COM0_DMA //MyCom.ReadComn=ReadComn_[Com87K]; // 不用 DMA 時使用 //InstallCom_DMA_0(Baud87K,DataBit87K,Parity87K,Stop87K); //COM0 使用 DMA 接收 data(尚未測試ok) //MyCom.ReadComn=ReadComn_DMA_0; //COM0 使用 DMA 接收 data (尚未測試ok) XS_AddComPort(&MyCom); XS_AddSystemLoopFun(Com0_LoopFun); } /*----------------------------------------------------------------------------*/ void UserEnd(void) { XS_RemoveComPort(&MyCom); CloseCom0UseDMA(); //COM0_DMA RestoreCom_[Com87K](); #if USE_USER_TIMER >= 1 //StopUserTimerFun(); #endif } /*----------------------------------------------------------------------------*/ void UserLoopFun(void) { /* // VxComm.exe will call this function in every scan time // refer to demo11 for scan-time evaluation */ } /*----------------------------------------------------------------------------*/ /* typedef struct t_TcpReadData{ int Comport; int Socket; int Length; char* ReadUartChar; }TCPREADDATA, *PTCPREADDATA; */ //int UserCmd(unsigned char *Cmd,unsigned char *Response) int UserCmd19(PTCPREADDATA p) //int UserCmd19(TCPREADDATA *p) // 這一個宣告方式也可以,跟上一行是一樣的。 { char *Cmd; /* // user's command interpreter // refer to all demo */ Cmd=p->ReadUartChar; Cmd[p->Length]=0; if (Cmd[0]){ /* Not Null command */ if(Cmd[0]=='0') { //DisableCom(1); TcpPrint(p->Socket,1,"Disable COM1 OK"); } else if(Cmd[0]=='1') { //EnableCom(1); TcpPrint(p->Socket,1,"Enable COM1 OK"); } else { TcpPrint(p->Socket,1,"Not support command"); } return 1; /* return OK */ } return 0; /* return ERROR */ } 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: XS_WriteSocket(p->Socket,pdata,datalength); */ } #if 0 // 停用。請改用 XS library 處理 tcp server 的方式。跟 Modbus,port9999 寫法一樣。 // 新範例為 DoPortUser() int VcomCmdUser(TCPREADDATA *p) { /* VCOM3005 or later will call this function for PortUser. when socket from TCP PORT PortUser will call this function. user can get the following message: p->ReadUartChar : the buffer store the command data. p->Length : the command data length. 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); */ /* here just send back the command come from PortUser. */ XS_WriteSocket(p->Socket,p->ReadUartChar,p->Length); } #endif #if USE_PORT_9999 >= 1 char DataBuf[1461]; void DoPort9999(int skt, int mode) { int Sendlen,cc,err; if(!mode){ // 剛連線成功會先呼叫這個副程式,傳入 mode=0。 // 在這裡可以決定要不要接受這個連線,不接受的話可以直接呼叫 XS_CloseSocket(skt); // 關掉連線。 // 如果需要輸入 user 帳號/密碼也可以在此送出訊息給對方。 } else { err = cc = readsocket( skt, DataBuf, sizeof(DataBuf)-1); if (err <= 0) { /* error or disconnected by remote side */ XS_CloseSocket(skt); } else { Sendlen=cc; err= XS_WriteSocket(skt,DataBuf,Sendlen); if (err < 0) { /* write error */ //_dPrint( "write error %d,errno=%d\n\r", err ,errno); XS_CloseSocket(skt); } } } } #endif #if USE_MODBUS_TCP >= 1 void DoModbus(int skt ,int mode) { int Sendlen,cc,err; if(!mode){ // 剛連線成功會先呼叫這個副程式,傳入 mode=0。 // 在這裡可以決定要不要接受這個連線,不接受的話可以直接呼叫 XS_CloseSocket(skt); // 關掉連線。 } else { err = cc = readsocket( skt, DataBuf, sizeof(DataBuf)-1); if (err <= 0) { /* error or disconnected by remote side */ XS_CloseSocket(skt); } else { Sendlen=cc; err= XS_WriteSocket(skt,DataBuf,Sendlen); if (err < 0) { /* write error */ //_dPrint( "write error %d,errno=%d\n\r", err ,errno); XS_CloseSocket(skt); } } } } #endif #if USE_PORT_USER >= 1 void DoPortUser(int skt,int mode) {int Sendlen,cc,err; if(!mode){ // 剛連線成功會先呼叫這個副程式,傳入 mode=0。 // 在這裡可以決定要不要接受這個連線,不接受的話可以直接呼叫 XS_CloseSocket(skt); // 關掉連線。 } else { err = cc = readsocket( skt, DataBuf, sizeof(DataBuf)-1); if (err <= 0) { /* error or disconnected by remote side */ XS_CloseSocket(skt); } else { Sendlen=cc; err= XS_WriteSocket(skt,DataBuf,Sendlen); if (err < 0) { /* write error */ //_dPrint( "write error %d,errno=%d\n\r", err ,errno); XS_CloseSocket(skt); } } } } #endif