Mercurial > code > home > repos > homeauto
changeset 394:ff588658de31
starting pn532 rfid reader in nim
Ignore-this: ee51d4acec4b7f88bb7f0e7491da7b8f
author | drewp@bigasterisk.com |
---|---|
date | Tue, 19 Feb 2019 12:08:22 -0800 |
parents | 5fc79536885a |
children | 3852a10a088f |
files | service/rfid_pn532/graphserver.nim service/rfid_pn532/rfid.nim service/rfid_pn532/tags.nim |
diffstat | 3 files changed, 263 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rfid_pn532/graphserver.nim Tue Feb 19 12:08:22 2019 -0800 @@ -0,0 +1,89 @@ +import asynchttpserver, asyncdispatch, asyncnet, strtabs, sequtils, times, os, strutils, strformat + +type + GraphServer* = ref object of RootObj + port*: int + clients: seq[AsyncSocket] + previousUpdateTime: int + httpServer: AsyncHttpServer + serverReady: Future[void] + +proc handleCORS(req: Request) {.async.} = + await req.respond(Http204, "", newHttpHeaders({ + "Access-Control-Allow-Origin": "*", + "Connection": "close"})) + +proc handle404(req: Request) {.async.} = + let headers = newHttpHeaders({"Content-Type": "text/plain", + "Connection": "close"}) + + await req.respond(Http404, "File not found", headers) + req.client.close() + +proc handleSSE(self: GraphServer, req: Request) {.async.} = + let headers = newHttpHeaders({"Content-Type": "text/event-stream", + "Access-Control-Allow-Origin": "*", + "Cache-Control": "no-cache", + "Connection": "keep-alive"}) + + await req.client.send("HTTP/1.1 200 OK\c\L") + await req.sendHeaders(headers) + await req.client.send("\c\L:ok\n\n") + self.clients.add(req.client) + +proc handleConnections(self: GraphServer, req: Request) {.async.} = + let clientCount = self.clients.len + let headers = newHttpHeaders({"Content-Type": "text/plain", + "Access-Control-Allow-Origin": "*", + "Cache-Control": "no-cache", + "Connection": "close"}) + + await req.respond(Http200, $clientCount, headers) + req.client.close() + +proc requestCallback(self: GraphServer, req: Request) {.async.} = + if req.reqMethod == HttpOptions: + asyncCheck handleCORS(req) + else: + case req.url.path + of "/connections": asyncCheck self.handleConnections(req) + of "/sse": asyncCheck self.handleSSE(req) + else: asyncCheck handle404(req) + +proc newGraphServer*(port: int): GraphServer = + new(result) + result.port = port + result.previousUpdateTime = toInt(epochTime() * 1000) + + result.httpServer = newAsyncHttpServer(true) + let self = result + self.serverReady = self.httpServer.serve( + Port(self.port), + proc (req: Request): Future[void] = self.requestCallback(req), + address="0.0.0.0") + asyncCheck self.serverReady + echo "Listening on " & $self.port + + +proc checkClients(self: GraphServer) = + self.clients = self.clients.filterIt(not it.isClosed()) + +proc pingClients(self: GraphServer) {.async.} = + let currentTime = toInt(epochTime() * 1000) + + if currentTime - self.previousUpdateTime < 1000: + return + + for client in self.clients: + if not client.isClosed(): + asyncCheck client.send("data: " & $currentTime & "\n\n") + + self.previousUpdateTime = toInt(epochTime() * 1000) + +proc run*(self: GraphServer) = + while true: + self.checkClients() + asyncCheck self.pingClients() + poll() + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rfid_pn532/rfid.nim Tue Feb 19 12:08:22 2019 -0800 @@ -0,0 +1,41 @@ +# make rfid && make build_image_pi +# docker pull bang6:5000/rfid_pn532_pi && docker run --rm -it --name rfid --net=host --privileged bang6:5000/rfid_pn532_pi + +import nfc-nim/freefare +import strformat +import strutils +import graphserver +import tags + +var nn = newNfcDevice() + +while true: + echo "loop" + + nn.forAllTags proc (tag: NfcTag) = + if tag.tagType() == freefare.MIFARE_CLASSIC_1K: + echo &"found mifare 1k" + else: + echo &" unknown tag type {freefare.freefare_get_tag_friendly_name(tag.tag)}" + return + + echo &" uid {tag.uid()}" + + tag.connect() + try: + echo &" block1: {tag.readBlock(1).escape}" + #tag.writeBlock(1, toBlock("helloworld")) + finally: + tag.disconnect() + + if false: + var data: freefare.MifareClassicBlock + data[0] = cast[cuchar](5) + data[1] = cast[cuchar](6) + data[2] = cast[cuchar](7) + tag.writeBlock(1, data) + +nn.destroy() + +let server = newGraphServer(port = 10012) +server.run()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/rfid_pn532/tags.nim Tue Feb 19 12:08:22 2019 -0800 @@ -0,0 +1,133 @@ +import logging +import sequtils +import strformat +import strutils +import sugar +import times + +import nfc-nim/nfc, nfc-nim/freefare + +var L = newConsoleLogger() +addHandler(L) + +proc check(succeed: bool, msg: string) = + if not succeed: + let e = new(IOError) + e.msg = msg + raise e + +proc check(p: ptr, msg: string) = + check(not isNil(p), msg) + +proc check(ret: int, msg: string) = + check(ret == 0, &"{msg} ({ret})") + +type NfcDevice = ref object of RootObj + context: ptr nfc.context + dev*: ptr nfc.device + +type NfcTag* {.byref.} = object + tag*: FreefareTag + +proc toBlock*(s: string): MifareClassicBlock = + for i in 0..result.high: + if i < s.len: + result[i] = s[i] + else: + result[i] = '\x00' + +proc toString*(b: MifareClassicBlock): string = + cast[array[16,char]](b).join + +proc newNfcDevice*(): NfcDevice = + new result + nfc.init(addr result.context) + + var connstrings: array[10, nfc.connstring] + var n = nfc.list_devices(result.context, + cast[ptr nfc.connstring](addr connstrings), + len(connstrings)) + info(&"{n} connection strings") + for i in 0 ..< n: + info(&" dev {i}: {join(connstrings[i])}") + + info("open dev") + result.dev = nfc.open(result.context, connstrings[0]) + let dev = result.dev + check(device_get_last_error(dev), + &"nfc.open failed on {join(connstrings[0])}") + +type TagArray {.unchecked.} = array[999, ptr FreefareTag] + +proc getTags(dev: ptr nfc.device): ptr FreefareTag = + info("getting tags") + let t0 = epochTime() + var ret: ptr FreefareTag = freefare.freefare_get_tags(dev) + check(ret, "freefare_get_tags returned null") + info(&"found tags in {epochTime() - t0}") + return ret + +# freefare lib wants to free all the tag memory, so process them in a +# callback and don't keep them outside that. +proc forAllTags*(self: var NfcDevice, onTag: (NfcTag) -> void) = + var ret = getTags(self.dev) + var tagList = cast[TagArray](ret) + for tagp in tagList: + if isNil(tagp): + break + if cast[int](tagp) < 10: + # pointer value looks wrong + break + + let tag: FreefareTag = tagp[] + if isNil(tag): + break + onTag(NfcTag(tag: tag)) + freefare.freefare_free_tags(ret) + +proc tagType*(self: NfcTag): freefare.freefare_tag_type = + freefare.freefare_get_tag_type(self.tag) + +proc uid*(self: NfcTag): cstring = + freefare.freefare_get_tag_uid(self.tag) + +proc connect*(self: NfcTag) = + check(freefare.mifare_classic_connect(self.tag), "connect") + +proc disconnect*(self: NfcTag) = + check(freefare.mifare_classic_disconnect(self.tag), "disconnect") + +proc destroy*(self: var NfcDevice) = + nfc.close(self.dev) + nfc.exit(self.context) + +var pubkey: MifareClassicKey = [cast[cuchar](0xff), + cast[cuchar](0xff), + cast[cuchar](0xff), + cast[cuchar](0xff), + cast[cuchar](0xff), + cast[cuchar](0xff)] + +proc readBlock*(self: NfcTag, blockNumber: int): string = + var blockNum = cast[freefare.MifareClassicBlockNumber](blockNumber) + check(freefare.mifare_classic_authenticate( + self.tag, blockNum, pubkey, freefare.MFC_KEY_A), + &"mifare_classic_authenticate() failed") + + var data: freefare.MifareClassicBlock + + check(mifare_classic_read(self.tag, blockNum, addr data), + "classic_read() failed") + return toString(data) + +proc writeBlock*(self: NfcTag, + blockNumber: int, + data: freefare.MifareClassicBlock) = + var blocknum = cast[freefare.MifareClassicBlockNumber](blockNumber) + check(freefare.mifare_classic_authenticate( + self.tag, blocknum, pubkey, freefare.MFC_KEY_A), + &"mifare_classic_authenticate() failed") + + check(mifare_classic_write(self.tag, blocknum, data), + "classic_write() failed") + info(&" wrote block {blocknum}: {data}")