diff --git a/deno.json b/deno.json index abdb72e..d9a27b3 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "name": "@joyautomation/tentacle", - "version": "0.0.36", + "version": "0.0.43", "description": "Tentacle is a modern soft PLC", "author": "Joy Automation", "license": "Apache-2.0", diff --git a/modbus/client.ts b/modbus/client.ts index 828616a..07cfeff 100644 --- a/modbus/client.ts +++ b/modbus/client.ts @@ -337,6 +337,25 @@ function readModbusFormatValue( throw new Error(`Unsupported format: ${format}`); } +function writeModbusFormatValue(value: number, format: string, modbus: Modbus): number[] { + const buffer = new ArrayBuffer(4) + const view = new DataView(buffer) + const data: number[] = [] + if (format === `FLOAT`) { + view.setFloat32(0, value) + data.push(view.getUint16(modbus.reverseWords ? 2 : 0, modbus.reverseBits)) + data.push(view.getUint16(modbus.reverseWords ? 0 : 2, modbus.reverseBits)) + } else if (format === `INT32`) { + view.setInt32(0, value) + data.push(view.getUint16(modbus.reverseWords ? 2 : 0, modbus.reverseBits)) + data.push(view.getUint16(modbus.reverseWords ? 0 : 2, modbus.reverseBits)) + } else if (format === `INT16`) { + view.setInt16(0, value) + data.push(view.getUint16(0, modbus.reverseBits)) + } + return data +} + export type ModbusError = { name: string; message: string; @@ -431,6 +450,7 @@ export type ModbusWriteFunctions = { export async function writeModbus( register: number, registerType: "HOLDING_REGISTER" | "COIL", + format: ModbusFormat, modbus: Modbus, value: number | boolean, ): Promise> { @@ -444,6 +464,7 @@ export async function writeModbus( ); } + modbus.client.writeRegisters const functionMap: ModbusWriteFunctions = { HOLDING_REGISTER: modbus.client.writeRegisters.bind(modbus.client), COIL: modbus.client.writeCoils.bind(modbus.client), @@ -451,7 +472,7 @@ export async function writeModbus( const result = await Promise.race([ // @ts-ignore fix this type problem later - functionMap[registerType](register, [value]) + functionMap[registerType](register, writeModbusFormatValue(value, format, modbus)) .then(() => createSuccess(undefined)) .catch((error) => createFail(error)), timeoutPromise(3000), diff --git a/plc/runtime.ts b/plc/runtime.ts index dbbdb30..8972081 100644 --- a/plc/runtime.ts +++ b/plc/runtime.ts @@ -365,15 +365,19 @@ export function startSourceIntervals< const writeResult = await writeModbus( variable.source.register, variable.source.registerType, + variable.source.format, source.client, //@ts-ignore fix type - currentVariable.value + variable.source.onSend + //@ts-expect-error TODO: fix type later + ? variable.source.onSend(currentVariable.value) + : currentVariable.value ); if (isFail(writeResult)) { log.warn( - `Failed to write to modbus ${source.id} - ${variableId}: ${writeResult.error}` + `Failed to write to modbus ${source.id} - ${variableId}: ${JSON.stringify(writeResult.message)}` ); - updateRuntimeError(plc, variableId, writeResult.error); + updateRuntimeError(plc, variableId, writeResult.message || "Unknown error"); } clearRuntimeError(plc, variableId); } diff --git a/synapse.ts b/synapse.ts index 0cd12fa..a87c73a 100644 --- a/synapse.ts +++ b/synapse.ts @@ -22,6 +22,8 @@ import { getModbusStateString } from "./modbus/client.ts"; import type { PlcMqtts } from "./types/mqtt.ts"; import { updateRuntimeValue } from "./plc/runtime.ts"; import type { Buffer } from "node:buffer"; +import { logs } from "./log.ts"; +const log = logs.main; export const variableTypeToSparkplugType = (datatype: string): TypeStr => { switch (datatype) { @@ -195,10 +197,14 @@ export function createPlcMqtt< for (const [variableId, variable] of Object.entries( variables )) { - const value = variable.source.onResponse - ? variable.source.onResponse(message) - : message; - updateRuntimeValue(plc, variableId, value); + try { + const value = variable.source.onResponse + ? variable.source.onResponse(message) + : message; + updateRuntimeValue(plc, variableId, value); + } catch (error) { + log.warn(`Error updating variable ${variableId}: ${error}`); + } } }, ];