diff --git a/Cfg/Template/mb_cfg.h b/Cfg/Template/mb_cfg.h index 4bb2104..0d44341 100644 --- a/Cfg/Template/mb_cfg.h +++ b/Cfg/Template/mb_cfg.h @@ -85,4 +85,6 @@ #define MODBUS_CFG_FC15_EN DEF_ENABLED #define MODBUS_CFG_FC16_EN DEF_ENABLED #define MODBUS_CFG_FC20_EN DEF_DISABLED -#define MODBUS_CFG_FC21_EN DEF_DISABLED \ No newline at end of file +#define MODBUS_CFG_FC21_EN DEF_DISABLED +#define MODBUS_CFG_FC43_EN DEF_DISABLED +#define MODBUS_CFG_FC43_14_EN DEF_DISABLED \ No newline at end of file diff --git a/Source/mb.h b/Source/mb.h index 786fe47..bad222a 100644 --- a/Source/mb.h +++ b/Source/mb.h @@ -423,6 +423,15 @@ void MB_FileWr (CPU_INT16U file_nbr, CPU_INT16U *perr); #endif +#if (MODBUS_CFG_FC43_EN == DEF_ENABLED) +#if (MODBUS_CFG_FC43_14_EN == DEF_ENABLED) +CPU_INT08U MB_DeviceIdRd (CPU_INT08U device_id_code, + CPU_INT08U object_id, + CPU_CHAR const **object_value, + CPU_INT16U *perr); +#endif +#endif + /* ********************************************************************************************************* * BSP FUNCTION PROTOTYPES @@ -688,6 +697,13 @@ CPU_INT16U MBM_FC16_HoldingRegWrNFP (MODBUS_CH *pch, #error "MODBUS_CFG_FC21_EN not #defined " #endif +#ifndef MODBUS_CFG_FC43_EN +#error "MODBUS_CFG_FC43_EN not #defined " +#endif + +#ifndef MODBUS_CFG_FC43_14_EN +#error "MODBUS_CFG_FC43_14_EN not #defined " +#endif /* diff --git a/Source/mb_def.h b/Source/mb_def.h index b04259b..a73ef45 100644 --- a/Source/mb_def.h +++ b/Source/mb_def.h @@ -74,6 +74,7 @@ #define MODBUS_FC16_HOLDING_REG_WR_MULTIPLE 16 /* Holding registers */ #define MODBUS_FC20_FILE_RD 20 /* Read contents of a File/Record */ #define MODBUS_FC21_FILE_WR 21 /* Write data to a File/Record */ +#define MODBUS_FC43_ENC_INTERFACE_TRANSPORT 43 /* Encapsulated Interface Transport */ #define MODBUS_FC08_LOOPBACK_QUERY 0 /* Loopback sub-function codes */ #define MODBUS_FC08_LOOPBACK_CLR_CTR 10 @@ -83,6 +84,8 @@ #define MODBUS_FC08_LOOPBACK_SLAVE_MSG_CTR 14 #define MODBUS_FC08_LOOPBACK_SLAVE_NO_RESP_CTR 15 +#define MODBUS_FC43_MEI_DEVID_RD 14 + #define MODBUS_COIL_OFF_CODE 0x0000 #define MODBUS_COIL_ON_CODE 0xFF00 @@ -94,10 +97,15 @@ #define MODBUS_ERR_NONE 0 -#define MODBUS_ERR_ILLEGAL_FC 1 -#define MODBUS_ERR_ILLEGAL_DATA_ADDR 2 -#define MODBUS_ERR_ILLEGAL_DATA_QTY 3 -#define MODBUS_ERR_ILLEGAL_DATA_VAL 4 +#define MODBUS_ERR_ILLEGAL_FC 0x01 +#define MODBUS_ERR_ILLEGAL_DATA_ADDR 0x02 +#define MODBUS_ERR_ILLEGAL_DATA_VAL 0x03 +#define MODBUS_ERR_SERVER_DEVICE_FAILURE 0x04 +#define MODBUS_ERR_ACKNOWLEDGE 0x05 +#define MODBUS_ERR_SERVER_DEVICE_BUSY 0x06 +#define MODBUS_ERR_MEMORY_PARITY_ERROR 0x08 +#define MODBUS_ERR_GW_PATH_UNAVAILABLE 0x0A +#define MODBUS_ERR_GW_TARGDEV_FAILED_TO_RES 0x0B #define MODBUS_ERR_FC01_01 101 #define MODBUS_ERR_FC01_02 102 @@ -126,6 +134,7 @@ #define MODBUS_ERR_FC15_01 1501 #define MODBUS_ERR_FC15_02 1502 #define MODBUS_ERR_FC15_03 1503 +#define MODBUS_ERR_FC15_04 1504 #define MODBUS_ERR_FC16_01 1601 #define MODBUS_ERR_FC16_02 1602 @@ -145,6 +154,14 @@ #define MODBUS_ERR_FC21_04 2104 #define MODBUS_ERR_FC21_05 2105 +#define MODBUS_ERR_FC43_01 4301 + +#define MODBUS_ERR_FC43_14_01 4311 +#define MODBUS_ERR_FC43_14_02 4312 +#define MODBUS_ERR_FC43_14_03 4313 +#define MODBUS_ERR_FC43_14_04 4314 +#define MODBUS_ERR_FC43_14_05 4315 + #define MODBUS_ERR_TIMED_OUT 3000 #define MODBUS_ERR_NOT_MASTER 3001 #define MODBUS_ERR_INVALID 3002 diff --git a/Source/mbs_core.c b/Source/mbs_core.c index a5f76c1..5027cef 100644 --- a/Source/mbs_core.c +++ b/Source/mbs_core.c @@ -32,6 +32,7 @@ #define MBS_MODULE #include +#include #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) @@ -101,6 +102,10 @@ #define MBS_RX_DIAG_DATA_H (pch->RxFrameData[4]) #define MBS_RX_DIAG_DATA_L (pch->RxFrameData[5]) +#define MBS_RX_MEI_TYPE (pch->RxFrameData[2]) +#define MBS_RX_DEVID_CODE (pch->RxFrameData[3]) +#define MBS_RX_DEVID_OBJECT_ID (pch->RxFrameData[4]) + #define MBS_RX_FRAME (&pch->RxFrame) #define MBS_RX_FRAME_ADDR (pch->RxFrameData[0]) #define MBS_RX_FRAME_FC (pch->RxFrameData[1]) @@ -125,6 +130,10 @@ #define MBS_TX_DIAG_DATA_H (pch->TxFrameData[4]) #define MBS_TX_DIAG_DATA_L (pch->TxFrameData[5]) +#define MBS_TX_DEVID_MEI_TYPE (pch->RxFrameData[2]) +#define MBS_TX_DEVID_CODE (pch->RxFrameData[3]) +#define MBS_TX_DEVID_COMFLEVEL (pch->RxFrameData[4]) + #define MBS_TX_FRAME (&pch->TxFrame) #define MBS_TX_FRAME_ADDR (pch->TxFrameData[0]) @@ -188,6 +197,13 @@ static CPU_BOOLEAN MBS_FC20_FileRd (MODBUS_CH *pch); static CPU_BOOLEAN MBS_FC21_FileWr (MODBUS_CH *pch); #endif +#if (MODBUS_CFG_FC43_EN == DEF_ENABLED) +static CPU_BOOLEAN MBS_FC43_EncInterfaceTransport(MODBUS_CH *pch); +#if (MODBUS_CFG_FC43_14_EN == DEF_ENABLED) +static CPU_BOOLEAN MBS_FC43_14_DeviceIdRd (MODBUS_CH *pch); +#endif +#endif + #if (MODBUS_CFG_ASCII_EN == DEF_ENABLED) static void MBS_ASCII_Task (MODBUS_CH *pch); #endif @@ -359,6 +375,12 @@ CPU_BOOLEAN MBS_FCxx_Handler (MODBUS_CH *pch) break; #endif +#if (MODBUS_CFG_FC43_EN == DEF_ENABLED) + case MODBUS_FC43_ENC_INTERFACE_TRANSPORT: + send_reply = MBS_FC43_EncInterfaceTransport(pch); + break; +#endif + default: /* Function code not implemented, set error response. */ pch->Err = MODBUS_ERR_ILLEGAL_FC; MBS_ErrRespSet(pch, @@ -432,7 +454,7 @@ static CPU_BOOLEAN MBS_FC01_CoilRd (MODBUS_CH *pch) if (nbr_coils == 0 || nbr_coils > 2000) { /* Make sure we don't exceed the allowed limit per request */ pch->Err = MODBUS_ERR_FC01_01; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); /* Tell caller that we need to send a response */ } nbr_bytes = ((nbr_coils - 1) / 8) + 1; /* Find #bytes needed for response. */ @@ -534,7 +556,7 @@ static CPU_BOOLEAN MBS_FC02_DIRd (MODBUS_CH *pch) if (nbr_di == 0 || nbr_di > 2000) { /* Make sure we don't exceed the allowed limit per request */ pch->Err = MODBUS_ERR_FC02_01; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); /* Tell caller that we need to send a response */ } nbr_bytes = ((nbr_di - 1) / 8) + 1; /* Find #bytes needed for response. */ @@ -644,7 +666,7 @@ static CPU_BOOLEAN MBS_FC03_HoldingRegRd (MODBUS_CH *pch) if (nbr_regs == 0 || nbr_regs > 125) { /* Make sure we don't exceed the allowed limit per request */ pch->Err = MODBUS_ERR_FC03_03; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); /* Tell caller that we need to send a response */ } nbr_bytes = (CPU_INT08U)(nbr_regs * sizeof(CPU_INT16U)); /* Find #bytes needed for response. */ @@ -652,7 +674,7 @@ static CPU_BOOLEAN MBS_FC03_HoldingRegRd (MODBUS_CH *pch) if (nbr_regs == 0 || nbr_regs > 62) { /* Make sure we don't exceed the allowed limit per request */ pch->Err = MODBUS_ERR_FC03_04; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); /* Tell caller that we need to send a response */ } nbr_bytes = (CPU_INT08U)(nbr_regs * sizeof(CPU_FP32)); /* Find #bytes needed for response. */ @@ -661,7 +683,7 @@ static CPU_BOOLEAN MBS_FC03_HoldingRegRd (MODBUS_CH *pch) if (nbr_regs == 0 || nbr_regs > 125) { /* Make sure we don't exceed the allowed limit per request */ pch->Err = MODBUS_ERR_FC03_03; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); /* Tell caller that we need to send a response */ } nbr_bytes = (CPU_INT08U)(nbr_regs * sizeof(CPU_INT16U)); /* Find #bytes needed for response. */ @@ -784,7 +806,7 @@ static CPU_BOOLEAN MBS_FC04_InRegRd (MODBUS_CH *pch) if (nbr_regs == 0 || nbr_regs > 125) { /* Make sure we don't exceed the allowed limit per request */ pch->Err = MODBUS_ERR_FC04_03; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); /* Tell caller that we need to send a response */ } nbr_bytes = (CPU_INT08U)(nbr_regs * sizeof(CPU_INT16U)); /* Find #bytes needed for response. */ @@ -792,7 +814,7 @@ static CPU_BOOLEAN MBS_FC04_InRegRd (MODBUS_CH *pch) if (nbr_regs == 0 || nbr_regs > 62) { /* Make sure we don't exceed the allowed limit per request */ pch->Err = MODBUS_ERR_FC04_04; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); /* Tell caller that we need to send a response */ } nbr_bytes = (CPU_INT08U)(nbr_regs * sizeof(CPU_FP32)); /* Find #bytes needed for response. */ @@ -801,7 +823,7 @@ static CPU_BOOLEAN MBS_FC04_InRegRd (MODBUS_CH *pch) if (nbr_regs == 0 || nbr_regs > 125) { /* Make sure we don't exceed the allowed limit per request */ pch->Err = MODBUS_ERR_FC04_03; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); /* Tell caller that we need to send a response */ } nbr_bytes = (CPU_INT08U)(nbr_regs * sizeof(CPU_INT16U)); /* Find #bytes needed for response. */ @@ -1156,7 +1178,7 @@ static CPU_BOOLEAN MBS_FC08_Loopback (MODBUS_CH *pch) default: pch->Err = MODBUS_ERR_FC08_01; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_VAL); + MODBUS_ERR_ILLEGAL_FC); break; } return (DEF_TRUE); /* Tell caller that we need to send a response */ @@ -1268,7 +1290,7 @@ static CPU_BOOLEAN MBS_FC15_CoilWrMultiple (MODBUS_CH *pch) } else { pch->Err = MODBUS_ERR_FC15_03; /* Number of bytes incorrect for number of COILS. */ MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_VAL); + MODBUS_ERR_SERVER_DEVICE_FAILURE); } return (DEF_TRUE); /* Tell caller that we need to send a response */ } @@ -1341,7 +1363,7 @@ static CPU_BOOLEAN MBS_FC16_HoldingRegWrMultiple (MODBUS_CH *pch) if (nbr_regs == 0 || nbr_regs > 125) { /* Make sure we don't exceed the allowed limit per request */ pch->Err = MODBUS_ERR_FC16_04; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); /* Tell caller that we need to send a response */ } data_size = sizeof(CPU_INT16U); @@ -1349,7 +1371,7 @@ static CPU_BOOLEAN MBS_FC16_HoldingRegWrMultiple (MODBUS_CH *pch) if (nbr_regs == 0 || nbr_regs > 62) { /* Make sure we don't exceed the allowed limit per request */ pch->Err = MODBUS_ERR_FC16_05; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); /* Tell caller that we need to send a response */ } data_size = sizeof(CPU_FP32); @@ -1358,7 +1380,7 @@ static CPU_BOOLEAN MBS_FC16_HoldingRegWrMultiple (MODBUS_CH *pch) if (nbr_regs == 0 || nbr_regs > 125) { /* Make sure we don't exceed the allowed limit per request */ pch->Err = MODBUS_ERR_FC16_04; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); /* Tell caller that we need to send a response */ } data_size = sizeof(CPU_INT16U); @@ -1369,7 +1391,7 @@ static CPU_BOOLEAN MBS_FC16_HoldingRegWrMultiple (MODBUS_CH *pch) if ((pch->RxFrameNDataBytes - 5) != nbr_bytes) { /* Compare actual number of bytes to what they say. */ pch->Err = MODBUS_ERR_FC16_01; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); } if ((nbr_bytes / nbr_regs) != (CPU_INT16U)data_size) { @@ -1498,7 +1520,7 @@ static CPU_BOOLEAN MBS_FC20_FileRd (MODBUS_CH *pch) if (cmd_len < 7 || cmd_len > 245) { /* Make sure the byte count Rx'd is within expected range */ pch->Err = MODBUS_ERR_FC20_01; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); /* Tell caller that we need to send a response */ } cmd_type = pch->RxFrameData[3]; /* Get the reference type */ @@ -1640,7 +1662,7 @@ static CPU_BOOLEAN MBS_FC21_FileWr (MODBUS_CH *pch) if (cmd_len < 7 || cmd_len > 245) { /* Make sure the byte count Rx'd is within expected range */ pch->Err = MODBUS_ERR_FC21_01; MBS_ErrRespSet(pch, - MODBUS_ERR_ILLEGAL_DATA_QTY); + MODBUS_ERR_ILLEGAL_DATA_VAL); return (DEF_TRUE); /* Tell caller that we need to send a response */ } cmd_type = pch->RxFrameData[3]; /* Get the reference type */ @@ -1709,6 +1731,196 @@ static CPU_BOOLEAN MBS_FC21_FileWr (MODBUS_CH *pch) #endif #endif +/* +********************************************************************************************************* +* MBS_FC43_EncInterfaceTransport() +* +* Description : The MODBUS Encapsulated Interface Transport is a mechanism for tunneling service requests and +* method invocations, as well as their returns, inside MODBUS PDUs . +* +* Argument(s) : pch Is a pointer to the Modbus channel's data structure. +* +* Return(s) : DEF_TRUE If a response needs to be sent +* DEF_FALSE If not +* +* Caller(s) : MBS_FCxx_Handler(). +* +* Note(s) : (1) The current version of this software only supports ONE MEI: 14. +* +********************************************************************************************************* +*/ + +#if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) +#if (MODBUS_CFG_FC43_EN == DEF_ENABLED) +static CPU_BOOLEAN MBS_FC43_EncInterfaceTransport (MODBUS_CH *pch) +{ + CPU_BOOLEAN send_reply; + + send_reply = DEF_FALSE; + + switch (MBS_RX_MEI_TYPE) { + case MODBUS_FC43_MEI_DEVID_RD: + send_reply = MBS_FC43_14_DeviceIdRd(pch); + break; + default: + pch->Err = MODBUS_ERR_FC43_01; + MBS_ErrRespSet(pch, + MODBUS_ERR_ILLEGAL_FC); + send_reply = DEF_TRUE; + break; + } + return send_reply; +} +#endif +#endif + +/* +********************************************************************************************************* +* MBS_FC43_14_DeviceIdRd() +* +* Description : Read the identification and additional information relative to the +* physical and functional description of a remote device. +* +* Argument(s) : pch Is a pointer to the Modbus channel's data structure. +* +* Return(s) : DEF_TRUE If a response needs to be sent +* DEF_FALSE If not +* +* Caller(s) : MBS_FCxx_Handler(). +* +********************************************************************************************************* +*/ + +#if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) +#if (MODBUS_CFG_FC43_EN == DEF_ENABLED) +#if (MODBUS_CFG_FC43_14_EN == DEF_ENABLED) +static CPU_BOOLEAN MBS_FC43_14_DeviceIdRd (MODBUS_CH *pch) +{ + CPU_INT08U *presp; + CPU_INT16U err; + CPU_INT08U device_id_code; + CPU_INT08U object_id; + CPU_CHAR const *pobject_value; + CPU_INT08U object_length; + CPU_INT08U nbr_objects_counter = 0; + + CPU_INT08U *pmore_follows; + CPU_INT08U *pnext_object_id; + CPU_INT08U *pnbr_objects; + + if (pch->RxFrameNDataBytes != 3) { /* Nbr of data bytes must be 3. */ + return (DEF_FALSE); /* Tell caller that we DON'T need to send a response */ + } + device_id_code = MBS_RX_DEVID_CODE; + object_id = MBS_RX_DEVID_OBJECT_ID; + + if (object_id > 0x06 && object_id < 0x80) { + pch->Err = MODBUS_ERR_FC43_14_01; + MBS_ErrRespSet(pch, + MODBUS_ERR_ILLEGAL_DATA_ADDR); + return (DEF_TRUE); + } + if ((device_id_code == 0 || device_id_code > 4) + || (device_id_code == 1 && object_id > 0x02) + || (device_id_code == 2 && (object_id < 0x03 || object_id > 0x06)) + || (device_id_code == 3 && object_id < 0x80) + ) { + pch->Err = MODBUS_ERR_FC43_14_02; + MBS_ErrRespSet(pch, + MODBUS_ERR_ILLEGAL_DATA_VAL); + return (DEF_TRUE); + } + switch(device_id_code) { + case 1: + nbr_objects_counter = 0x02 - object_id + 1; + break; + case 2: + nbr_objects_counter = 0x06 - object_id + 1; + break; + // case 3: + // nbr_objects_counter = 0xff - object_id + 1; + // break; + case 4: + nbr_objects_counter = 1; + break; + default: + break; + } + pch->TxFrameNDataBytes = 0; /* Number of data bytes */ + presp = &pch->TxFrameData[0]; /* Reset the pointer to the start of the response */ + *presp++ = MBS_RX_FRAME_ADDR; + *presp++ = MBS_RX_FRAME_FC; + + *presp++ = MBS_RX_MEI_TYPE; + *presp++ = device_id_code; + *presp++ = 0x80 + device_id_code; + pmore_follows = presp++; + pnext_object_id = presp++; + pnbr_objects = presp++; + + *pmore_follows = 0; + *pnext_object_id = object_id; + *pnbr_objects = 0; + + pch->TxFrameNDataBytes = 6; + + while (nbr_objects_counter > 0) { + object_length = MB_DeviceIdRd(device_id_code, + *pnext_object_id, + &pobject_value, + &err); + switch (err) { + case MODBUS_ERR_NONE: + break; + case MODBUS_ERR_RANGE: + pch->Err = MODBUS_ERR_FC43_14_03; + MBS_ErrRespSet(pch, + MODBUS_ERR_ILLEGAL_DATA_ADDR); + return (DEF_TRUE); + default: + pch->Err = MODBUS_ERR_FC43_14_04; + MBS_ErrRespSet(pch, + MODBUS_ERR_SERVER_DEVICE_FAILURE); + return (DEF_TRUE); + } + if (object_length == 0) { + break; + } + if (object_length > (252 - 5)) { + pch->Err = MODBUS_ERR_FC43_14_05; + MBS_ErrRespSet(pch, + MODBUS_ERR_SERVER_DEVICE_FAILURE); + return (DEF_TRUE); + } + if (pch->TxFrameNDataBytes + object_length > 252) { + break; + } + /* Copy data to frame */ + *presp++ = *pnext_object_id; + *presp++ = object_length; + pch->TxFrameNDataBytes += 2; + + memcpy(presp, pobject_value, object_length); + presp += object_length; + pch->TxFrameNDataBytes += object_length; + + nbr_objects_counter--; + (*pnbr_objects)++; + (*pnext_object_id)++; + } + if (nbr_objects_counter > 0) { + *pmore_follows = 0xFF; + } else { + *pnext_object_id = 0; + } + pch->Err = MODBUS_ERR_NONE; + //return (DEF_FALSE); + return (DEF_TRUE); /* Tell caller that we need to send a response */ +} +#endif +#endif +#endif + /* ********************************************************************************************************* * MBS_StatInit() @@ -1886,4 +2098,4 @@ static void MBS_RTU_Task (MODBUS_CH *pch) pch->RxBufPtr = &pch->RxBuf[0]; } #endif -#endif \ No newline at end of file +#endif