import asyncnet import asyncdispatch import strutils import vars import tables ### modbus general ### var sock {.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" sock = await asyncnet.dial(server.config.modbusAddr, Port(server.config.modbusPort)) proc readPacket_mbTcp(): Future[(uint16, string)] {.async.} = var res = "" res = await sock.recv(8) while res == "": await reconnect() res = await sock.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 sock.recv(int(length) - 2) while res == "": await reconnect() res = await sock.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 sock.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*() {.async.} = sock = await asyncnet.dial(server.config.modbusAddr, Port(server.config.modbusPort)) transaction_id = 0u16 transactions = initTable[uint16, proc(msg: string)]() asyncCheck processAnswers()