aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/pbdrv/CMakeLists.txt14
-rw-r--r--lib/pbdrv/pb-buf.c10
-rw-r--r--lib/pbdrv/pb-buf.h20
-rw-r--r--lib/pbdrv/pb-msg.c32
-rw-r--r--lib/pbdrv/pb-msg.h17
-rw-r--r--lib/pbdrv/pb-read.c39
-rw-r--r--lib/pbdrv/pb-read.h28
-rw-r--r--lib/pbdrv/pb-serial.c66
-rw-r--r--lib/pbdrv/pb-serial.h46
-rw-r--r--lib/pbdrv/pb-types.h10
-rw-r--r--lib/pbdrv/pb-write.c97
-rw-r--r--lib/pbdrv/pb-write.h16
-rw-r--r--test/CMakeLists.txt2
-rw-r--r--test/pbdrv/cmd.cpp52
-rw-r--r--test/pbdrv/msg.cpp30
-rw-r--r--test/pbdrv/msg.h (renamed from test/pbdrv/cmd.h)0
16 files changed, 205 insertions, 274 deletions
diff --git a/lib/pbdrv/CMakeLists.txt b/lib/pbdrv/CMakeLists.txt
index 340e863..f1b1d62 100644
--- a/lib/pbdrv/CMakeLists.txt
+++ b/lib/pbdrv/CMakeLists.txt
@@ -12,17 +12,23 @@ project(pbdrv C CXX)
add_subdirectory(lib/mpack)
-# generic puzzle bus (de)serializer library
-add_library(pbdrv STATIC pb-read.c pb-write.c pb-serial.c)
+# generic puzzle bus message handling library functions
+add_library(pbdrv STATIC
+ pb-msg.c
+ pb-serial.c
+ pb-buf.c
+ )
target_link_libraries(pbdrv mpack)
target_include_directories(pbdrv SYSTEM INTERFACE .)
# puzzle bus module specific code (superset of pbdrv)
-add_library(pbdrv-mod STATIC pb-mod.c)
+add_library(pbdrv-mod STATIC
+ pb-mod.c
+ )
target_link_libraries(pbdrv-mod pbdrv)
target_include_directories(pbdrv-mod SYSTEM INTERFACE .)
# supported puzzle bus drivers
include(drv/arduino/cfg.cmake)
-# include(drv/rp2040/cfg.cmake) # moved to /main/pbdrv.c
+# include(drv/rp2040/cfg.cmake) # please see /main/pbdrv.h
diff --git a/lib/pbdrv/pb-buf.c b/lib/pbdrv/pb-buf.c
new file mode 100644
index 0000000..673040f
--- /dev/null
+++ b/lib/pbdrv/pb-buf.c
@@ -0,0 +1,10 @@
+#include "pb-buf.h"
+
+#include <stdlib.h>
+
+void pbdrv_buf_free(pbdrv_buf_t * buf) {
+ if (buf->data == NULL) return;
+ free(buf->data);
+ buf->data = NULL;
+}
+
diff --git a/lib/pbdrv/pb-buf.h b/lib/pbdrv/pb-buf.h
new file mode 100644
index 0000000..149b384
--- /dev/null
+++ b/lib/pbdrv/pb-buf.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//! binary buffer struct
+typedef struct {
+ char * data; //! pointer to data
+ size_t size; //! size of data
+} pbdrv_buf_t;
+
+void pbdrv_buf_free(pbdrv_buf_t * buf);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/lib/pbdrv/pb-msg.c b/lib/pbdrv/pb-msg.c
new file mode 100644
index 0000000..ead9f09
--- /dev/null
+++ b/lib/pbdrv/pb-msg.c
@@ -0,0 +1,32 @@
+#include <mpack.h>
+
+#include "pb-msg.h"
+#include "pb-serial.h"
+
+pbdrv_buf_t pbdrv_msg_write(const pb_msg_t * msg) {
+ pbdrv_buf_t buf = { 0 };
+ mpack_writer_t writer;
+
+ mpack_writer_init_growable(&writer, &buf.data, &buf.size);
+
+ pbdrv_serialize(&writer, msg);
+
+ mpack_writer_destroy(&writer);
+ return buf;
+}
+
+pb_msg_t * pbdrv_msg_read(const pbdrv_buf_t * buf) {
+ mpack_reader_t reader;
+ mpack_reader_init_data(&reader, buf->data, buf->size);
+
+ pb_msg_t * msg = malloc(sizeof(pb_msg_t));
+
+ pbdrv_deserialize(&reader, msg);
+
+ return msg;
+}
+
+void pbdrv_msg_free(pb_msg_t * msg) {
+ pbdrv_free(msg);
+}
+
diff --git a/lib/pbdrv/pb-msg.h b/lib/pbdrv/pb-msg.h
new file mode 100644
index 0000000..9823d57
--- /dev/null
+++ b/lib/pbdrv/pb-msg.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "pb-types.h"
+#include "pb-buf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+pbdrv_buf_t pbdrv_msg_write(const pb_msg_t * msg);
+pb_msg_t * pbdrv_msg_read(const pbdrv_buf_t * buf);
+void pbdrv_msg_free(pb_msg_t * msg);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/lib/pbdrv/pb-read.c b/lib/pbdrv/pb-read.c
deleted file mode 100644
index ce8b5b1..0000000
--- a/lib/pbdrv/pb-read.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <mpack.h>
-
-#include "pb-read.h"
-
-// pb_msg_header_t * pbdrv_read_msg_header(mpack_reader_t * reader, pb_msg_header_t * header) {
-// header->type = mpack_expect_u8(reader);
-// header->sender = mpack_expect_u16(reader);
-//
-// return header;
-// }
-//
-// pb_cmd_req_read_t * pbdrv_read_cmd_req_read(mpack_reader_t * reader, pb_cmd_req_read_t * msg) {
-// msg->propid = mpack_expect_u8(reader);
-//
-// return msg;
-// }
-//
-// void * pbdrv_read_unknown(const char * data, size_t size) {
-// mpack_reader_t reader;
-// mpack_reader_init_data(&reader, data, size);
-//
-// void * msg = NULL;
-//
-// pb_msg_header_t header;
-// pbdrv_read_msg_header(&reader, &header);
-// switch (header.type) {
-// case PB_CMD_REQ_READ: {
-// // pb_cmd_req_read_t msg;
-// msg = malloc(sizeof(pb_cmd_req_read_t));
-// pbdrv_read_cmd_req_read(&reader, msg);
-// break;
-// }
-// default: return NULL;
-// }
-//
-// if (mpack_reader_error(&reader) != mpack_ok) return NULL;
-// return NULL;
-// }
-
diff --git a/lib/pbdrv/pb-read.h b/lib/pbdrv/pb-read.h
deleted file mode 100644
index cb61e06..0000000
--- a/lib/pbdrv/pb-read.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <stddef.h>
-#include <mpack.h>
-
-#include "pb-types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// pb_msg_header_t * pbdrv_read_msg_header(mpack_reader_t * reader, pb_msg_header_t * header);
-// pb_cmd_req_read_t * pbdrv_read_cmd_req_read(mpack_reader_t * reader, pb_cmd_req_read_t * msg);
-//
-// pb_cmd_res_read_t * pbdrv_read_cmd_res_read(const char * data, size_t size);
-// pb_cmd_req_write_t * pbdrv_read_cmd_req_write(const char * data, size_t size);
-// pb_cmd_req_state_t * pbdrv_read_cmd_req_state(const char * data, size_t size);
-// pb_cmd_res_state_t * pbdrv_read_cmd_res_state(const char * data, size_t size);
-// pb_cmd_req_set_state_t * pbdrv_read_cmd_req_set_state(const char * data, size_t size);
-// pb_cmd_magic_t * pbdrv_read_cmd_magic(const char * data, size_t size);
-
-pb_msg_t * pbdrv_read_unknown(const pbdrv_buf_t * buf);
-
-#ifdef __cplusplus
-}
-#endif
-
diff --git a/lib/pbdrv/pb-serial.c b/lib/pbdrv/pb-serial.c
index bc213d5..95bb8fb 100644
--- a/lib/pbdrv/pb-serial.c
+++ b/lib/pbdrv/pb-serial.c
@@ -4,29 +4,83 @@
#include "pb-types.h"
void pbdrv_serialize(mpack_writer_t * writer, const pb_msg_t * msg) {
- pbdrv_s_msg_header(writer, msg);
+ pbdrv_sr_msg_header(writer, msg);
if (msg->msg == NULL) return;
+ switch (msg->type) {
+ case PB_CMD_REQ_READ: return pbdrv_sr_cmd_req_read(writer, msg);
+ case PB_CMD_RES_READ: return pbdrv_sr_cmd_res_read(writer, msg);
+ default: break;
+ }
+}
+void pbdrv_deserialize(mpack_reader_t * reader, pb_msg_t * msg) {
+ pbdrv_dsr_msg_header(reader, msg);
+ switch (msg->type) {
+ case PB_CMD_REQ_READ: return pbdrv_dsr_cmd_req_read(reader, msg);
+ case PB_CMD_RES_READ: return pbdrv_dsr_cmd_res_read(reader, msg);
+ default: break;
+ }
+}
+void pbdrv_free(pb_msg_t * msg) {
+ if (msg == NULL) return;
switch (msg->type) {
- case PB_CMD_REQ_READ: return pbdrv_s_cmd_req_read(writer, msg->msg);
- case PB_CMD_RES_READ: return pbdrv_s_cmd_res_read(writer, msg->msg);
+ case PB_CMD_REQ_READ: return pbdrv_free_cmd_req_read(msg);
+ case PB_CMD_RES_READ: return pbdrv_free_cmd_res_read(msg);
default: break;
}
+ pbdrv_free_msg_header(msg);
}
-void pbdrv_s_msg_header(mpack_writer_t * writer, const pb_msg_t * msg) {
+void pbdrv_sr_msg_header(mpack_writer_t * writer, const pb_msg_t * msg) {
mpack_write_u8(writer, msg->type);
// TODO: if pbdrv is compiled under the pbdrv-mod target, place
// PBDRV_MOD_ADDR in this field
mpack_write_u16(writer, msg->sender);
}
+void pbdrv_dsr_msg_header(mpack_reader_t * reader, pb_msg_t * msg) {
+ msg->type = mpack_expect_u8(reader);
+ msg->sender = mpack_expect_u16(reader);
+}
+void pbdrv_free_msg_header(pb_msg_t * msg) { }
-void pbdrv_s_cmd_req_read(mpack_writer_t * writer, const pb_cmd_req_read_t * msg) {
+void pbdrv_sr_cmd_req_read(mpack_writer_t * writer, const pb_msg_t * _msg) {
+ pb_cmd_req_read_t * msg = _msg->msg;
mpack_write_u8(writer, msg->propid);
}
+void pbdrv_dsr_cmd_req_read(mpack_reader_t * reader, pb_msg_t * _msg) {
+ pb_cmd_req_read_t * msg = _msg->msg = malloc(sizeof(pb_cmd_req_read_t));
+ msg->propid = mpack_expect_u8(reader);
+}
+void pbdrv_free_cmd_req_read(pb_msg_t * _msg) {
+ if (_msg->msg != NULL) {
+ free(_msg->msg);
+ _msg->msg = NULL;
+ }
+}
+
+void pbdrv_sr_cmd_res_read(mpack_writer_t * writer, const pb_msg_t * _msg) {
+ pb_cmd_res_read_t * msg = _msg->msg;
-void pbdrv_s_cmd_res_read(mpack_writer_t * writer, const pb_cmd_res_read_t * msg) {
mpack_write_u8(writer, msg->propid);
mpack_write_bin(writer, (char *) msg->value, msg->_value_size);
}
+void pbdrv_dsr_cmd_res_read(mpack_reader_t * reader, pb_msg_t * _msg) {
+ pb_cmd_res_read_t * msg = _msg->msg = malloc(sizeof(pb_cmd_res_read_t));
+
+ msg->propid = mpack_expect_u8(reader);
+ msg->_value_size = mpack_expect_bin(reader);
+ msg->value = (uint8_t *) mpack_read_bytes_alloc(reader, msg->_value_size);
+ mpack_done_bin(reader);
+}
+void pbdrv_free_cmd_res_read(pb_msg_t * _msg) {
+ if (_msg->msg != NULL) {
+ pb_cmd_res_read_t * msg = _msg->msg;
+ if (msg->value != NULL) {
+ MPACK_FREE(msg->value);
+ msg->value = NULL;
+ }
+ free(_msg->msg);
+ _msg->msg = NULL;
+ }
+}
diff --git a/lib/pbdrv/pb-serial.h b/lib/pbdrv/pb-serial.h
index 77e1345..ac89838 100644
--- a/lib/pbdrv/pb-serial.h
+++ b/lib/pbdrv/pb-serial.h
@@ -8,29 +8,29 @@
extern "C" {
#endif
-
-void pbdrv_serialize(mpack_writer_t * writer, const pb_msg_t * msg);
-
-void pbdrv_s_msg_header(mpack_writer_t * writer, const pb_msg_t * msg);
-void pbdrv_s_cmd_req_read(mpack_writer_t * writer, const pb_cmd_req_read_t * msg);
-void pbdrv_s_cmd_res_read(mpack_writer_t * writer, const pb_cmd_res_read_t * msg);
-void pbdrv_s_cmd_req_write(mpack_writer_t * writer, const pb_cmd_req_write_t * msg);
-void pbdrv_s_cmd_req_state(mpack_writer_t * writer, const pb_cmd_req_state_t * msg);
-void pbdrv_s_cmd_res_state(mpack_writer_t * writer, const pb_cmd_res_state_t * msg);
-void pbdrv_s_cmd_req_set_state(mpack_writer_t * writer, const pb_cmd_req_set_state_t * msg);
-void pbdrv_s_cmd_req_magic(mpack_writer_t * writer, const pb_cmd_req_magic_t * msg);
-void pbdrv_s_cmd_res_magic(mpack_writer_t * writer, const pb_cmd_res_magic_t * msg);
-
-// typedef void pbdrv_deserialize_t(mpack_reader_t * reader);
-// pbdrv_deserialize_t pbdrv_d_msg_header;
-// pbdrv_deserialize_t pbdrv_d_cmd_req_read;
-// pbdrv_deserialize_t pbdrv_d_cmd_res_read;
-// pbdrv_deserialize_t pbdrv_d_cmd_req_write;
-// pbdrv_deserialize_t pbdrv_d_cmd_req_state;
-// pbdrv_deserialize_t pbdrv_d_cmd_res_state;
-// pbdrv_deserialize_t pbdrv_d_cmd_req_set_state;
-// pbdrv_deserialize_t pbdrv_d_cmd_req_magic;
-// pbdrv_deserialize_t pbdrv_d_cmd_res_magic;
+#define __pb_cmd(name) \
+ pbdrv_serialize_t pbdrv_sr_##name; \
+ pbdrv_deserialize_t pbdrv_dsr_##name; \
+ pbdrv_free_t pbdrv_free_##name;
+
+typedef void pbdrv_serialize_t(mpack_writer_t * writer, const pb_msg_t * msg);
+pbdrv_serialize_t pbdrv_serialize;
+
+typedef void pbdrv_deserialize_t(mpack_reader_t * reader, pb_msg_t * msg);
+pbdrv_deserialize_t pbdrv_deserialize;
+
+typedef void pbdrv_free_t(pb_msg_t * msg);
+pbdrv_free_t pbdrv_free;
+
+__pb_cmd(msg_header)
+__pb_cmd(cmd_req_read)
+__pb_cmd(cmd_res_read)
+__pb_cmd(cmd_req_write)
+__pb_cmd(cmd_req_state)
+__pb_cmd(cmd_res_state)
+__pb_cmd(cmd_req_set_state)
+__pb_cmd(cmd_req_magic)
+__pb_cmd(cmd_res_magic)
#ifdef __cplusplus
}
diff --git a/lib/pbdrv/pb-types.h b/lib/pbdrv/pb-types.h
index 4974270..7156272 100644
--- a/lib/pbdrv/pb-types.h
+++ b/lib/pbdrv/pb-types.h
@@ -18,12 +18,6 @@ extern "C" {
//! I2C address (10 or 7 bit)
typedef uint16_t i2c_addr_t;
-//! binary buffer struct
-typedef struct {
- char * data; //! pointer to data
- size_t size; //! size of data
-} pbdrv_buf_t;
-
//! puzzle bus command types
enum pb_cmd_id {
PB_CMD_REQ_READ, //!< request a puzzle module property
@@ -66,14 +60,14 @@ typedef struct {
//! PB_CMD_RES_READ data
typedef struct {
uint8_t propid; //!< id of returned state property
- const uint8_t * value;
+ uint8_t * value;
size_t _value_size;
} pb_cmd_res_read_t;
//! PB_CMD_REQ_WRITE data
typedef struct {
uint8_t propid; //!< state property id to write
- const uint8_t * value; //!< new value of property
+ uint8_t * value; //!< new value of property
size_t _value_size;
} pb_cmd_req_write_t;
diff --git a/lib/pbdrv/pb-write.c b/lib/pbdrv/pb-write.c
deleted file mode 100644
index 445dd0b..0000000
--- a/lib/pbdrv/pb-write.c
+++ /dev/null
@@ -1,97 +0,0 @@
-#include <mpack.h>
-
-#include "pb-write.h"
-#include "pb-serial.h"
-
-pbdrv_buf_t pbdrv_write_msg(const pb_msg_t * msg) {
- pbdrv_buf_t buf = { 0 };
- mpack_writer_t writer;
-
- mpack_writer_init_growable(&writer, &buf.data, &buf.size);
-
- pbdrv_serialize(&writer, msg);
-
- mpack_writer_destroy(&writer);
- return buf;
-}
-
-//
-// pbdrv_buf_t pbdrv_write_cmd_req_read(pb_cmd_req_read_t data) {
-// data.header.type = PB_CMD_REQ_READ;
-// pbdrv_writer_t writer;
-// pbdrv_write_init(&writer);
-//
-// pbdrv_write_msg_header(&writer, data.header);
-// mpack_write_u8(&writer.writer, data.propid);
-//
-// return pbdrv_write_finish(&writer);
-// }
-//
-// pbdrv_buf_t pbdrv_write_cmd_res_read(pb_cmd_res_read_t data) {
-// data.header.type = PB_CMD_RES_READ;
-// pbdrv_writer_t writer;
-// pbdrv_write_init(&writer);
-//
-// pbdrv_write_msg_header(&writer, data.header);
-// mpack_write_u8(&writer.writer, data.propid);
-// mpack_write_bin(&writer.writer, (char *) data.value, data._value_size);
-//
-// return pbdrv_write_finish(&writer);
-// }
-//
-// pbdrv_buf_t pbdrv_write_cmd_req_write(pb_cmd_req_write_t data) {
-// data.header.type = PB_CMD_REQ_WRITE;
-// pbdrv_writer_t writer;
-// pbdrv_write_init(&writer);
-//
-// pbdrv_write_msg_header(&writer, data.header);
-// mpack_write_u8(&writer.writer, data.propid);
-// mpack_write_bin(&writer.writer, (char *) data.value, data._value_size);
-//
-// return pbdrv_write_finish(&writer);
-// }
-//
-// pbdrv_buf_t pbdrv_write_cmd_req_state(pb_cmd_req_state_t data) {
-// data.header.type = PB_CMD_REQ_STATE;
-// pbdrv_writer_t writer;
-// pbdrv_write_init(&writer);
-//
-// pbdrv_write_msg_header(&writer, data.header);
-// mpack_write_u8(&writer.writer, data.state);
-//
-// return pbdrv_write_finish(&writer);
-// }
-//
-// pbdrv_buf_t pbdrv_write_cmd_res_state(pb_cmd_res_state_t data) {
-// data.header.type = PB_CMD_RES_STATE;
-// pbdrv_writer_t writer;
-// pbdrv_write_init(&writer);
-//
-// pbdrv_write_msg_header(&writer, data.header);
-// mpack_write_u8(&writer.writer, data.state);
-//
-// return pbdrv_write_finish(&writer);
-// }
-//
-// pbdrv_buf_t pbdrv_write_cmd_req_set_state(pb_cmd_req_set_state_t data) {
-// data.header.type = PB_CMD_REQ_SET_STATE;
-// pbdrv_writer_t writer;
-// pbdrv_write_init(&writer);
-//
-// pbdrv_write_msg_header(&writer, data.header);
-// mpack_write_u8(&writer.writer, data.state);
-//
-// return pbdrv_write_finish(&writer);
-// }
-//
-// pbdrv_buf_t pbdrv_write_cmd_magic(pb_cmd_magic_t data) {
-// data.header.type = PB_CMD_MAGIC;
-// pbdrv_writer_t writer;
-// pbdrv_write_init(&writer);
-//
-// pbdrv_write_msg_header(&writer, data.header);
-// mpack_write_bin(&writer.writer, data.magic, data._magic_size);
-//
-// return pbdrv_write_finish(&writer);
-// }
-
diff --git a/lib/pbdrv/pb-write.h b/lib/pbdrv/pb-write.h
deleted file mode 100644
index c77db47..0000000
--- a/lib/pbdrv/pb-write.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#pragma once
-
-#include <mpack.h>
-
-#include "pb-types.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-pbdrv_buf_t pbdrv_write_msg(const pb_msg_t * msg);
-
-#ifdef __cplusplus
-}
-#endif
-
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index b2b2937..9b1f40e 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -8,7 +8,7 @@ project(pbtest C CXX ASM)
add_executable(test
# i2ctcp/main.cpp
- pbdrv/cmd.cpp
+ pbdrv/msg.cpp
)
add_subdirectory(lib/googletest)
diff --git a/test/pbdrv/cmd.cpp b/test/pbdrv/cmd.cpp
deleted file mode 100644
index 8b7ee89..0000000
--- a/test/pbdrv/cmd.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#include <gtest/gtest.h>
-
-#include "pb-write.h"
-#include "pb-read.h"
-
-#include "cmd.h"
-
-// sorry for metaprogramming
-#define test_cmd(fn) \
- TEST(pbdrv_cmd, fn) { \
- pbdrv_buf_t cmd = pbdrv_write_cmd_##fn(expected_##fn); \
- ASSERT_NE(cmd.data, nullptr); \
- ASSERT_GE(cmd.size, 0); \
- }
-
-// test_cmd(req_read);
-// test_cmd(res_read);
-// test_cmd(req_write);
-// test_cmd(req_state);
-// test_cmd(res_state);
-// test_cmd(req_set_state);
-// test_cmd(magic);
-
-TEST(pbdrv_cmd_rw, magic) {
- pb_cmd_req_read_t content = {
- .propid = 0,
- };
- pb_msg_t msg = {
- .type = PB_CMD_REQ_READ,
- .sender = 0xff,
- .msg = &content,
- };
- pbdrv_buf_t buf = pbdrv_write_msg(&msg);
-
- ASSERT_NE(buf.data, nullptr);
- ASSERT_GE(buf.size, 0);
-
- // void * _cmd = NULL;
- // pb_cmd_id type = pbdrv_read_msg();
- // ASSERT_EQ(type, PB_CMD_MAGIC);
-}
-
-// pb_cmd_req_read_t * msg = (pb_cmd_req_read_t *) pbdrv_read_unknown(cmd_req_read.data, cmd_req_read.size);
-// ASSERT_NE(msg, nullptr);
-// ASSERT_EQ(msg->header.type, PB_CMD_REQ_READ);
-
-// TEST(pbdrv, read_cmd_res_read) { }
-// TEST(pbdrv, read_cmd_req_state) { }
-// TEST(pbdrv, read_cmd_res_state) { }
-// TEST(pbdrv, read_cmd_req_set_state) { }
-// TEST(pbdrv, read_cmd_magic) { }
-
diff --git a/test/pbdrv/msg.cpp b/test/pbdrv/msg.cpp
new file mode 100644
index 0000000..3d2b48d
--- /dev/null
+++ b/test/pbdrv/msg.cpp
@@ -0,0 +1,30 @@
+#include <gtest/gtest.h>
+
+#include "pb-msg.h"
+
+TEST(pbdrv_msg_rw, cmd_req_read) {
+ pb_cmd_req_read_t content = {
+ .propid = 2,
+ };
+ pb_msg_t msg_write = {
+ .type = PB_CMD_REQ_READ,
+ .sender = 0xff,
+ .msg = &content,
+ };
+ pbdrv_buf_t buf = pbdrv_msg_write(&msg_write);
+
+ ASSERT_NE(buf.data, nullptr);
+ ASSERT_GE(buf.size, 0);
+
+ pb_msg_t * msg_read = pbdrv_msg_read(&buf);
+ pbdrv_buf_free(&buf);
+
+ ASSERT_EQ(buf.data, nullptr);
+
+ EXPECT_EQ(msg_write.type, msg_read->type);
+ EXPECT_EQ(msg_write.sender, msg_read->sender);
+ EXPECT_EQ(((pb_cmd_req_read_t *) msg_write.msg)->propid, ((pb_cmd_req_read_t *) msg_read->msg)->propid);
+
+ pbdrv_msg_free(msg_read);
+}
+
diff --git a/test/pbdrv/cmd.h b/test/pbdrv/msg.h
index 52bee37..52bee37 100644
--- a/test/pbdrv/cmd.h
+++ b/test/pbdrv/msg.h