File service_protocol.hpp
File List > SensorHub_FW > src > service_protocol.hpp
Go to the documentation of this file
/* *******************************************************************************************
* Copyright (c) 2023 by RobotPatient Simulators
*
* Authors: Richard Kroesen en Victor Hogeweij
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction,
*
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
* is furnished to do so,
*
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
***********************************************************************************************/
#ifndef SERVICEPROTOCOL_HPP
#define SERVICEPROTOCOL_HPP
#include <Arduino.h>
#include <FreeRTOS.h>
#include <queue.h>
#include <device_settings.hpp>
#include <device_status.hpp>
#include <ringbuffer.hpp>
#include <usb_service_protocol.hpp>
const char kStreamFormatString[] = "{\"NumOfShorts\": %d, \"SampleNum\": %d, \"Sensor\": %d, \"Buf\": [";
const char kStreamDataFormatString[] = "{ \"Val\": %d}";
const char kHelpUsageString[] = "**********************************HELP************************************"
"\r\n"
"CMDS: STATUS - Prints: status of the system, connected devices and "
"sampletime\r\n"
" SETPORT [DeviceType portA] [DeviceType portB] [DeviceType BackBone] "
"\r\n"
" - Setup (sensor) software drivers on the selected port in "
"argument\r\n"
" SETID [UniqueDeviceID] - Sets a unique identifier for the system\r\n"
" STREAM - Stream current sensor measurements to this console\r\n"
" SETSR [Sample rate port a] [Sample rate port b] - Sets the sample rate for \r\n"
" port a in b in milliseconds (10-1000 ms)\r";
const char kSetPortFormatString[] = "!OK Port A set to: %d, Port B set to: %d, Port BB set to: %d";
const char kInvalidArgumentValues[] = "!E Invalid arguments entered!";
const char kSetIDFormatString[] = "!OK Device id is set to: %d";
const char kSetSampleTimeFormatString[] = "!OK Sampletime on Port A set to: %d, Port B set to: %d";
inline constexpr int kMessageBufferSize = 1024;
static char MessageBuffer[kMessageBufferSize];
inline constexpr uint8_t kNumOfRegisters = 7;
inline constexpr uint8_t kNumOfArgumentsSetPort = 3;
inline constexpr int kUpperRangeArgSetPort = kNumOfSupportedSensors-1;
inline constexpr int kLowerRangeArgSetPort = 0;
inline constexpr uint8_t kNumOfArgumentsSetID = 1;
inline constexpr int kUpperRangeArgSetID = 255;
inline constexpr int kLowerRangeArgSetID = 0;
inline constexpr uint8_t kNumOfArgumentsSetSR = 2;
inline constexpr int kUpperRangeArgSetSR = 1000;
inline constexpr int kLowerRangeArgSetSR = 10;
inline constexpr uint8_t ParseOK = 1;
inline constexpr uint8_t ParseFail = 0;
typedef struct {
uint8_t num_of_arguments;
int upper_range;
int lower_range;
} ArgSpecs;
uint8_t ParseEnteredArgumentsToInt(char** argument, int* buffer, const ArgSpecs ArgSpec) {
for (uint8_t arg_num = 0; arg_num < ArgSpec.num_of_arguments; arg_num++) {
buffer[arg_num] = atoi(argument[arg_num]);
if (buffer[arg_num] < ArgSpec.lower_range || buffer[arg_num] > ArgSpec.upper_range) {
return ParseFail;
}
}
return ParseOK;
}
void ComposeJsonFormattedStringOfSensorData(SensorData* data) {
memset(MessageBuffer, '\0', kMessageBufferSize);
uint8_t num_of_shorts = data->num_of_bytes > 1 ? (data->num_of_bytes) / 2 : 1;
int writecnt = snprintf(MessageBuffer, kMessageBufferSize, kStreamFormatString, num_of_shorts, data->sample_num, data->sensor_id);
for (uint8_t sensor_short_num = 0; sensor_short_num < num_of_shorts; sensor_short_num++) {
writecnt += snprintf(MessageBuffer + writecnt, kMessageBufferSize - writecnt, kStreamDataFormatString, data->buffer[sensor_short_num]);
if (sensor_short_num != num_of_shorts - 1)
writecnt += snprintf(MessageBuffer + writecnt, kMessageBufferSize - writecnt, ",");
}
snprintf(MessageBuffer + writecnt, kMessageBufferSize - writecnt, "]}");
}
const char* CMD_STATUS_CB(char** args, int num_of_args) {
memset(MessageBuffer, '\0', kMessageBufferSize);
systemStatus.GetDeviceStatus(MessageBuffer, kMessageBufferSize);
return MessageBuffer;
}
const char* CMD_SETPORT_CB(char** args, int num_of_args) {
memset(MessageBuffer, '\0', kMessageBufferSize);
int argBuffer[kNumOfI2CPorts];
const ArgSpecs SetPortSpecs = {kNumOfI2CPorts, kUpperRangeArgSetPort, kLowerRangeArgSetPort};
const bool ArgumentsAreValid = ParseEnteredArgumentsToInt(args, argBuffer, SetPortSpecs);
if (ArgumentsAreValid) {
portAProperties.AssignSensorToI2CPort((SensorTypes)argBuffer[module::status::kSensorPortAIndex]);
portBProperties.AssignSensorToI2CPort((SensorTypes)argBuffer[module::status::kSensorPortBIndex]);
snprintf(MessageBuffer, kMessageBufferSize, kSetPortFormatString, argBuffer[module::status::kSensorPortAIndex],
argBuffer[module::status::kSensorPortBIndex], argBuffer[module::status::kBBPortIndex]);
return MessageBuffer;
} else {
return kInvalidArgumentValues;
}
}
const char* CMD_SETID_CB(char** args, int num_of_args) {
memset(MessageBuffer, '\0', kMessageBufferSize);
int argBuffer[kNumOfArgumentsSetID];
const ArgSpecs SetIDSpecs = {kNumOfArgumentsSetID, kUpperRangeArgSetID, kLowerRangeArgSetID};
const bool ArgumentsAreValid = ParseEnteredArgumentsToInt(args, argBuffer, SetIDSpecs);
if (ArgumentsAreValid) {
systemStatus.SetDeviceID(argBuffer[0]);
snprintf(MessageBuffer, kMessageBufferSize, kSetIDFormatString, argBuffer[0]);
return MessageBuffer;
} else {
return kInvalidArgumentValues;
}
}
const char* CMD_STREAM_CB(char** args, int num_of_args) {
memset(MessageBuffer, '\0', kMessageBufferSize);
SensorData data;
while (1) {
// Receive the SensorData from the message queue
if (xQueueReceive(serviceProtocolQueue, &(data), (TickType_t)10) == pdPASS) {
ComposeJsonFormattedStringOfSensorData
(&data);
return MessageBuffer;
}
}
return "!E can't receive message from queue";
}
const char* CMD_HELP_CB(char** args, int num_of_args) {
return kHelpUsageString;
}
const char* CMD_SETSR_CB(char** args, int num_of_args) {
memset(MessageBuffer, '\0', kMessageBufferSize);
int argBuffer[kNumOfArgumentsSetSR];
const ArgSpecs SetIDSpecs = {kNumOfArgumentsSetSR, kUpperRangeArgSetSR, kLowerRangeArgSetSR};
const bool ArgumentsAreValid = ParseEnteredArgumentsToInt(args, argBuffer, SetIDSpecs);
if (ArgumentsAreValid) {
portAProperties.SetSampleTime(argBuffer[0]);
portBProperties.SetSampleTime(argBuffer[1]);
snprintf(MessageBuffer, kMessageBufferSize, kSetSampleTimeFormatString, argBuffer[0], argBuffer[1]);
return MessageBuffer;
} else {
return kInvalidArgumentValues;
}
}
static usb_service_protocol::USBServiceProtocolRegisters USBRegisters[kNumOfRegisters]{ {"STATUS", 0, false, CMD_STATUS_CB},
{"SETPORT", kNumOfArgumentsSetPort, false, CMD_SETPORT_CB},
{"SETID", kNumOfArgumentsSetID, false, CMD_SETID_CB},
{"STREAM", 0, true, CMD_STREAM_CB},
{"SETSR", kNumOfArgumentsSetSR, false, CMD_SETSR_CB},
{"HELP", 0, false, CMD_HELP_CB}};
#endif