// TODO: too many arguments // Build common part of modbus request, decorate it with transport layer specific header, send request and get response PDU back public byte[] SendModbusRequest(byte id, ModbusFunctionCodes functionCode, ushort readAddress, ushort readCount, ushort writeAddress, ushort writeCount, byte[] writeData) { // Build common part of modbus request byte[] requestPdu = BuildRequestPdu(id, functionCode, readAddress, readCount, writeAddress, writeCount, writeData); // Decorate common part of modbus request with transport layer specific header byte[] requestAdu = BuildRequestAdu(requestPdu); // Send modbus request and return response return(Query(requestAdu)); // response PDU }
public static ModbusTCPMessage ParseBytes(IEnumerable <byte> message) { var og = new ModbusTCPMessage(message); ModbusFunctionCodes func = og.PDU.FunctionCode; switch (func) { case ModbusFunctionCodes.ReadHoldingRegisters: return(new ReadRegistersMessage(message)); case ModbusFunctionCodes.PresetMultipleRegisters: return(new WriteHoldingRegistersMessage(message)); default: return(new ModbusTCPMessage(message)); } }
// TODO: Refactor this. Too many lines and arguments; ugly switch statement. Hard to follow. Break out a new class. // Build common part of modbus request private byte[] BuildRequestPdu(byte id, ModbusFunctionCodes functionCode, ushort readAddress, ushort readCount, ushort writeAddress, ushort writeCount, byte[] writeData) { byte[] help; // Used to convert ushort into bytes byte[] requestPdu = null; switch (functionCode) { case ModbusFunctionCodes.ReadCoils: case ModbusFunctionCodes.ReadDiscreteInputs: case ModbusFunctionCodes.ReadHoldingRegisters: case ModbusFunctionCodes.ReadInputRegisters: requestPdu = new byte[6]; // Build request header requestPdu[0] = id; requestPdu[1] = (byte)functionCode; help = BitConverter.GetBytes(readAddress); requestPdu[2] = help[1]; // Start read address -Hi requestPdu[3] = help[0]; // Start read address -Lo help = BitConverter.GetBytes(readCount); requestPdu[4] = help[1]; // Number of coils or register to read -Hi requestPdu[5] = help[0]; // Number of coils or register to read -Lo break; case ModbusFunctionCodes.WriteSingleCoil: requestPdu = new byte[6]; // Build request header requestPdu[0] = id; requestPdu[1] = 0x05; help = BitConverter.GetBytes(writeAddress); requestPdu[2] = help[1]; // Address of coil to force -Hi requestPdu[3] = help[0]; // Address of coil to force -Lo // Copy data requestPdu[4] = writeData[0]; // Output value -Hi ( 0xFF or 0x00 ) requestPdu[5] = 0x00; // Output value -Lo ( const: 0x00 ) break; case ModbusFunctionCodes.WriteSingleRegister: requestPdu = new byte[6]; // Build request header requestPdu[0] = id; requestPdu[1] = 0x06; help = BitConverter.GetBytes(writeAddress); requestPdu[2] = help[1]; // Address of register to force -Hi requestPdu[3] = help[0]; // Address of register to force -Lo requestPdu[4] = writeData[1]; // Output value -Hi requestPdu[5] = writeData[0]; // Output value -Lo break; case ModbusFunctionCodes.GetCommEventCounter: requestPdu = new byte[2]; // Build request header requestPdu[0] = id; requestPdu[1] = 0x0B; break; case ModbusFunctionCodes.WriteMultipleCoils: byte byteCount = (byte)(writeCount / 8); if ((writeCount % 8) > 0) { byteCount += 1; } requestPdu = new byte[7 + byteCount]; // Build request header requestPdu[0] = id; requestPdu[1] = 0x0F; help = BitConverter.GetBytes(writeAddress); requestPdu[2] = help[1]; // Start address of coils to force -Hi requestPdu[3] = help[0]; // Start address of coils to force -Lo help = BitConverter.GetBytes(writeCount); requestPdu[4] = help[1]; // Number of coils to write -Hi requestPdu[5] = help[0]; // Number of coils to write -Lo requestPdu[6] = byteCount; // Copy data for (int i = 0; i < byteCount; ++i) { requestPdu[7 + i] = writeData[i]; } break; case ModbusFunctionCodes.WriteMultipleRegisters: requestPdu = new byte[7 + (writeCount * 2)]; // Build request header requestPdu[0] = id; requestPdu[1] = 0x10; help = BitConverter.GetBytes(writeAddress); requestPdu[2] = help[1]; // Start address of coils to force -Hi requestPdu[3] = help[0]; // Start address of coils to force -Lo help = BitConverter.GetBytes(writeCount); requestPdu[4] = help[1]; // Number of register to write -Hi requestPdu[5] = help[0]; // Number of register to write -Lo requestPdu[6] = (byte)(writeCount * 2); // Number of bytes to write // Copy data for (int i = 0; i < (writeCount * 2); i++) { requestPdu[7 + i] = writeData[i]; } break; case ModbusFunctionCodes.MaskWriteRegister: requestPdu = new byte[8]; // Build request header requestPdu[0] = id; requestPdu[1] = 0x16; help = BitConverter.GetBytes(writeAddress); requestPdu[2] = help[1]; // Address of register to force -Hi requestPdu[3] = help[0]; // Address of register to force -Lo requestPdu[4] = writeData[1]; // And_Mask -Hi requestPdu[5] = writeData[0]; // And_Mask -Lo requestPdu[6] = writeData[3]; // Or_Mask -Hi requestPdu[7] = writeData[2]; // Or_Mask -Lo break; case ModbusFunctionCodes.ReadWriteMultipleRegisters: requestPdu = new byte[11 + (writeCount * 2)]; // Build request header requestPdu[0] = id; requestPdu[1] = 0x17; help = BitConverter.GetBytes(readAddress); requestPdu[2] = help[1]; // Start read address -Hi requestPdu[3] = help[0]; // Start read address -Lo help = BitConverter.GetBytes(readCount); requestPdu[4] = help[1]; // Number of register to read -Hi requestPdu[5] = help[0]; // Number of register to read -Lo help = BitConverter.GetBytes(writeAddress); requestPdu[6] = help[1]; // Start write address -Hi requestPdu[7] = help[0]; // Start write address -Lo help = BitConverter.GetBytes(writeCount); requestPdu[8] = help[1]; // Number of register to write -Hi requestPdu[9] = help[0]; // Number of register to write -Lo requestPdu[10] = (byte)(writeCount * 2); // Number of bytes to write // Copy data for (int i = 0; i < (writeCount * 2); ++i) { requestPdu[11 + i] = writeData[i]; } break; } // switch return(requestPdu); }
public ProtocolDataUnit(ModbusFunctionCodes functionCode, IEnumerable <byte> data) { FunctionCode = functionCode; Data = data; }