import std/[asyncdispatch, asyncnet] import std/[strutils, tables] ### modbus general ### var mb_host {.threadvar.}: string var mb_port {.threadvar.}: Port var modbusSocket* {.threadvar.}: AsyncSocket var transaction_id {.threadvar.}: uint16 var transactions {.threadvar.}: Table[uint16, proc(msg: string)] proc mkPacket_mbTcp (mb_packet: string): string = inc(transaction_id) return parseHexStr(toHex(transaction_id) & toHex(0u16) & toHex(uint16(len(mb_packet)))) & mb_packet proc reconnect () {.async.} = echo "verbindung putt, ich fix das mal" await sleepAsync(5000) echo "jetzt" modbusSocket = await asyncnet.dial(mb_host, mb_port) proc readPacket_mbTcp (): Future[(uint16, string)] {.async.} = var res = "" res = await modbusSocket.recv(8) while res == "": await reconnect() res = await modbusSocket.recv(8) let transaction_id = fromHex[uint16](toHex(res[0..1])) let length = fromHex[uint16](toHex(res[4..5])) let function_code = cast[uint8](res[7]) res = await modbusSocket.recv(int(length) - 2) while res == "": await reconnect() res = await modbusSocket.recv(8) if function_code >= 128u8: raise newException(OsError, "mordbus error: " & toHex(res)) return (transaction_id, res) proc processAnswers() {.async.} = while true: try: let (transaction_id, mb_packet) = await readPacket_mbTcp() transactions[transaction_id](mb_packet) except: let e = getCurrentException() echo("error while processing mordbus answer: ", e.msg) proc doRequest[T] (req: string, parse_proc: proc(foo: string): T): Future[T] = var fut = newFuture[T]() let tcp_packet = mkPacket_mbTcp(req) asyncCheck modbusSocket.send(tcp_packet) transactions[transaction_id] = proc(answer: string) = #transactions.del(transaction_id) fut.complete(parse_proc(answer)) return fut proc retry[T] (req: string, parse_proc: proc(foo: string): T): Future[T] {.async.} = var retries = 5 var res: T while retries > 0: try: res = await doRequest(req, parse_proc) return res except: retries = retries - 1 let e = getCurrentException() echo("error while processing mordbus answer: ", e.msg) ### readInputRegisters ### proc mkPacket_readInputRegisters (unit_id: uint8, address: uint16, count: uint16): string = return parseHexStr(toHex(unit_id) & toHex(4u8) & toHex(address) & toHex(count)) proc parsePacket_readInputRegisters (packet: string): seq[uint16] = var res: seq[uint16] = @[] let bytes = cast[uint8](packet[0]) var i = 1 while i < int(bytes): res.add(fromHex[uint16](toHex(packet[i..i+1]))) i += 2 return res proc readInputRegisters* (unit_id: uint8, address: uint16, count: uint16): Future[seq[uint16]] {.async.} = return await retry(mkPacket_readInputRegisters(unit_id, address, count), parsePacket_readInputRegisters) ### readRegisters ### proc mkPacket_readRegisters (unit_id: uint8, address: uint16, count: uint16): string = return parseHexStr(toHex(unit_id) & toHex(3u8) & toHex(address) & toHex(count)) proc parsePacket_readRegisters (packet: string): seq[uint16] = var res: seq[uint16] = @[] let bytes = cast[uint8](packet[0]) var i = 1 while i < int(bytes): res.add(fromHex[uint16](toHex(packet[i..i+1]))) i += 2 return res proc readRegisters* (unit_id: uint8, address: uint16, count: uint16): Future[seq[uint16]] {.async.} = return await retry(mkPacket_readRegisters(unit_id, address, count), parsePacket_readRegisters) ### writeRegister ### proc mkPacket_writeRegister (unit_id: uint8, address: uint16, value: uint16): string = return parseHexStr(toHex(unit_id) & toHex(6u8) & toHex(address) & toHex(value)) proc parsePacket_writeRegister (packet: string): bool = return true proc writeRegister* (unit_id: uint8, address: uint16, value: uint16): Future[bool] {.async.} = return await retry(mkPacket_writeRegister(unit_id, address, value), parsePacket_writeRegister) ### conversion ### proc mbFloatDCBA* (input: seq[uint16]): float32 = let i: uint32 = uint32(input[0]) * 65536u32 + uint32(input[1]) return cast[float32](i) ### main ### proc initModbus* (host: string, port: int) {.async.} = mb_host = host mb_port = Port(port) modbusSocket = await asyncnet.dial(mb_host, mb_port) transaction_id = 0u16 transactions = initTable[uint16, proc(msg: string)]() asyncCheck processAnswers()