/* XDemo66: Use DMA to access 87K module that plug in the slot of the I-8000 system. Compiler: BC++ 3.1 Compile mode: large Project: user.c v7000.c vModbus.c [after XS8_3002] ..\LIB\8000E.Lib ..\LIB\TCPIPL.Lib ..\LIB\XS8_NNNN.Lib, with NNNN being the lib file's version. When using normal mode to access 87K modules via COM0, data would be lost about 0.07%. To solve this problem, you can use either of following methods: Method 1: check response data length. If length of response is not correct, discard the response. Method 2: use DMA technique. Hardware: 8000E + 87017 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. [03/Mar/2003] by Kevin Modify function: SendCmdToCom0_DMA(char* Cmd, char* Response) [17/Mar/2005] */ #include #include #include "..\lib\module.h" char cDMA_OutBuffer[20];// Don't change this when using DMA mode. char cInBuffer[80]; // Input buffer to store data form COM0 (both DMA mode and normal mode). int iActionMode=1; // Change this to switch DMA mode and normal mode. // 1: Use DMA mode // 2: Use normal mode int iSlot=0; unsigned long lErrorNo=0; unsigned long lStartTime,lTime; int iDataLength; int iFirstTime=1; unsigned long lLoop; int iRet; char cTemp; // For XDemo66 int SendCmdToCom0_DMA(char* Cmd, char* Response) { // Cmd: command sent to the 87K module that plug in slot. // this function will add (CR) to the end // of the command string. // Response: declare the input buffer to store the // the response from the 87K module that plug in slot. int iCmdLength; Com0SetInputBuf(Response,80); sprintf(cDMA_OutBuffer,"%s\r",Cmd); ToComStr_0(cDMA_OutBuffer); return 0; } void UserEnd(void) { Print("Call UserEnd().\r\n"); StopUserTimerFun(); } // For XDemo66 int ReceiveResponseFromCom0_DMA(char* Response, int Timeout) { // Response: input buffer to store the // the response from the 87K module that plug in slot. // the last byte (CR) will be cut. // Timeout: timeout to receive response. Unit is ms. unsigned long lStartTime; int iReveiveDataSize; lStartTime=*TimeTicks; iReveiveDataSize=Com0GetDataSize(); while(Response[iReveiveDataSize-1]!=0x0d) { iReveiveDataSize=Com0GetDataSize(); if((*TimeTicks-lStartTime)>Timeout) return TimeOut; } Response[iReveiveDataSize-1]=0; // chang last byte from 0x0d to 0 return 0; } // For XDemo66 int ReceiveResponseFromCom0_Normal(unsigned char* Response,long lTimeout) { //receives one string that with one terminal character 0x0D. unsigned char cChar; int iIndex=0; unsigned long lStartTime; lStartTime=*TimeTicks; for(;;) { if(IsCom0()) //check COM port { cChar=ReadCom0(); //read data from COM port if(cChar=='\r') //the terminal char is 0x0D { Response[iIndex]=0; return NoError; //return data length } else Response[iIndex++]=cChar; lStartTime=*TimeTicks; } if((*TimeTicks-lStartTime)>=lTimeout) { Response[iIndex]=0; return TimeOut; //receive data timeout } } } 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) { /* // user's initial function // timer initialized for UserCount() // I/O or variables initialized for UserLoopFun() // I/O or variables initialized for User's functions in this file // refer to demo9 & demo11 for example code */ InitLib(); // To use [MiniOS7 for 8000 new], you need call this function // at begin of c program. // XS8_nnnn.Lib has not add this function to it's kernel. // So, you need call that in UserInit. // To know what difference between original MiniOS7 and new MiniOS7, // please refer CD:\Napdos\MiniOS7\8000new\8000-new_eng.txt // 8000-new_big5.txt // 8000-new_gb2312.txt // [26,Oct,2002] by Kevin SetBaudrate(1,115200); DisableCom(1); // Set COM1 to programming mode. printCom1("/***********************/\n\r"); printCom1("/* DMA function test */\n\r"); printCom1("/***********************/\n\r"); printCom1("\n\r"); printCom1("1) DMA mode\n\r"); printCom1("2) Normal mode\n\r\n\r"); printCom1("Please choose mode(1~2):"); // Get Mode while(!IsCom1()) { RefreshWDT(); } cTemp=ReadCom1(); printCom1("%c\n\r",cTemp); iActionMode=cTemp-'0'; // Get slot printCom1("Slot(0~3 or 0~7)="); while(!IsCom1()) { RefreshWDT(); } cTemp=ReadCom1(); printCom1("%c\n\r",cTemp); iSlot=cTemp-'0'; InstallCom0(115200,8,0,0); switch(iActionMode) { case 1: OpenCom0UseDMA(); if(iFirstTime) { ChangeToSlot(iSlot); SendCmdToCom0_DMA("%0000080A00",cInBuffer); ReceiveResponseFromCom0_DMA(cInBuffer,10); if(cInBuffer[0]=='!') printCom1("[DMA] Change to engineer unit ok\n\r"); else printCom1("[DMA] Change to engineer unit error\n\r"); iFirstTime=0; } break; case 2: if(iFirstTime) { ChangeToSlot(iSlot); ToCom0Bufn("%0000080A00\r",12); ReceiveResponseFromCom0_Normal(cInBuffer,50); if(cInBuffer[0]=='!') printCom1("[Normal] Change to engineer unit ok\n\r\n\r"); else printCom1("[Normal] Change to engineer unit error\n\r\n\r"); iFirstTime=0; } break; } lErrorNo=0; lStartTime=*TimeTicks; } void UserLoopFun(void) { /* // VxComm.exe will call this function every scan time // refer to demo11 for scan-time evaluation */ if(IsCom1()) { cTemp=ReadCom1(); if(cTemp=='q' || cTemp=='Q' || cTemp=='r' || cTemp=='R') { if(iActionMode==1) { CloseCom0UseDMA(); RestoreCom0(); } printCom1("\n\r\n\r"); printCom1("1) DMA mode\n\r"); printCom1("2) Normal mode\n\r\n\r"); printCom1("Please choose mode(1~2):"); // Get Mode while(!IsCom1()) { RefreshWDT(); } cTemp=ReadCom1(); printCom1("%c\n\r",cTemp); iActionMode=cTemp-'0'; // Get slot printCom1("Slot(0~3 or 0~7)="); while(!IsCom1()) { RefreshWDT(); } cTemp=ReadCom1(); printCom1("%c\n\r",cTemp); iSlot=cTemp-'0'; lErrorNo=0; lStartTime=*TimeTicks; lLoop=0; } } lLoop++; switch(iActionMode) { case 1: InstallCom0(115200,8,0,0); OpenCom0UseDMA(); lTime=*TimeTicks; SendCmdToCom0_DMA("#00",cInBuffer); iRet=ReceiveResponseFromCom0_DMA(cInBuffer,10); lTime=*TimeTicks-lTime; break; case 2: InstallCom0(115200,8,0,0); lTime=*TimeTicks; ToCom0Bufn("#00\r",4); iRet=ReceiveResponseFromCom0_Normal(cInBuffer,50); lTime=*TimeTicks-lTime; break; } iDataLength=strlen(cInBuffer); if(iDataLength!=57) // response of 87017/87018 is ">+01.000+02.000........", total 1 + 7*8= 57 bytes. { lErrorNo++; if(iRet==TimeOut) printCom1("\n\r[TimeOut] Error %lu,Cost %lu ms, String[%d]:%s\n\r",lErrorNo,lTime,iDataLength,cInBuffer); else printCom1("\n\r[ Short ] Error %lu,Cost %lu ms, String[%d]:%s\n\r",lErrorNo,lTime,iDataLength,cInBuffer); } else { if(lLoop==1) printCom1("Receive %02d bytes:%s\n\r\n\r",iDataLength,cInBuffer); } printCom1("Time= %lu sec, Costs %02ld ms, Loop=%05lu, Error=%02lu : %6.3f percent \r",(*TimeTicks-lStartTime)/1000,lTime,lLoop,lErrorNo,(float)lErrorNo/(float)lLoop*100); } int UserCmd(unsigned char *Cmd,unsigned char *Response) { /* // user's command interpreter // refer to all demo */ if (Cmd[0]) /* Not Null command */ { strcpy(Response,Cmd); /* echo user's command back */ 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 to return a message to the client, just use the socket to send data. use: VcomSendSocket(p->Socket,pdata,datalength); */ 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 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 via the user's defined port(PortUser), 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 } void Port9999Start(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 9999, 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 } void Port502Start(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 502, 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 }