# NVT Joints inspection This document describes the communication between the KZV SW and the New Vision Technologies device for detecting joints and combs ## Protocol version history Since protocol version `2`, the response to `GetVersion` contains a `protocolVersion` field, which uniquely defines a version of the communication protocol. If the version implemented by the KZV is different than a version implemented by NVT, KZV SW will report an error and refuse to communicate. The following protocol versions have been defined so far: ### 1. Initial version Used for the first test-drive on 2022/11 ### 2. Protocol version, SelfTest - Added the `protocolVersion` field to the `GetVersion` response - Added the `SelfTest` command and state ## Communication overview The communication protocol is a simple stateless request-response protocol carried over TCP. The two communicating parties are - The KZV SW - The New Vision Technologies device (further referred to as NVT) The NVT will act as a TCP server, spawning the server as soon as it is ready for measurement. The KZV SW will connect to it as a client. NVT should support having multiple TCP clients connected at the same time (event from different IPs). Since the protocol is stateless, this should be easy to implement. Communication is strictly request-response, that is, the client (KZV SW) sends a request/command message, and the server (NVT) responds with a single response message. If the KZV SW doesn't receive a response in 1 second, it will timeout, this is considered to be a failure on the NVT side. Messages exchanged between the two parties are JSON-encoded. Each message must be formatted on single line. The message delimiter is the newline character (LF, single `0x0A` byte). Thus, each party will read bytes until it reaches a single `0x0A` byte in order to read a whole single message. For clarity, messages in this document may be formatted on multiple lines, but they must be transmitted on a single line only during actual communication. ## Messages overview KZV messages are conceptually either commands ([StartMeasurement](#startmeasurement), [StopMeasurement](#stopmeasurement)), or requests ([GetState](#getstate), [GetMeasuredData](#getmeasureddata), ...). Commands initiate an action on the NVT side, they are responded to with [CommandResponse](#commandresponse). Requests are used to retrieve information from NVT, each request message has a single corresponding response message. Each message has a `messageType` field uniquely identifying the message. NVT may also respond to any command or request with either [BadRequest](#badrequest) - the KZV message is unknown or badly formatted, or an [Error](#error) - NVT was unable to fulfill the command/request because of runtime error. **All values (openings, overlaps, distances, start KM etc.) are transmitted in basic SI values, that is, meters.** Timestamps (build date) are encoded using the RFC 3339 format. ## Generic messages ### BadRequest This message can be returned by the NVT as a response to **any** KZV message. It denotes that the NVT was unable to understand the KZV message - unknown message, invalid parameters etc. The `error` field should contain precise description of the problem. **Example** ```json { "messageType": "BadRequest", "error": "Request has unknown format (details)/Unknown request/..." } ``` ### Error This message can be returned by the NVT as a response to **any** KZV message. It denotes that the NVT was unable to perform the action requested by KZV. This will usually indicate HW problems, but can be used to any other fitting purposes. **Example** ```json { "messageType": "Error", "error": "Error communicating with the camera" } ``` ### CommandResponse This message is a response to KZV commands (like [StartMeasurement](#startmeasurement), [StopMeasurement](#stopmeasurement)). If the command was successfully executed, `"success": true` is returned and the `error` field may be absent. If the command failed, `"success": false` is returned and the `error` field must be present and contain an explanation of why the command failed. An example of failure may be the KZV issuing a [StartMeasurement](#startmeasurement) command while the NVT is already measuring. ```json { "messageType": "CommandResponse", "success": false, "error": "Optional error message (this field may not be present if Ok) in case of a failure" } ``` ## GetVersion KZV sends this request to obtain information about the NVT SW version ### Request ```json { "messageType": "GetVersion" } ``` ### Response - `product` is up to NVT - `version` should be in the [SemVer](https://semver.org/) format - `buildDate` should be in the RFC 3339 format - `protocolVersion`: The protocol version reported by NVT must match the protocol version implemented by the KZV SW, otherwise the KZV SW will refuse further communication. ```json { "messageType": "Version", "product": "NVT CombDetector", "version": "1.2.3", "buildDate": "2022-03-05T08:40:51.620Z", "protocolVersion": 2 } ``` ## GetState ### Request KZV uses this to obtain info about the NVT state. It repeatedly (several times a second) queries the NVT state using this message. ```json { "messageType": "GetState" } ``` ### Response NVT reports the state of the measurement and the state of vision detection apparatus. ```json { "messageType": "State", "state": "NotReady|Ready|Measuring|SelfTest", "visionOk": true } ``` ## GetMessages NVT may want to report additional information to the KZV. KZV repeatedly (several times a second) queries the NVT messages using `GetMessages` to be informed about anything interesting NVT may want to report to KZV. Each NVT message has assigned a unique, zero-based index incremented by one. The `skip` field in the request indicates how many messages should be skipped in the response. This is so that old messages are not needlessly being sent all the time. NVT may choose to remember only a limited number of messages, e. g. only the last 1000 messages. Each message has assigned a severity (one of `Debug`, `Info`, `Warn`, `Error`), and a timestamp in the RFC 3339 format. ### Request ```json { "messageType": "GetMessages", "skip": 10 } ``` ### Response ```json { "messageType": "Messages", "messages": [ { "severity": "Debug", "index": 11, "timestamp": "2022-03-05T08:40:51.620Z", "message": "Some debug message" }, { "severity": "Info", "index": 12, "timestamp": "2022-03-05T08:40:51.620Z", "message": "Some info message" }, { "severity": "Warn", "index": 13, "timestamp": "2022-03-05T08:40:51.620Z", "message": "Some warning message" }, { "severity": "Error", "index": 14, "timestamp": "2022-03-05T08:40:51.620Z", "message": "Some error message" } ] } ``` ## SelfTest This command instructs the NVT device to start a self-test. Self-test is used to determine whether the device is ready for successful measurement - there's no mud, moist, etc. It may be necessary that the operator puts a special gray surface under the cameras before starting the self-test. ### Request Start the self-test procedure. ```json { "messageType": "SelfTest" } ``` ### Response [CommandResponse](#commandresponse). `Ok` if self-test procedure was started successfully, `Failure` if there was a problem (HW problem, measurement in progress, ...) On `OK` the NVT goes to the `SelfTest` state and starts self-testing (this may take seconds or more). If the self-test finishes successfully, NVT goes to the `Ready` state. If there is any problem, it goes to the `NotReady` state and reports any errors using the `GetMessages` response. The errors should be as user-friendly and instructive as possible and should also include instructions for the operator on how to fix the problems. ## StartMeasurement ### Request This command instructs the NVT to a start new measurement. `startKm` is given in meters. ```json { "messageType": "StartMeasurement", "startKm": 123.4, "kmDirection": "Up|Down" } ``` ### Response [CommandResponse](#commandresponse). `Ok` if measurement was started successfully, `Failure` if there was a problem (HW problem, measurement already running, ...) ## GetMeasuredData This request is used to obtain measured data. KZV will issue this request repeatedly (several times per second) during measurement. If the measurement is not running, NVT should return `MeasuredData` with `Joint/Comb Left/Right` fields absent. Measured data consists of last measured left and right joint and comb. If a particular joint/comb has not been measured yet, the relevant field will be absent. It was discussed with the NVT that if the KZV SW requests measured data frequently enough (e. g. once per second), it can't miss any measured comb or joint, because those are not that close to each other. All the returned values are reported in meters. ### Request ```json { "messageType": "GetMeasuredData" } ``` ### Response Example with all fields present (all values measured) ```json { "messageType": "MeasuredData", "jointLeft": { "distance": 10, "km": 133.4, "jointLength": 0.0123 }, "jointRight": { "distance": 10.1, "km": 133.4, "jointLength": 0.0123 }, "combLeft": { "distance": 20, "km": 133.4, "overlap1": 0.11, "overlap2": 0.111, "overlap3": 0.109, "opening1": 0.01, "opening3": 0.009, "opening2": 0.011, "heightDifference1": 0.0021, "heightDifference2": 0.0022, "heightDifference3": 0.0023 }, "combRight": { "distance": 20.1, "km": 133.4, "overlap1": 0.11, "overlap2": 0.111, "overlap3": 0.109, "opening1": 0.01, "opening3": 0.009, "opening2": 0.011, "heightDifference1": 0.0021, "heightDifference2": 0.0022, "heightDifference3": 0.0023 } } ``` Example with only the left joint having been measured yet ```json { "messageType": "MeasuredData", "jointLeft": { "distance": 10, "km": 133.4, "jointLength": 0.0123 } } ``` ## StopMeasurement This command instructs the NVT to stop current measurement. ### Request ```json { "messageType": "StopMeasurement" } ``` ### Response [CommandResponse](#commandresponse). `Ok` if measurement was stopped successfully, `Failure` if there was a problem (HW problem, measurement not running, ...)