Skip to content

Commit

Permalink
Implement some JSON, fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Barabas5532 committed Nov 27, 2023
1 parent 55f8397 commit ef957e5
Show file tree
Hide file tree
Showing 23 changed files with 357 additions and 106 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@
[submodule "test/support/freertos/FreeRTOS-Kernel"]
path = test/support/freertos/FreeRTOS-Kernel
url = https://github.com/Barabas5532/FreeRTOS-Kernel.git
[submodule "test/support/protobuf-c/protobuf-c"]
path = test/support/protobuf-c/protobuf-c
url = https://github.com/protobuf-c/protobuf-c.git
4 changes: 3 additions & 1 deletion firmware/components/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ add_subdirectory(messages)
add_subdirectory(midi_mapping)
add_subdirectory(midi_protocol)
add_subdirectory(os)
add_subdirectory(persistence)
add_subdirectory(persistence)
add_subdirectory(presets)
add_subdirectory(uuid)
1 change: 1 addition & 0 deletions firmware/components/midi_mapping/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ target_link_libraries(midi_mapping
shrapnel::audio_param
shrapnel::etl
shrapnel::midi_protocol
shrapnel::uuid
shrapnel::rapidjson
PRIVATE
shrapnel::compiler_warning_flags)
Expand Down
3 changes: 2 additions & 1 deletion firmware/components/midi_mapping/include/midi_mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,13 @@

#include "audio_param.h"
#include "midi_protocol.h"
#include "uuid.h"

