/
AwsomeMeNGL
/
SerialMonitor_582-1_Practicing
Обзор
Документация
Войти
/
AwsomeMeNGL
/
SerialMonitor_582-1_Practicing
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
SerialMonitor2/Protocols/Protocol_Modbus.cs
361 строка
14 KB
ShadowRec
Initial commit
18 фев 2025, 16:51
18 фев 2025, 16:51
9d77dc2
Код
Авторство
О чём код?
using System; namespace ModbusProtocol { public class Modbus { public class Const { public const ushort COIL_ALLOVABLE_VALUE = 0xFF00; } public class FunctionType { public const byte READ = 0; public const byte WRITE = 1; public const byte RD_WR = 2; public const byte DIAG = 3; } public class Function { public const byte READ_COILS = 0x01; public const byte READ_DESCRETE_INPUTS = 0x02; public const byte READ_HOLDING_REGISTER = 0x03; public const byte READ_INPUT_REGISTER = 0x04; public const byte WRITE_SINGLE_COIL = 0x05; public const byte WRITE_SINGLE_REGISTER = 0x06; public const byte WRITE_MULTIPLE_COILS = 0x0F; public const byte WRITE_MULTIPLE_REGISTERS = 0x10; public const byte READ_WRITE_MULTIPLE_REGISTERS = 0x17; public const byte DIAG_READ_EXCEPTION_STATUS = 0x07; public const byte DIAG_DIAGNOSTICS = 0x08; public const byte DIAG_GET_COM_EVENT_COUNTER = 0x0B; public const byte DIAG_GET_COM_EVENT_LOG = 0x0C; public const byte DIAG_GET_SLAVE_ID = 0x11; public const byte DIAG_GET_DEVICE_ID = 0x2B; public const byte EXCEPTION_FLAG = 0x80; } public static string[] FunctionName = { "01h Read Coils", "02h Read Discrete Inputs", "03h Read Holding Registers", "04h Read Input Registers", "05h Write Single Coil", "06h Write Single Register", "0Fh Write Multiple Coils", "10h Write Multiple Registers" }; public static byte[] FunctionCode = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0F, 0x10 }; public static string GetExceptionName(byte exCode) { switch (exCode) { case 0x00: return "NoException"; case 0x01: return "Illegal function"; case 0x02: return "Illegal data address"; case 0x03: return "Illegal data value"; case 0x04: return "Slave device failure"; case 0x05: return "Acknowledge"; case 0x06: return "Slave device busy"; case 0x07: return "Negative acknowledge"; // Removed in the last version case 0x08: return "Memory parity error"; case 0x0A: return "Gateway path is unavailable"; case 0x0B: return "Gateway target device failed to respond"; case 0xE1: return "The value is not alloved"; // In localization only default: return "Unknown exception"; } } // CRC Tables #region private static byte[] aucCRCHi = { 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 }; private static byte[] aucCRCLo = { 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 }; #endregion static ushort CRC16( byte[] frame ) { byte ucCRCHi = 0xFF; byte ucCRCLo = 0xFF; int iIndex; for (int i = 0; i < frame.Length; i++) { iIndex = ucCRCLo ^ (frame[i]); ucCRCLo = (byte)(ucCRCHi ^ aucCRCHi[iIndex]); ucCRCHi = aucCRCLo[iIndex]; } return ( ushort )( ucCRCHi << 8 | ucCRCLo ); } public class Request : ICloneable { public byte DeviceID; public byte Function; public ushort FirstAddr; public ushort QuantityValue; public ushort[] Param = { }; public ushort CRC16; public bool isUrgently; public object Clone() { return this.MemberwiseClone(); } } public static byte[] BildFrame(ref Request req) { byte[] buf = null; int idx = 0; Array.Resize(ref buf, 6); buf[idx++] = req.DeviceID; buf[idx++] = req.Function; buf[idx++] = (byte)(req.FirstAddr >> 8); buf[idx++] = (byte)(req.FirstAddr); buf[idx++] = (byte)(req.QuantityValue >> 8); buf[idx++] = (byte)(req.QuantityValue); if (req.Function == Function.WRITE_MULTIPLE_COILS) { Array.Resize(ref buf, buf.Length + 1); buf[idx++] = (byte)(req.QuantityValue / 8); } if (req.Function == Function.WRITE_MULTIPLE_REGISTERS) { Array.Resize(ref buf, buf.Length + 1); buf[idx++] = (byte)(req.QuantityValue * 2); } if ((req.Function == Function.WRITE_MULTIPLE_COILS) || (req.Function == Function.WRITE_MULTIPLE_REGISTERS)) { Array.Resize(ref buf, buf.Length + req.Param.Length * 2); int paramIdx = 0; while (paramIdx < req.Param.Length) { buf[idx++] = (byte)(req.Param[paramIdx] >> 8); buf[idx++] = (byte)(req.Param[paramIdx]); paramIdx++; } } ushort crc = CRC16(buf); req.CRC16 = crc; Array.Resize(ref buf, buf.Length + 2); buf[idx++] = (byte)(crc); buf[idx++] = (byte)(crc >> 8); return buf; } public class Response { public byte DeviceID; public byte Function; public byte FunctionType; public byte Size; public ushort Address; public byte[] Param; public ushort CRC16; public byte ExceptionCode; public bool Valid; } public static Response ReceiveFrame(byte[] frame) { if (frame.Length < 5) return null; Response req = new Response(); int frameIdx = frame.Length - 1; ushort crc = frame[frameIdx--]; crc <<= 8; crc |= frame[frameIdx]; Array.Resize(ref frame, frameIdx); req.CRC16 = crc; if (crc == CRC16(frame)) { req.Valid = true; frameIdx = 0; req.DeviceID = frame[frameIdx++]; req.Function = frame[frameIdx++]; switch (req.Function) { case Function.READ_COILS: case Function.READ_DESCRETE_INPUTS: case Function.READ_HOLDING_REGISTER: case Function.READ_INPUT_REGISTER: req.FunctionType = FunctionType.READ; break; case Function.WRITE_MULTIPLE_COILS: case Function.WRITE_MULTIPLE_REGISTERS: case Function.WRITE_SINGLE_COIL: case Function.WRITE_SINGLE_REGISTER: req.FunctionType = FunctionType.WRITE; break; case Function.READ_WRITE_MULTIPLE_REGISTERS: req.FunctionType = FunctionType.RD_WR; break; case Function.DIAG_DIAGNOSTICS: case Function.DIAG_GET_COM_EVENT_COUNTER: case Function.DIAG_GET_COM_EVENT_LOG: case Function.DIAG_GET_DEVICE_ID: case Function.DIAG_GET_SLAVE_ID: case Function.DIAG_READ_EXCEPTION_STATUS: req.FunctionType = FunctionType.DIAG; break; } if ((req.Function & Function.EXCEPTION_FLAG) != 0) { req.ExceptionCode = frame[frameIdx++]; } else { req.ExceptionCode = 0; switch (req.FunctionType) { case FunctionType.WRITE: req.Address = frame[frameIdx++]; req.Address <<= 8; req.Address |= frame[frameIdx++]; break; case FunctionType.READ: req.Size = frame[frameIdx++]; break; } Array.Resize(ref req.Param, frame.Length - frameIdx); int idx = 0; while (frameIdx < frame.Length) { req.Param[idx++] = frame[frameIdx++]; } } } else { req.Valid = false; } return req; } public static ushort GetInt16(byte[] buf, ref int idx) { if (idx > buf.Length - 2) return 0; ushort int16; int16 = buf[idx++]; int16 <<= 8; int16 |= buf[idx++]; return int16; } public static uint GetInt32(byte[] buf, ref int idx) { if (idx > buf.Length - 4) return 0; ushort int16; uint int32; int16 = buf[idx++]; int16 <<= 8; int16 |= buf[idx++]; // Get LSB int32 = buf[idx++]; int32 <<= 8; int32 |= buf[idx++]; int32 <<= 16; // Get MSB int32 |= int16; return int32; } public static ulong GetInt64(byte[] buf, ref int idx) { if (idx > buf.Length - 8) return 0; ushort int16; uint int32; ulong int64; int16 = buf[idx++]; int16 <<= 8; int16 |= buf[idx++]; // Get LSB int32 = buf[idx++]; int32 <<= 8; int32 |= buf[idx++]; int32 <<= 16; // Get MSB int32 |= int16; int16 = buf[idx++]; int16 <<= 8; int16 |= buf[idx++]; // Get LSB int64 = buf[idx++]; int64 <<= 8; int64 |= buf[idx++]; int64 <<= 16; // Get MSB int64 |= int16; int64 <<= 32; int64 |= int32; return int64; } } }