建立 MAG160C 逆向工程交接仓库
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
#include "mag160c/mag160c.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
int main() {
|
||||
assert(std::strcmp(mag160c_error_name(MAG160C_OK), "MAG160C_OK") == 0);
|
||||
assert(std::strcmp(mag160c_error_name(MAG160C_ERR_PROTOCOL_UNKNOWN),
|
||||
"MAG160C_ERR_PROTOCOL_UNKNOWN") == 0);
|
||||
assert(std::strcmp(mag160c_error_name(static_cast<mag160c_error_t>(9999)),
|
||||
"MAG160C_ERR_UNKNOWN_CODE") == 0);
|
||||
|
||||
assert(mag160c_init(nullptr) == MAG160C_ERR_INVALID_ARGUMENT);
|
||||
assert(std::strstr(mag160c_last_error(), "out_ctx") != nullptr);
|
||||
|
||||
mag160c_context_t* ctx = nullptr;
|
||||
assert(mag160c_init(&ctx) == MAG160C_OK);
|
||||
assert(ctx != nullptr);
|
||||
assert(std::strcmp(mag160c_last_error(), "") == 0);
|
||||
|
||||
mag160c_shutdown(ctx);
|
||||
mag160c_shutdown(nullptr);
|
||||
|
||||
assert(mag160c_list_devices(nullptr, nullptr, nullptr) == MAG160C_ERR_INVALID_ARGUMENT);
|
||||
|
||||
ctx = nullptr;
|
||||
assert(mag160c_init(&ctx) == MAG160C_OK);
|
||||
mag160c_device_info_t* devices = reinterpret_cast<mag160c_device_info_t*>(0x1);
|
||||
size_t device_count = 42;
|
||||
#if MAG160C_HAS_LIBUSB
|
||||
assert(mag160c_list_devices(ctx, &devices, &device_count) == MAG160C_OK);
|
||||
mag160c_free_device_list(devices);
|
||||
#else
|
||||
assert(mag160c_list_devices(ctx, &devices, &device_count) == MAG160C_ERR_UNSUPPORTED);
|
||||
assert(devices == nullptr);
|
||||
assert(device_count == 0);
|
||||
assert(std::strstr(mag160c_last_error(), "libusb") != nullptr);
|
||||
mag160c_free_device_list(devices);
|
||||
#endif
|
||||
mag160c_shutdown(ctx);
|
||||
|
||||
const uint8_t payload[] = {0x00, 0x05};
|
||||
const uint8_t expected[] = {
|
||||
0x7e, 0x00, 0x07, 0x85, 0x02, 0x77, 0x00, 0x01, 0x00, 0x05, 0x7f};
|
||||
|
||||
size_t encoded_size = 0;
|
||||
assert(mag160c_tcm_encode_frame(0x02, 0x77, 0x0001, payload, sizeof(payload), nullptr, 0,
|
||||
&encoded_size) == MAG160C_ERR_INVALID_ARGUMENT);
|
||||
assert(encoded_size == sizeof(expected));
|
||||
|
||||
uint8_t encoded[sizeof(expected)] = {};
|
||||
assert(mag160c_tcm_encode_frame(0x02, 0x77, 0x0001, payload, sizeof(payload), encoded,
|
||||
sizeof(encoded), &encoded_size) == MAG160C_OK);
|
||||
assert(encoded_size == sizeof(expected));
|
||||
assert(std::memcmp(encoded, expected, sizeof(expected)) == 0);
|
||||
|
||||
uint8_t main_cmd = 0;
|
||||
uint8_t sub_cmd = 0;
|
||||
uint16_t frame_id = 0;
|
||||
size_t payload_size = 0;
|
||||
assert(mag160c_tcm_decode_header(encoded, encoded_size, &main_cmd, &sub_cmd, &frame_id,
|
||||
&payload_size) == MAG160C_OK);
|
||||
assert(main_cmd == 0x02);
|
||||
assert(sub_cmd == 0x77);
|
||||
assert(frame_id == 0x0001);
|
||||
assert(payload_size == sizeof(payload));
|
||||
|
||||
size_t rotate_size = 0;
|
||||
assert(mag160c_tcm_build_rotate_frame(5, nullptr, 0, &rotate_size) ==
|
||||
MAG160C_ERR_INVALID_ARGUMENT);
|
||||
assert(rotate_size == sizeof(expected));
|
||||
|
||||
uint8_t rotate_frame[sizeof(expected)] = {};
|
||||
assert(mag160c_tcm_build_rotate_frame(5, rotate_frame, sizeof(rotate_frame), &rotate_size) ==
|
||||
MAG160C_OK);
|
||||
assert(rotate_size == sizeof(expected));
|
||||
assert(std::memcmp(rotate_frame, expected, sizeof(expected)) == 0);
|
||||
|
||||
const uint8_t expected_green_blink[] = {
|
||||
0x7e, 0x00, 0x09, 0x87, 0x02, 0x32, 0x00, 0x01, 0x01, 0x00, 0xff, 0x00, 0x35};
|
||||
size_t light_size = 0;
|
||||
uint8_t light_frame[sizeof(expected_green_blink)] = {};
|
||||
assert(mag160c_tcm_build_light_frame(MAG160C_TCM_LIGHT_GREEN, MAG160C_TCM_LIGHT_BLINK,
|
||||
light_frame, sizeof(light_frame), &light_size) ==
|
||||
MAG160C_OK);
|
||||
assert(light_size == sizeof(expected_green_blink));
|
||||
assert(std::memcmp(light_frame, expected_green_blink, sizeof(expected_green_blink)) == 0);
|
||||
|
||||
assert(mag160c_tcm_build_light_frame(static_cast<mag160c_tcm_light_color_t>(99),
|
||||
MAG160C_TCM_LIGHT_BLINK, light_frame,
|
||||
sizeof(light_frame), &light_size) ==
|
||||
MAG160C_ERR_INVALID_ARGUMENT);
|
||||
assert(std::strstr(mag160c_last_error(), "color") != nullptr);
|
||||
|
||||
const std::vector<uint8_t> oversized_payload(65531U, 0xaa);
|
||||
encoded_size = 123U;
|
||||
assert(mag160c_tcm_encode_frame(0x02, 0x77, 0x0001, oversized_payload.data(),
|
||||
oversized_payload.size(), nullptr, 0, &encoded_size) ==
|
||||
MAG160C_ERR_INVALID_ARGUMENT);
|
||||
assert(encoded_size == 0);
|
||||
assert(std::strstr(mag160c_last_error(), "too large") != nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "core/device.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
int main() {
|
||||
using mag160c::core::EndpointDescriptor;
|
||||
using mag160c::core::EndpointPair;
|
||||
using mag160c::core::EndpointType;
|
||||
|
||||
const std::vector<EndpointDescriptor> endpoints = {
|
||||
{0x01, EndpointType::Interrupt},
|
||||
{0x82, EndpointType::Bulk},
|
||||
{0x03, EndpointType::Bulk},
|
||||
};
|
||||
|
||||
EndpointPair pair{};
|
||||
assert(mag160c::core::find_bulk_pair(endpoints, &pair));
|
||||
assert(pair.bulk_in == 0x82);
|
||||
assert(pair.bulk_out == 0x03);
|
||||
|
||||
const std::vector<EndpointDescriptor> missing_out = {
|
||||
{0x82, EndpointType::Bulk},
|
||||
};
|
||||
|
||||
pair = {};
|
||||
assert(!mag160c::core::find_bulk_pair(missing_out, &pair));
|
||||
assert(!mag160c::core::find_bulk_pair(endpoints, nullptr));
|
||||
|
||||
assert(mag160c::core::is_in_endpoint(0x82));
|
||||
assert(!mag160c::core::is_in_endpoint(0x03));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
#include "core/ir_frame.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
void test_parse_valid_frame() {
|
||||
// 2x1 frame: marker + counter + len + type + shutter + 2 pixels + trailing marker + tail
|
||||
std::vector<uint8_t> data(0x38 + 4, 0xaa);
|
||||
auto w32 = [&](size_t off, uint32_t v) {
|
||||
data[off] = static_cast<uint8_t>(v);
|
||||
data[off + 1] = static_cast<uint8_t>(v >> 8);
|
||||
data[off + 2] = static_cast<uint8_t>(v >> 16);
|
||||
data[off + 3] = static_cast<uint8_t>(v >> 24);
|
||||
};
|
||||
w32(0x00, 0x1bb1b11b);
|
||||
w32(0x04, 42);
|
||||
w32(0x08, 4); // data_length
|
||||
w32(0x0c, 1); // raw frame type
|
||||
w32(0x10, 1000); // shutter
|
||||
data[0x1c] = 0x34;
|
||||
data[0x1d] = 0x12;
|
||||
data[0x1e] = 0x78;
|
||||
data[0x1f] = 0x56;
|
||||
w32(0x1c + 4, 0x1bb1b11c);
|
||||
|
||||
mag160c::core::IrFrameHeader h{};
|
||||
const uint16_t* pixels = nullptr;
|
||||
assert(mag160c::core::parse_ir_frame(data.data(), data.size(), &h, &pixels) == MAG160C_OK);
|
||||
assert(h.marker == 0x1bb1b11b);
|
||||
assert(h.frame_counter == 42);
|
||||
assert(h.data_length == 4);
|
||||
assert(h.frame_type == 1);
|
||||
assert(h.period_shutter == 1000);
|
||||
assert(pixels[0] == 0x1234);
|
||||
assert(pixels[1] == 0x5678);
|
||||
}
|
||||
|
||||
void test_parse_rejects_bad_marker() {
|
||||
std::vector<uint8_t> data(0x40, 0);
|
||||
data[0] = 0xab;
|
||||
|
||||
mag160c::core::IrFrameHeader h{};
|
||||
const uint16_t* pixels = nullptr;
|
||||
assert(mag160c::core::parse_ir_frame(data.data(), data.size(), &h, &pixels) ==
|
||||
MAG160C_ERR_PROTOCOL_UNKNOWN);
|
||||
}
|
||||
|
||||
void test_parse_rejects_bad_type_and_trailer() {
|
||||
std::vector<uint8_t> data(0x40, 0);
|
||||
auto w32 = [&](size_t off, uint32_t v) {
|
||||
data[off] = static_cast<uint8_t>(v);
|
||||
data[off + 1] = static_cast<uint8_t>(v >> 8);
|
||||
data[off + 2] = static_cast<uint8_t>(v >> 16);
|
||||
data[off + 3] = static_cast<uint8_t>(v >> 24);
|
||||
};
|
||||
w32(0x00, 0x1bb1b11b);
|
||||
w32(0x08, 4);
|
||||
w32(0x0c, 2); // invalid type
|
||||
mag160c::core::IrFrameHeader h{};
|
||||
const uint16_t* pixels = nullptr;
|
||||
assert(mag160c::core::parse_ir_frame(data.data(), data.size(), &h, &pixels) ==
|
||||
MAG160C_ERR_PROTOCOL_UNKNOWN);
|
||||
|
||||
w32(0x0c, 0);
|
||||
w32(0x1c + 4, 0xdeadbeef); // bad trailing marker
|
||||
assert(mag160c::core::parse_ir_frame(data.data(), data.size(), &h, &pixels) ==
|
||||
MAG160C_ERR_PROTOCOL_UNKNOWN);
|
||||
}
|
||||
|
||||
void test_calibrate_flat_band() {
|
||||
// 4 pixels, 2 bands (1 search threshold), threshold = {5} per pixel
|
||||
const std::vector<uint16_t> frame{1000, 2000, 3000, 4000};
|
||||
const std::vector<int16_t> thresholds{5, 5, 5, 5};
|
||||
// per band per pixel {coeff, offset}: band0 = {0, 100}, band1 = {0, 200}
|
||||
const std::vector<uint16_t> coeff{
|
||||
0, 100, 0, 100, 0, 100, 0, 100,
|
||||
0, 200, 0, 200, 0, 200, 0, 200,
|
||||
};
|
||||
|
||||
mag160c::core::IrCalibrationTables tables{};
|
||||
tables.thresholds = thresholds.data();
|
||||
tables.coeff = coeff.data();
|
||||
tables.pixel_count = 4;
|
||||
tables.band_count = 2;
|
||||
tables.baseline = nullptr;
|
||||
tables.has_baseline = false;
|
||||
|
||||
std::vector<uint16_t> out(4);
|
||||
mag160c::core::calibrate_frame(frame.data(), tables, out.data());
|
||||
|
||||
// diff = frame >> 1 = 500..2000, all > 5 → band 1 → offset 200
|
||||
for (auto v : out) {
|
||||
assert(v == 200);
|
||||
}
|
||||
}
|
||||
|
||||
void test_calibrate_interpolation_and_clamp() {
|
||||
// 2 pixels, 2 bands, threshold = {500}
|
||||
const std::vector<uint16_t> frame{2000, 0x8000};
|
||||
const std::vector<uint16_t> baseline{0, 0x100};
|
||||
const std::vector<int16_t> thresholds{500, 500};
|
||||
// band0: {coeff=0x1000 (4096), offset=1000}; band1: {coeff=0x100, offset=2000}
|
||||
const std::vector<uint16_t> coeff{
|
||||
0x1000, 1000, 0x1000, 1000,
|
||||
0x0100, 2000, 0x0100, 2000,
|
||||
};
|
||||
|
||||
mag160c::core::IrCalibrationTables tables{};
|
||||
tables.thresholds = thresholds.data();
|
||||
tables.coeff = coeff.data();
|
||||
tables.pixel_count = 2;
|
||||
tables.band_count = 2;
|
||||
tables.baseline = baseline.data();
|
||||
tables.has_baseline = true;
|
||||
|
||||
std::vector<uint16_t> out(2);
|
||||
mag160c::core::calibrate_frame(frame.data(), tables, out.data());
|
||||
|
||||
// pixel 0: diff = (2000-0)>>1 = 1000 > 500 → band1: 2000 + (1000*0x100 >> 12) = 2000 + 62
|
||||
assert(out[0] == 2062);
|
||||
// pixel 1: diff = (0x8000-0x100)>>1 = 0x3f80 (16256) > 500 → band1: 2000 + (16256*256 >> 12)
|
||||
// = 2000 + 1016 = 3016
|
||||
assert(out[1] == 3016);
|
||||
}
|
||||
|
||||
void test_calibrate_negative_diff_zero() {
|
||||
const std::vector<uint16_t> frame{100};
|
||||
const std::vector<uint16_t> baseline{200};
|
||||
const std::vector<int16_t> thresholds{5};
|
||||
const std::vector<uint16_t> coeff{0x1000, 1000, 0x1000, 1000};
|
||||
|
||||
mag160c::core::IrCalibrationTables tables{};
|
||||
tables.thresholds = thresholds.data();
|
||||
tables.coeff = coeff.data();
|
||||
tables.pixel_count = 1;
|
||||
tables.band_count = 2;
|
||||
tables.baseline = baseline.data();
|
||||
tables.has_baseline = true;
|
||||
|
||||
std::vector<uint16_t> out(1);
|
||||
mag160c::core::calibrate_frame(frame.data(), tables, out.data());
|
||||
|
||||
// diff = (int16)(100-200) >> 1 = -50; negative coeff*offset path clamps to >= 0:
|
||||
// band0 (diff <= 5): 1000 + (-50 * 4096 >> 12) = 1000 - 50 = 950
|
||||
assert(out[0] == 950);
|
||||
}
|
||||
|
||||
void test_parse_rejects_truncated_frame() {
|
||||
std::vector<uint8_t> data(0x38 + 4, 0);
|
||||
auto w32 = [&](size_t off, uint32_t v) {
|
||||
data[off] = static_cast<uint8_t>(v);
|
||||
data[off + 1] = static_cast<uint8_t>(v >> 8);
|
||||
data[off + 2] = static_cast<uint8_t>(v >> 16);
|
||||
data[off + 3] = static_cast<uint8_t>(v >> 24);
|
||||
};
|
||||
w32(0x00, 0x1bb1b11b);
|
||||
w32(0x08, 4);
|
||||
|
||||
mag160c::core::IrFrameHeader h{};
|
||||
const uint16_t* pixels = nullptr;
|
||||
data.resize(data.size() - 1); // truncate
|
||||
assert(mag160c::core::parse_ir_frame(data.data(), data.size(), &h, &pixels) ==
|
||||
MAG160C_ERR_PROTOCOL_UNKNOWN);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
test_parse_valid_frame();
|
||||
test_parse_rejects_bad_marker();
|
||||
test_parse_rejects_bad_type_and_trailer();
|
||||
test_parse_rejects_truncated_frame();
|
||||
test_calibrate_flat_band();
|
||||
test_calibrate_interpolation_and_clamp();
|
||||
test_calibrate_negative_diff_zero();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "mag160c/mag160c.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
int main() {
|
||||
assert(mag160c_ir_open_first(nullptr, nullptr) == MAG160C_ERR_INVALID_ARGUMENT);
|
||||
assert(std::strstr(mag160c_last_error(), "ctx") != nullptr);
|
||||
|
||||
mag160c_ir_close(nullptr);
|
||||
|
||||
assert(mag160c_ir_get_info(nullptr, nullptr) == MAG160C_ERR_INVALID_ARGUMENT);
|
||||
assert(std::strstr(mag160c_last_error(), "device") != nullptr);
|
||||
|
||||
mag160c_context_t* ctx = nullptr;
|
||||
assert(mag160c_init(&ctx) == MAG160C_OK);
|
||||
|
||||
mag160c_ir_device_t* ir = nullptr;
|
||||
assert(mag160c_ir_open_first(ctx, &ir) == MAG160C_OK);
|
||||
assert(ir != nullptr);
|
||||
|
||||
mag160c_ir_info_t info{};
|
||||
assert(mag160c_ir_get_info(ir, &info) == MAG160C_OK);
|
||||
assert(info.width == 160);
|
||||
assert(info.height == 120);
|
||||
assert(info.output_width == 160);
|
||||
assert(info.output_height == 120);
|
||||
assert(info.max_fps == 25);
|
||||
assert(info.current_fps == 0);
|
||||
assert(std::strcmp(info.name, "MAG160C") == 0);
|
||||
assert(std::strcmp(info.type, "vendor-bulk-ir") == 0);
|
||||
|
||||
assert(mag160c_ir_trigger_ffc(ir) == MAG160C_ERR_UNSUPPORTED);
|
||||
assert(std::strstr(mag160c_last_error(), "0x6bb6b672") != nullptr);
|
||||
assert(std::strstr(mag160c_last_error(), "0x03") != nullptr);
|
||||
|
||||
size_t raw_size = 123;
|
||||
assert(mag160c_ir_read_raw_once(ir, nullptr, 0, &raw_size, 100) ==
|
||||
MAG160C_ERR_UNSUPPORTED);
|
||||
assert(raw_size == 0);
|
||||
assert(std::strstr(mag160c_last_error(), "0x1bb1b11b") != nullptr);
|
||||
|
||||
mag160c_ir_close(ir);
|
||||
mag160c_shutdown(ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "core/tcm_device.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
void test_rotate_positive_payload() {
|
||||
mag160c::core::TcmCommandBuilder builder;
|
||||
const std::vector<uint8_t> expected{
|
||||
0x7e, 0x00, 0x07, 0x85, 0x02, 0x77, 0x00, 0x01, 0x00, 0x05, 0x7f};
|
||||
|
||||
const auto encoded = builder.build_rotate_frame(5);
|
||||
|
||||
assert(encoded == expected);
|
||||
}
|
||||
|
||||
void test_rotate_negative_payload_and_frame_increment() {
|
||||
mag160c::core::TcmCommandBuilder builder;
|
||||
(void)builder.build_rotate_frame(5);
|
||||
|
||||
const std::vector<uint8_t> expected{
|
||||
0x7e, 0x00, 0x07, 0x85, 0x02, 0x77, 0x00, 0x02, 0x01, 0x03, 0x7f};
|
||||
|
||||
const auto encoded = builder.build_rotate_frame(-3);
|
||||
|
||||
assert(encoded == expected);
|
||||
}
|
||||
|
||||
void test_green_blink_payload() {
|
||||
mag160c::core::TcmCommandBuilder builder;
|
||||
const std::vector<uint8_t> expected{
|
||||
0x7e, 0x00, 0x09, 0x87, 0x02, 0x32, 0x00, 0x01, 0x01, 0x00, 0xff, 0x00, 0x35};
|
||||
|
||||
const auto encoded = builder.build_light_frame(MAG160C_TCM_LIGHT_GREEN, MAG160C_TCM_LIGHT_BLINK);
|
||||
|
||||
assert(encoded == expected);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
test_rotate_positive_payload();
|
||||
test_rotate_negative_payload_and_frame_increment();
|
||||
test_green_blink_payload();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#include "core/tcm_frame.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
void test_rotate_frame_encoding() {
|
||||
const std::vector<uint8_t> payload{0x00, 0x05};
|
||||
const std::vector<uint8_t> expected{
|
||||
0x7e, 0x00, 0x07, 0x85, 0x02, 0x77, 0x00, 0x01, 0x00, 0x05, 0x7f};
|
||||
|
||||
const auto encoded = mag160c::core::encode_tcm_frame(0x02, 0x77, 0x0001, payload);
|
||||
|
||||
assert(encoded == expected);
|
||||
}
|
||||
|
||||
void test_decode_rejects_bad_header_checksum() {
|
||||
auto encoded = mag160c::core::encode_tcm_frame(0x02, 0x77, 0x0001, {0x00, 0x05});
|
||||
encoded[3] ^= 0xff;
|
||||
|
||||
mag160c::core::TcmFrame decoded;
|
||||
assert(mag160c::core::decode_tcm_frame(encoded.data(), encoded.size(), &decoded) ==
|
||||
MAG160C_ERR_CHECKSUM);
|
||||
}
|
||||
|
||||
void test_decode_roundtrip() {
|
||||
const std::vector<uint8_t> payload{0x10, 0x20, 0x30};
|
||||
const auto encoded = mag160c::core::encode_tcm_frame(0xa1, 0xb2, 0xc3d4, payload);
|
||||
|
||||
mag160c::core::TcmFrame decoded;
|
||||
assert(mag160c::core::decode_tcm_frame(encoded.data(), encoded.size(), &decoded) == MAG160C_OK);
|
||||
|
||||
assert(decoded.main_cmd == 0xa1);
|
||||
assert(decoded.sub_cmd == 0xb2);
|
||||
assert(decoded.frame_id == 0xc3d4);
|
||||
assert(decoded.payload == payload);
|
||||
}
|
||||
|
||||
void test_encode_rejects_oversized_payload() {
|
||||
const std::vector<uint8_t> payload(65531U, 0xaa);
|
||||
|
||||
bool threw_length_error = false;
|
||||
try {
|
||||
(void)mag160c::core::encode_tcm_frame(0x02, 0x77, 0x0001, payload);
|
||||
} catch (const std::length_error&) {
|
||||
threw_length_error = true;
|
||||
}
|
||||
|
||||
assert(threw_length_error);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
test_rotate_frame_encoding();
|
||||
test_decode_rejects_bad_header_checksum();
|
||||
test_decode_roundtrip();
|
||||
test_encode_rejects_oversized_payload();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user