namespace shrapnel {
namespace midi {

struct Mapping {
using id_t = std::array<uint8_t, 16>;
using id_t = uuid::uuid_t;

enum class Mode
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ rapidjson::Value to_json(rapidjson::Document &document, const Message &object);
template<>
rapidjson::Value to_json(rapidjson::Document &document, const Mapping &object);

template<>
rapidjson::Value to_json(rapidjson::Document &document, const Mapping::id_t &object);

template<>
rapidjson::Value to_json(rapidjson::Document &document, const std::pair<Mapping::id_t, Mapping> &object);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ std::optional<MapType> from_json(const rapidjson::Value &json) {
return std::nullopt;
}

auto id = from_json<Mapping::id_t>(entry.name);
auto id = uuid::from_json<Mapping::id_t>(entry.name);
if(!id.has_value())
{
ESP_LOGE(TAG, "failed to get uuid");
Expand Down
21 changes: 2 additions & 19 deletions firmware/components/midi_mapping/src/midi_mapping_json_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,31 +114,14 @@ rapidjson::Value to_json(rapidjson::Document &document, const Mapping &object)
return json;
}

template <>
rapidjson::Value to_json(rapidjson::Document &document,
const Mapping::id_t &object) {
char uuid[37];
sprintf(uuid,
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
"%02x%02x%02x%02x%02x%02x",
object[0], object[1], object[2], object[3], object[4], object[5],
object[6], object[7], object[8], object[9], object[10], object[11],
object[12], object[13], object[14], object[15]);

rapidjson::Value out;
out.SetString(uuid, 36, document.GetAllocator());

return out;
}

template<>
rapidjson::Value to_json(rapidjson::Document &document, const std::pair<Mapping::id_t, Mapping> &object)
{
rapidjson::Value json;
json.SetObject();

rapidjson::Value mapping = to_json(document, object.second);
auto id = to_json(document, object.first);
auto id = uuid::to_json(document, object.first);
json.AddMember(id, mapping, document.GetAllocator());
return json;
}
Expand Down Expand Up @@ -209,7 +192,7 @@ rapidjson::Value to_json(rapidjson::Document &document, const etl::imap<Mapping:
for(const auto &entry : object)
{
rapidjson::Value mapping = to_json(document, entry.second);
auto id = to_json(document, entry.first);
auto id = uuid::to_json(document, entry.first);
json.AddMember(id, mapping, document.GetAllocator());
}

Expand Down
76 changes: 2 additions & 74 deletions firmware/components/midi_mapping/src/midi_mapping_json_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
namespace shrapnel {
namespace midi {

static int parse_uuid(Mapping::id_t &uuid, const char *string);

template<>
std::optional<GetRequest> from_json(const rapidjson::Value &)
{
Expand Down Expand Up @@ -117,7 +115,7 @@ std::optional<std::pair<Mapping::id_t, Mapping>> from_json(const rapidjson::Valu
return std::nullopt;
}

auto id = from_json<Mapping::id_t>(mapping_id);
auto id = uuid::from_json<Mapping::id_t>(mapping_id);
if(!id.has_value()) {
ESP_LOGE(TAG, "failed to get id");
return std::nullopt;
Expand Down Expand Up @@ -166,7 +164,7 @@ std::optional<Remove> from_json(const rapidjson::Value &json) {
return std::nullopt;
}

auto uuid = from_json<Mapping::id_t>(id_member->value);
auto uuid = uuid::from_json<Mapping::id_t>(id_member->value);
if(!uuid.has_value())
{
ESP_LOGE(TAG, "Failed to parse UUID");
Expand Down Expand Up @@ -210,75 +208,5 @@ std::optional<MappingApiMessage> from_json(const rapidjson::Value &json) {
return std::nullopt;
}

template<>
std::optional<Mapping::id_t> from_json(const rapidjson::Value &json) {
constexpr const char *TAG = "Mapping::id_t from_json";

if (!json.IsString()) {
ESP_LOGE(TAG, "id is not string");
return std::nullopt;
}

Mapping::id_t out;
int rc = parse_uuid(out, json.GetString());
if(rc != 0) {
ESP_LOGE(TAG, "failed to get uuid");
return std::nullopt;
}

return out;
}

static int parse_uuid(Mapping::id_t &uuid, const char *string)
{
constexpr std::size_t UUID_LENGTH = 36;
constexpr char TAG[] = "parse_uuid";

if(UUID_LENGTH != std::strlen(string))
{
ESP_LOGE(TAG, "Incorrect UUID string length");
return -1;
}

size_t i = 0;
size_t j = 0;
ESP_LOGD(TAG, "i = %zu, j = %zu", i , j);
while(i < UUID_LENGTH)
{
char digit[2];
std::memcpy(digit, &string[i], 2);

ESP_LOGD(TAG, "digit = %c%c", digit[0] , digit[1]);

// TODO error on invalid characters: z, symbols etc
// The only valid characters are 0 to 9 and a to f.
//
// Handle uppercase as well. It is required when a string UUID
// is an input as per RFC 4122 Section 3
// https://tools.ietf.org/html/rfc4122#section-3
auto get_value = [&] (char hex) -> uint8_t {
if(hex >= 'a')
{
return hex - 'a' + 10;
}
else
{
return hex - '0';
}
};

uuid[j] = get_value(digit[0]) << 4 | get_value(digit[1]);

j++;

i += 2;
bool is_separator = (i == 8) || (i == 13) || (i == 18) || (i == 23);
if(is_separator) i++;
ESP_LOGD(TAG, "i = %zu, j = %zu", i , j);
}

return 0;
}

}
}
20 changes: 18 additions & 2 deletions firmware/components/presets/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,23 @@ add_library(shrapnel::presets ALIAS presets)
target_sources(presets
PRIVATE
proto/generated/presets.pb-c.c
src/presets_json_builder.cpp)
src/presets_json_builder.cpp
src/selected_preset_json_builder.cpp)
target_include_directories(presets PUBLIC proto/generated include)

target_link_libraries(presets PUBLIC idf::protobuf-c shrapnel::rapidjson)
target_link_libraries(presets PUBLIC idf::protobuf-c shrapnel::rapidjson shrapnel::etl shrapnel::uuid)

if(DEFINED TESTING)
add_executable(presets_test
test/selected_preset_json_builder.cpp)

target_include_directories(presets_test PRIVATE include)

target_link_libraries(presets_test
PRIVATE
presets
GTest::gtest_main
GTest::gmock
shrapnel::compiler_warning_flags)
gtest_discover_tests(presets_test)
endif()
3 changes: 1 addition & 2 deletions firmware/components/presets/include/presets.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#pragma once

#include <cstdint>
#include <etl/array.h>

namespace shrapnel::presets {
using id_t = etl::array<uint8_t, 16>;
using id_t = std::array<uint8_t, 16>;
}
9 changes: 6 additions & 3 deletions firmware/components/presets/include/selected_preset_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,24 @@
#include <variant>

#include "presets.h"
#include "uuid.h"

namespace shrapnel::presets {
namespace shrapnel::selected_preset {

using shrapnel::uuid::uuid_t;

struct Read
{
};

struct Notify
{
id_t selectedPresetId;
uuid_t selectedPresetId;
};

struct Write
{
id_t selectedPresetId;
uuid_t selectedPresetId;
};

using SelectedPresetApiMessage = std::variant<Read, Notify, Write>;
Expand Down
38 changes: 38 additions & 0 deletions firmware/components/presets/include/selected_preset_json_builder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once

// Disable warning inside rapidjson
// https://github.com/Tencent/rapidjson/issues/1700
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
#pragma GCC diagnostic ignored "-Wsign-conversion"
#pragma GCC diagnostic ignored "-Wswitch-enum"
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#pragma GCC diagnostic pop

#include "selected_preset_api.h"

namespace shrapnel::selected_preset {

/** Convert \p object to a JSON value
*
* \note The \p document must not by modified by this function. It is only
* passed in so that its allocator member can be accessed.
*/
template <typename T>
rapidjson::Value to_json(rapidjson::Document &document, const T &object);

template <>
rapidjson::Value to_json(rapidjson::Document &document,
const Read &object);

template <>
rapidjson::Value to_json(rapidjson::Document &document,
const Notify &object);

template <>
rapidjson::Value to_json(rapidjson::Document &document,
const Write &object);

} // namespace shrapnel::selected_preset
22 changes: 22 additions & 0 deletions firmware/components/presets/src/selected_preset_json_builder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "selected_preset_json_builder.h"

namespace shrapnel::selected_preset {

template <>
rapidjson::Value to_json(rapidjson::Document &document, const Notify &object)
{
rapidjson::Value json;
json.SetObject();

json.AddMember("messageType",
rapidjson::StringRef("SelectedPreset::notify"),
document.GetAllocator());

json.AddMember("selectedPreset",
uuid::to_json(document, object.selectedPresetId),
document.GetAllocator());

return json;
}

} // namespace shrapnel::selected_preset
Loading

0 comments on commit ef957e5

Please sign in to comment.