Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
23 changes: 22 additions & 1 deletion modbus/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Result<void>> {
Expand All @@ -444,14 +464,15 @@ 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),
}

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),
Expand Down
10 changes: 7 additions & 3 deletions plc/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
14 changes: 10 additions & 4 deletions synapse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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}`);
}
}
},
];
Expand Down