Skip to content

Commit 258ff79

Browse files
nehalkpatelclaude
andcommitted
Refactor I2C and UART interfaces to use std::byte
Replace uint8_t with std::byte for all I2C and UART data transmission APIs to improve type safety and prevent accidental arithmetic operations on raw byte data. This change aligns with modern C++ best practices and makes the intent of byte-oriented operations more explicit throughout the codebase. Updated interfaces, implementations, applications, and tests. Added custom JSON serialization support for std::byte in the host emulator message encoder. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 499242e commit 258ff79

12 files changed

Lines changed: 120 additions & 77 deletions

src/apps/i2c_demo/i2c_demo.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <algorithm>
44
#include <array>
55
#include <chrono>
6+
#include <cstddef>
67
#include <expected>
78

89
#include "apps/app.hpp"
@@ -35,7 +36,8 @@ auto I2CDemo::Run() -> std::expected<void, common::Error> {
3536
constexpr uint16_t kDeviceAddress{0x50};
3637

3738
// Test pattern to write/read
38-
const std::array<uint8_t, 4> test_pattern{0xDE, 0xAD, 0xBE, 0xEF};
39+
const std::array<std::byte, 4> test_pattern{std::byte{0xDE}, std::byte{0xAD},
40+
std::byte{0xBE}, std::byte{0xEF}};
3941

4042
// Main loop - write pattern, read it back, verify
4143
while (true) {

src/apps/uart_echo/uart_echo.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ auto UartEcho::Init() -> std::expected<void, common::Error> {
3333
[this, &uart_config]() { return board_.Uart1().Init(uart_config); })
3434
.and_then([this]() {
3535
return board_.Uart1().SetRxHandler(
36-
[this](const uint8_t* data, size_t size) {
36+
[this](const std::byte* data, size_t size) {
3737
// Echo the data back
38-
const std::vector<uint8_t> echo_data(data, data + size);
38+
const std::vector<std::byte> echo_data(data, data + size);
3939
std::ignore = board_.Uart1().Send(echo_data);
4040

4141
// Toggle LED1 to indicate data received
@@ -47,8 +47,9 @@ auto UartEcho::Init() -> std::expected<void, common::Error> {
4747
auto UartEcho::Run() -> std::expected<void, common::Error> {
4848
// Send initial greeting message
4949
const std::string greeting{"UART Echo ready! Send data to echo it back.\n"};
50+
const auto* greeting_bytes{reinterpret_cast<const std::byte*>(greeting.data())};
5051
auto send_result{board_.Uart1().Send(
51-
std::vector<uint8_t>(greeting.begin(), greeting.end()))};
52+
std::span<const std::byte>{greeting_bytes, greeting.size()})};
5253
if (!send_result) {
5354
return std::unexpected(send_result.error());
5455
}

src/libs/mcu/host/emulator_message_json_encoder.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
#pragma once
22

3+
#include <cstddef>
34
#include <nlohmann/json.hpp>
45
#include <string>
6+
#include <vector>
57

68
#include "libs/common/error.hpp"
79
#include "libs/mcu/host/host_emulator_messages.hpp"
810
#include "libs/mcu/pin.hpp"
911

12+
// Custom JSON serialization for std::byte
13+
namespace nlohmann {
14+
template <>
15+
struct adl_serializer<std::byte> {
16+
static void to_json(json& j, const std::byte& b) {
17+
j = std::to_integer<uint8_t>(b);
18+
}
19+
20+
static void from_json(const json& j, std::byte& b) {
21+
b = static_cast<std::byte>(j.get<uint8_t>());
22+
}
23+
};
24+
} // namespace nlohmann
25+
1026
namespace common {
1127

1228
NLOHMANN_JSON_SERIALIZE_ENUM(Error,

src/libs/mcu/host/host_emulator_messages.hpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <cstddef>
34
#include <cstdint>
45
#include <expected>
56
#include <string>
@@ -43,9 +44,9 @@ struct UartEmulatorRequest {
4344
ObjectType object{ObjectType::kUart};
4445
std::string name;
4546
OperationType operation;
46-
std::vector<uint8_t> data; // For Send operation
47-
size_t size{0}; // For Receive operation (buffer size)
48-
uint32_t timeout_ms{0}; // For Receive operation
47+
std::vector<std::byte> data; // For Send operation
48+
size_t size{0}; // For Receive operation (buffer size)
49+
uint32_t timeout_ms{0}; // For Receive operation
4950
auto operator==(const UartEmulatorRequest& other) const -> bool {
5051
return type == other.type && object == other.object && name == other.name &&
5152
operation == other.operation && data == other.data &&
@@ -57,7 +58,7 @@ struct UartEmulatorResponse {
5758
MessageType type{MessageType::kResponse};
5859
ObjectType object{ObjectType::kUart};
5960
std::string name;
60-
std::vector<uint8_t> data; // Received data
61+
std::vector<std::byte> data; // Received data
6162
size_t bytes_transferred{0};
6263
common::Error status;
6364
auto operator==(const UartEmulatorResponse& other) const -> bool {
@@ -73,8 +74,8 @@ struct I2CEmulatorRequest {
7374
std::string name;
7475
OperationType operation;
7576
uint16_t address{0};
76-
std::vector<uint8_t> data; // For Send operation
77-
size_t size{0}; // For Receive operation (buffer size)
77+
std::vector<std::byte> data; // For Send operation
78+
size_t size{0}; // For Receive operation (buffer size)
7879
auto operator==(const I2CEmulatorRequest& other) const -> bool {
7980
return type == other.type && object == other.object && name == other.name &&
8081
operation == other.operation && address == other.address &&
@@ -87,7 +88,7 @@ struct I2CEmulatorResponse {
8788
ObjectType object{ObjectType::kI2C};
8889
std::string name;
8990
uint16_t address{0};
90-
std::vector<uint8_t> data; // Received data
91+
std::vector<std::byte> data; // Received data
9192
size_t bytes_transferred{0};
9293
common::Error status;
9394
auto operator==(const I2CEmulatorResponse& other) const -> bool {

src/libs/mcu/host/host_i2c.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@
1515
namespace mcu {
1616

1717
auto HostI2CController::SendData(uint16_t address,
18-
std::span<const uint8_t> data)
18+
std::span<const std::byte> data)
1919
-> std::expected<void, common::Error> {
2020
const I2CEmulatorRequest request{
2121
.type = MessageType::kRequest,
2222
.object = ObjectType::kI2C,
2323
.name = name_,
2424
.operation = OperationType::kSend,
2525
.address = address,
26-
.data = std::vector<uint8_t>(data.begin(), data.end()),
26+
.data = std::vector<std::byte>(data.begin(), data.end()),
2727
.size = 0,
2828
};
2929

@@ -46,7 +46,7 @@ auto HostI2CController::SendData(uint16_t address,
4646
}
4747

4848
auto HostI2CController::ReceiveData(uint16_t address, size_t size)
49-
-> std::expected<std::span<uint8_t>, common::Error> {
49+
-> std::expected<std::span<std::byte>, common::Error> {
5050
const I2CEmulatorRequest request{
5151
.type = MessageType::kRequest,
5252
.object = ObjectType::kI2C,
@@ -77,11 +77,11 @@ auto HostI2CController::ReceiveData(uint16_t address, size_t size)
7777
const size_t bytes_to_copy{std::min(response.data.size(), buffer.size())};
7878
std::copy_n(response.data.begin(), bytes_to_copy, buffer.begin());
7979

80-
return std::span<uint8_t>{buffer.data(), bytes_to_copy};
80+
return std::span<std::byte>{buffer.data(), bytes_to_copy};
8181
}
8282

8383
auto HostI2CController::SendDataInterrupt(
84-
uint16_t address, std::span<const uint8_t> data,
84+
uint16_t address, std::span<const std::byte> data,
8585
std::function<void(std::expected<void, common::Error>)> callback)
8686
-> std::expected<void, common::Error> {
8787
callback(SendData(address, data));
@@ -90,14 +90,14 @@ auto HostI2CController::SendDataInterrupt(
9090

9191
auto HostI2CController::ReceiveDataInterrupt(
9292
uint16_t address, size_t size,
93-
std::function<void(std::expected<std::span<uint8_t>, common::Error>)>
93+
std::function<void(std::expected<std::span<std::byte>, common::Error>)>
9494
callback) -> std::expected<void, common::Error> {
9595
callback(ReceiveData(address, size));
9696
return {};
9797
}
9898

9999
auto HostI2CController::SendDataDma(
100-
uint16_t address, std::span<const uint8_t> data,
100+
uint16_t address, std::span<const std::byte> data,
101101
std::function<void(std::expected<void, common::Error>)> callback)
102102
-> std::expected<void, common::Error> {
103103
callback(SendData(address, data));
@@ -106,7 +106,7 @@ auto HostI2CController::SendDataDma(
106106

107107
auto HostI2CController::ReceiveDataDma(
108108
uint16_t address, size_t size,
109-
std::function<void(std::expected<std::span<uint8_t>, common::Error>)>
109+
std::function<void(std::expected<std::span<std::byte>, common::Error>)>
110110
callback) -> std::expected<void, common::Error> {
111111
callback(ReceiveData(address, size));
112112
return {};

src/libs/mcu/host/host_i2c.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,34 +23,34 @@ class HostI2CController final : public I2CController, public Receiver {
2323
auto operator=(HostI2CController&&) -> HostI2CController& = delete;
2424
~HostI2CController() override = default;
2525

26-
auto SendData(uint16_t address, std::span<const uint8_t> data)
26+
auto SendData(uint16_t address, std::span<const std::byte> data)
2727
-> std::expected<void, common::Error> override;
2828

2929
auto ReceiveData(uint16_t address, size_t size)
30-
-> std::expected<std::span<uint8_t>, common::Error> override;
30+
-> std::expected<std::span<std::byte>, common::Error> override;
3131

3232
auto SendDataInterrupt(
33-
uint16_t address, std::span<const uint8_t> data,
33+
uint16_t address, std::span<const std::byte> data,
3434
std::function<void(std::expected<void, common::Error>)> callback)
3535
-> std::expected<void, common::Error> override;
3636
auto ReceiveDataInterrupt(
3737
uint16_t address, size_t size,
38-
std::function<void(std::expected<std::span<uint8_t>, common::Error>)>
38+
std::function<void(std::expected<std::span<std::byte>, common::Error>)>
3939
callback) -> std::expected<void, common::Error> override;
4040

41-
auto SendDataDma(uint16_t address, std::span<const uint8_t> data,
41+
auto SendDataDma(uint16_t address, std::span<const std::byte> data,
4242
std::function<void(std::expected<void, common::Error>)>
4343
callback) -> std::expected<void, common::Error> override;
4444
auto ReceiveDataDma(
4545
uint16_t address, size_t size,
46-
std::function<void(std::expected<std::span<uint8_t>, common::Error>)>
46+
std::function<void(std::expected<std::span<std::byte>, common::Error>)>
4747
callback) -> std::expected<void, common::Error> override;
4848
auto Receive(const std::string_view& message)
4949
-> std::expected<std::string, common::Error> override;
5050

5151
private:
5252
const std::string name_;
5353
Transport& transport_;
54-
std::unordered_map<uint16_t, std::array<uint8_t, 256>> data_buffers_;
54+
std::unordered_map<uint16_t, std::array<std::byte, 256>> data_buffers_;
5555
};
5656
} // namespace mcu

src/libs/mcu/host/host_uart.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ auto HostUart::Init(const UartConfig& config)
2727
return {};
2828
}
2929

30-
auto HostUart::Send(std::span<const uint8_t> data)
30+
auto HostUart::Send(std::span<const std::byte> data)
3131
-> std::expected<void, common::Error> {
3232
if (!initialized_) {
3333
return std::unexpected(common::Error::kInvalidState);
@@ -42,7 +42,7 @@ auto HostUart::Send(std::span<const uint8_t> data)
4242
.object = ObjectType::kUart,
4343
.name = name_,
4444
.operation = OperationType::kSend,
45-
.data = std::vector<uint8_t>(data.begin(), data.end()),
45+
.data = std::vector<std::byte>(data.begin(), data.end()),
4646
.size = 0,
4747
.timeout_ms = 0,
4848
};
@@ -59,7 +59,7 @@ auto HostUart::Send(std::span<const uint8_t> data)
5959
});
6060
}
6161

62-
auto HostUart::Receive(std::span<uint8_t> buffer, uint32_t timeout_ms)
62+
auto HostUart::Receive(std::span<std::byte> buffer, uint32_t timeout_ms)
6363
-> std::expected<size_t, common::Error> {
6464
if (!initialized_) {
6565
return std::unexpected(common::Error::kInvalidState);
@@ -99,7 +99,7 @@ auto HostUart::Receive(std::span<uint8_t> buffer, uint32_t timeout_ms)
9999
});
100100
}
101101

102-
auto HostUart::SendAsync(std::span<const uint8_t> data,
102+
auto HostUart::SendAsync(std::span<const std::byte> data,
103103
std::function<void(std::expected<void, common::Error>)>
104104
callback) -> std::expected<void, common::Error> {
105105
if (!initialized_) {
@@ -118,7 +118,7 @@ auto HostUart::SendAsync(std::span<const uint8_t> data,
118118
.object = ObjectType::kUart,
119119
.name = name_,
120120
.operation = OperationType::kSend,
121-
.data = std::vector<uint8_t>(data.begin(), data.end()),
121+
.data = std::vector<std::byte>(data.begin(), data.end()),
122122
.size = 0,
123123
.timeout_ms = 0,
124124
};
@@ -135,7 +135,7 @@ auto HostUart::SendAsync(std::span<const uint8_t> data,
135135
}
136136

137137
auto HostUart::ReceiveAsync(
138-
std::span<uint8_t> buffer,
138+
std::span<std::byte> buffer,
139139
std::function<void(std::expected<size_t, common::Error>)> callback)
140140
-> std::expected<void, common::Error> {
141141
if (!initialized_) {
@@ -191,7 +191,7 @@ auto HostUart::Flush() -> std::expected<void, common::Error> {
191191
return {};
192192
}
193193

194-
auto HostUart::SetRxHandler(std::function<void(const uint8_t*, size_t)> handler)
194+
auto HostUart::SetRxHandler(std::function<void(const std::byte*, size_t)> handler)
195195
-> std::expected<void, common::Error> {
196196
if (!initialized_) {
197197
return std::unexpected(common::Error::kInvalidState);

src/libs/mcu/host/host_uart.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,26 @@ class HostUart final : public Uart, public Receiver {
2525
auto Init(const UartConfig& config)
2626
-> std::expected<void, common::Error> override;
2727

28-
auto Send(std::span<const uint8_t> data)
28+
auto Send(std::span<const std::byte> data)
2929
-> std::expected<void, common::Error> override;
3030

31-
auto Receive(std::span<uint8_t> buffer, uint32_t timeout_ms)
31+
auto Receive(std::span<std::byte> buffer, uint32_t timeout_ms)
3232
-> std::expected<size_t, common::Error> override;
3333

34-
auto SendAsync(std::span<const uint8_t> data,
34+
auto SendAsync(std::span<const std::byte> data,
3535
std::function<void(std::expected<void, common::Error>)>
3636
callback) -> std::expected<void, common::Error> override;
3737

3838
auto ReceiveAsync(
39-
std::span<uint8_t> buffer,
39+
std::span<std::byte> buffer,
4040
std::function<void(std::expected<size_t, common::Error>)> callback)
4141
-> std::expected<void, common::Error> override;
4242

4343
auto IsBusy() const -> bool override;
4444
auto Available() const -> size_t override;
4545
auto Flush() -> std::expected<void, common::Error> override;
4646

47-
auto SetRxHandler(std::function<void(const uint8_t*, size_t)> handler)
47+
auto SetRxHandler(std::function<void(const std::byte*, size_t)> handler)
4848
-> std::expected<void, common::Error> override;
4949

5050
// Receiver interface for handling async responses from emulator
@@ -63,10 +63,10 @@ class HostUart final : public Uart, public Receiver {
6363
std::function<void(std::expected<size_t, common::Error>)> receive_callback_{};
6464

6565
// Receive handler for unsolicited incoming data
66-
std::function<void(const uint8_t*, size_t)> rx_handler_{};
66+
std::function<void(const std::byte*, size_t)> rx_handler_{};
6767

6868
// Receive buffer for async operations
69-
std::vector<uint8_t> receive_buffer_{};
69+
std::vector<std::byte> receive_buffer_{};
7070
};
7171

7272
} // namespace mcu

0 commit comments

Comments
 (0)