From ffe929d8eab7bc9ac8ce716e210ea067d7d9c1c4 Mon Sep 17 00:00:00 2001 From: Tau Date: Thu, 8 Nov 2018 14:19:15 -0500 Subject: [PATCH] jvs/jvs-util.c: Add JVS dispatch helper --- jvs/jvs-util.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++ jvs/jvs-util.h | 21 ++++++++++ jvs/meson.build | 2 + 3 files changed, 132 insertions(+) create mode 100644 jvs/jvs-util.c create mode 100644 jvs/jvs-util.h diff --git a/jvs/jvs-util.c b/jvs/jvs-util.c new file mode 100644 index 0000000..1bbe10e --- /dev/null +++ b/jvs/jvs-util.c @@ -0,0 +1,109 @@ +#include + +#include +#include +#include + +#include "hook/iobuf.h" + +#include "jvs/jvs-frame.h" +#include "jvs/jvs-util.h" + +#include "util/dprintf.h" + +typedef HRESULT (*jvs_dispatch_fn_t)( + void *ctx, + struct const_iobuf *req, + struct iobuf *resp); + +void jvs_crack_request( + const void *bytes, + size_t nbytes, + struct iobuf *resp, + uint8_t jvs_addr, + jvs_dispatch_fn_t dispatch_fn, + void *dispatch_ctx) +{ + uint8_t req_bytes[128]; + uint8_t resp_bytes[128]; + struct iobuf decode; + struct iobuf encode; + struct const_iobuf segments; + HRESULT hr; + + assert(bytes != NULL); + assert(resp != NULL); + assert(jvs_addr != 0x00 && (jvs_addr < 0x20 || jvs_addr == 0xFF)); + assert(dispatch_fn != NULL); + + decode.bytes = req_bytes; + decode.nbytes = sizeof(req_bytes); + decode.pos = 0; + + hr = jvs_frame_decode(&decode, bytes, nbytes); + + if (FAILED(hr)) { + return; + } + +#if 0 + dprintf("Decoded request:\n"); + dump_iobuf(&decode); +#endif + + if (req_bytes[0] != jvs_addr && req_bytes[0] != 0xFF) { + return; + } + + iobuf_flip(&segments, &decode); + segments.pos = 2; + + encode.bytes = resp_bytes; + encode.nbytes = sizeof(resp_bytes); + encode.pos = 3; + + /* +1: Don't try to dispatch the trailing checksum byte */ + + hr = S_OK; /* I guess an empty request packet is technically valid? */ + + while (segments.pos + 1 < segments.nbytes) { + hr = dispatch_fn(dispatch_ctx, &segments, &encode); + + if (FAILED(hr)) { + break; + } + } + + if (FAILED(hr)) { + /* Send an error in the overall status byte */ + encode.pos = 3; + + resp_bytes[0] = 0x00; /* Dest addr (master) */ + resp_bytes[1] = 0x02; /* Payload len: Status byte, checksum byte */ + + if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { + resp_bytes[2] = 0x04; /* Status: "Overflow" */ + } else { + resp_bytes[2] = 0x02; /* Status: Encoutered unsupported command */ + } + } else if (encode.pos == 3) { + /* Probably a reset, don't emit a response frame with empty payload */ + return; + } else { + /* Send success response */ + resp_bytes[0] = 0x00; /* Dest addr (master) */ + resp_bytes[1] = encode.pos - 2 + 1; /* -2 header +1 checksum */ + resp_bytes[2] = 0x01; /* Status: Success */ + } + +#if 0 + dprintf("Encoding response:\n"); + dump_iobuf(&encode); +#endif + + hr = jvs_frame_encode(resp, encode.bytes, encode.pos); + + if (FAILED(hr)) { + dprintf("JVS Node: Response encode error: %x\n", (int) hr); + } +} diff --git a/jvs/jvs-util.h b/jvs/jvs-util.h new file mode 100644 index 0000000..e3fc4e5 --- /dev/null +++ b/jvs/jvs-util.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include +#include + +#include "hook/iobuf.h" + +typedef HRESULT (*jvs_dispatch_fn_t)( + void *ctx, + struct const_iobuf *req, + struct iobuf *resp); + +void jvs_crack_request( + const void *bytes, + size_t nbytes, + struct iobuf *resp, + uint8_t jvs_addr, + jvs_dispatch_fn_t dispatch_fn, + void *dispatch_ctx); diff --git a/jvs/meson.build b/jvs/meson.build index b08aba3..3c90966 100644 --- a/jvs/meson.build +++ b/jvs/meson.build @@ -11,5 +11,7 @@ jvs_lib = static_library( 'jvs-bus.h', 'jvs-frame.c', 'jvs-frame.h', + 'jvs-util.c', + 'jvs-util.h', ], )