📄 mm_rab.lib
字号:
{
// incomplete response
nErr = MM_TIMEOUT;
abort;
}
if(!(pcHex = strchr(acHex, nByte)))
{
// illegal character
nErr = MM_GARBAGE;
abort;
}
*pcRep++ += (pcHex - acHex);
}
if(nByte != '\r')
{
// look for ASCII response's terminal CR
nByte = -1; // protect against immediate time out
waitfor(DelayMs(MM_ERTO) || ((nByte = mmRecv()) != -1));
if(nByte == -1)
{
// incomplete response
nErr = MM_TIMEOUT;
abort;
}
else if(nByte != '\r')
{
// response doesn't fit in buffer
nErr = MM_TOOLONG;
abort;
}
}
// look for ASCII response's terminal LF
nByte = -1; // protect against immediate time out
waitfor(DelayMs(MM_ERTO) || ((nByte = mmRecv()) != -1));
if(nByte == -1)
{
// incomplete response
nErr = MM_TIMEOUT;
}
else if(nByte != '\n')
{
// illegal character
nErr = MM_GARBAGE;
}
else if(mmLRC(acMMRep, pcRep - acMMRep))
{
// bad LRC in ASCII response
nErr = MM_BADXRC;
}
else if(acMMCmd[0] != acMMRep[0])
{
// response is not from queried slave!
nErr = MM_BADID;
}
else if(acMMCmd[1] == acMMRep[1])
{
// normal response to query
nErr = MM_OK;
}
else if(acMMCmd[1] != (acMMRep[1] & 0x7F))
{
// not a response to query
nErr = MM_BADCODE;
}
else
{
// return slave's exception response, except zero (MM_BUSY)
nErr = (acMMRep[2] == 0) ? MM_RESCODE : ((int) acMMRep[2] & 0xFF);
}
}
return nErr;
}
/*=========================================================================*\
Initialize MODBus ASCII Driver
\*=========================================================================*/
/* START FUNCTION DESCRIPTION *****************************************
mmaInit <MM_RAB.LIB>
NOTE: MM_RAB.LIB functions are generally not reentrant.
SYNTAX: void mmaInit()
DESCRIPTION: Responsible for inclusion of Modbus ASCII mmLRC() and
mmExec() functions. The standard 1 second end reply time out may be
overridden by an optional user defined milliseconds value (MM_ERTO,
cast to long). The standard 1 second begin reply (query end to response
begin) time out may also be overridden by an optional user defined
milliseconds value (MM_BRTO, cast to long). This function is normally
called only by the user supplied or library function which initializes
the Modbus Master communication port.
RETURN VALUE: None.
END DESCRIPTION ******************************************************/
nodebug
void mmaInit()
{
}
/***************************************************************************\
MODBus RTU Master Packet Processing
\***************************************************************************/
/*** BeginHeader mmrInit */
void mmrInit(unsigned long);
// additional function prototypes for Modbus RTU
unsigned mmCRC(unsigned char *,unsigned);
int mmExec();
extern long mmrEndTimeOutMS;
/*** EndHeader */
/*=========================================================================*\
Compute Cyclic Redundancy Check
\*=========================================================================*/
const unsigned char acMMRHi[] ={
0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40,
0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41,
0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40,
0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40,
0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40,
0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41,
0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40,
0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40,
0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40,
0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41,
0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41,
0x00,0xC1,0x81,0x40, 0x01,0xC0,0x80,0x41, 0x01,0xC0,0x80,0x41, 0x00,0xC1,0x81,0x40
};
const unsigned char acMMRLo[] ={
0x00,0xC0,0xC1,0x01, 0xC3,0x03,0x02,0xC2, 0xC6,0x06,0x07,0xC7, 0x05,0xC5,0xC4,0x04,
0xCC,0x0C,0x0D,0xCD, 0x0F,0xCF,0xCE,0x0E, 0x0A,0xCA,0xCB,0x0B, 0xC9,0x09,0x08,0xC8,
0xD8,0x18,0x19,0xD9, 0x1B,0xDB,0xDA,0x1A, 0x1E,0xDE,0xDF,0x1F, 0xDD,0x1D,0x1C,0xDC,
0x14,0xD4,0xD5,0x15, 0xD7,0x17,0x16,0xD6, 0xD2,0x12,0x13,0xD3, 0x11,0xD1,0xD0,0x10,
0xF0,0x30,0x31,0xF1, 0x33,0xF3,0xF2,0x32, 0x36,0xF6,0xF7,0x37, 0xF5,0x35,0x34,0xF4,
0x3C,0xFC,0xFD,0x3D, 0xFF,0x3F,0x3E,0xFE, 0xFA,0x3A,0x3B,0xFB, 0x39,0xF9,0xF8,0x38,
0x28,0xE8,0xE9,0x29, 0xEB,0x2B,0x2A,0xEA, 0xEE,0x2E,0x2F,0xEF, 0x2D,0xED,0xEC,0x2C,
0xE4,0x24,0x25,0xE5, 0x27,0xE7,0xE6,0x26, 0x22,0xE2,0xE3,0x23, 0xE1,0x21,0x20,0xE0,
0xA0,0x60,0x61,0xA1, 0x63,0xA3,0xA2,0x62, 0x66,0xA6,0xA7,0x67, 0xA5,0x65,0x64,0xA4,
0x6C,0xAC,0xAD,0x6D, 0xAF,0x6F,0x6E,0xAE, 0xAA,0x6A,0x6B,0xAB, 0x69,0xA9,0xA8,0x68,
0x78,0xB8,0xB9,0x79, 0xBB,0x7B,0x7A,0xBA, 0xBE,0x7E,0x7F,0xBF, 0x7D,0xBD,0xBC,0x7C,
0xB4,0x74,0x75,0xB5, 0x77,0xB7,0xB6,0x76, 0x72,0xB2,0xB3,0x73, 0xB1,0x71,0x70,0xB0,
0x50,0x90,0x91,0x51, 0x93,0x53,0x52,0x92, 0x96,0x56,0x57,0x97, 0x55,0x95,0x94,0x54,
0x9C,0x5C,0x5D,0x9D, 0x5F,0x9F,0x9E,0x5E, 0x5A,0x9A,0x9B,0x5B, 0x99,0x59,0x58,0x98,
0x88,0x48,0x49,0x89, 0x4B,0x8B,0x8A,0x4A, 0x4E,0x8E,0x8F,0x4F, 0x8D,0x4D,0x4C,0x8C,
0x44,0x84,0x85,0x45, 0x87,0x47,0x46,0x86, 0x82,0x42,0x43,0x83, 0x41,0x81,0x80,0x40
};
nodebug
unsigned mmCRC(unsigned char *pcMess, unsigned wLen)
{
auto unsigned char cHi,cLo; // CRC Accumulators (MSB & LSB)
auto unsigned w; // CRC Shift In Index
cHi = cLo = 0xFF; // Init CRC
while(wLen--)
{ // For Each Byte
w = cHi ^ *pcMess++; // Next Table Index
cHi = cLo ^ acMMRHi[w]; // Next CRC
cLo = acMMRLo[w];
}
return ((unsigned) cHi << 8) | cLo; // Return Composite
}
/*=========================================================================*\
Assemble MODBus RTU Packet & Process when Done
\*=========================================================================*/
#ifndef MM_BRTO
#define MM_BRTO 100L // arbitrary default RTU Begin Reply Time Out (mS)
#endif
nodebug
int mmExec()
{
static unsigned char *pcRep;
auto unsigned wCRC;
static unsigned wCnt;
static int nByte;
auto int nErr;
nErr = MM_BUSY;
costate
{
wCRC = mmCRC(acMMCmd, pcMMCmd - acMMCmd); // get RTU CRC
mmCmdWord(wCRC); // add CRC to RTU query
while(mmRecv() != -1); // clean out receive buffer
mmSend(NULL, 0); // clean out transmit buffer
waitfor(mmSend(acMMCmd, pcMMCmd - acMMCmd)); // send Modbus RTU query
// clear out response buffer (extra time for response to begin)
memset(acMMRep, 0, sizeof(acMMRep));
if(acMMCmd[0] == 0x00)
{
// broadcast command, no slave response expected
nErr = MM_OK;
abort;
}
// look for RTU response's initial byte (slave ID)
pcRep = acMMRep;
nByte = -1; // protect against immediate time out
waitfor(DelayMs(MM_BRTO) || ((nByte = mmRecv()) != -1));
if(nByte == -1){
nErr = MM_TIMEOUT;
abort;
}
*pcRep++ = nByte;
// collect RTU response bytes until a time out
for(wCnt = 1; wCnt < sizeof(acMMRep); wCnt++)
{
nByte = -1; // protect against immediate time out
waitfor(DelayMs(mmrEndTimeOutMS) || ((nByte = mmRecv()) != -1));
if(nByte == -1)
{
// end of RTU response
break;
}
*pcRep++ = nByte;
}
// check excessive response length
if(wCnt == sizeof(acMMRep))
{
// look for RTU response's time out
nByte = -1; // protect against immediate time out
waitfor(DelayMs(mmrEndTimeOutMS) || ((nByte = mmRecv()) != -1));
if(nByte != -1)
{
// response doesn't fit in buffer
nErr = MM_TOOLONG;
abort;
}
}
// check minimum response length (ID + Function + loCRC + hiCRC)
if(wCnt < 4)
{
// incomplete response
nErr = MM_TIMEOUT;
}
else if(wCnt -= 2, mmCRC(acMMRep,wCnt) != mmRepWord(wCnt))
{
// bad CRC in RTU response
nErr = MM_BADXRC;
}
else if(acMMCmd[0] != acMMRep[0])
{
// response is not from queried slave!
nErr = MM_BADID;
}
else if(acMMCmd[1] == acMMRep[1])
{
// normal response to query
nErr = MM_OK;
}
else if(acMMCmd[1] != (acMMRep[1] & 0x7F))
{
// not a response to query
nErr = MM_BADCODE;
}
else
{
// return slave's exception response, except zero (MM_BUSY)
nErr = (acMMRep[2] == 0) ? MM_RESCODE : ((int) acMMRep[2] & 0xFF);
}
}
return nErr;
}
/*=========================================================================*\
Initialize MODBus RTU Driver
\*=========================================================================*/
/* START FUNCTION DESCRIPTION *****************************************
mmrInit <MM_RAB.LIB>
NOTE: MM_RAB.LIB functions are generally not reentrant.
SYNTAX: void mmrInit(unsigned long qBaud)
DESCRIPTION: Responsible for inclusion of Modbus RTU mmCRC() and
mmExec() functions. Initializes the end reply time out gap to the
standard 3.5 character-times, unless overridden by an optional user
defined milliseconds value (MM_ERTO, cast to long). The arbitrary 100
milliseconds begin reply (query end to response begin) time out may
also be overridden by an optional user defined milliseconds value
(MM_BRTO, cast to long). This function is normally called only by the
user supplied or library function which initializes the Modbus Master
communication port.
PARAMETER1: baud rate (bits per second).
RETURN VALUE: None.
END DESCRIPTION ******************************************************/
long mmrEndTimeOutMS;
nodebug
void mmrInit(unsigned long qBaud)
{
// check/set user defined vs. default Modbus RTU end time out gap value
// NB: Modbus RTU default end time out gap depends on communication rate.
#ifdef MM_ERTO
mmrEndTimeOutMS = (long) MM_ERTO;
#else
// NB: This formula assumes 11 bits (start1+data8+stop2) per transmitted
// character, then adds 1 mS "round up" time.
//
// (3.5 char/gap) * (11 bits/char) * (1000 mS/sec)
// mS/gap = ----------------------------------------------- + (1 mS/gap)
// (qBaud bits/sec)
mmrEndTimeOutMS = 38500L / qBaud + 1L;
#endif
}
/*** BeginHeader */
#endif
/*** EndHeader */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -