Giới thiệu
JSON hiện diện khắp nơi - từ dịch vụ web đến IoT. Nhưng có một vấn đề: hầu hết các thư viện JSON phổ biến được viết với mục đích cho máy tính để bàn và máy chủ, nơi mà không ai quan tâm đến việc thừa ra vài megabyte. Trên các vi điều khiển, đặc biệt là các thiết bị Cortex-M, từng byte và từng mili giây đều rất quý giá.
Dĩ nhiên, bạn có thể truyền các cấu trúc C thô và thậm chí ghi chúng trực tiếp vào một tệp cấu hình. Cách này hoạt động, nhưng việc gỡ lỗi trở thành một cuộc chiến đau đớn.
Tại một thời điểm, tôi đã chán ngấy với việc vật lộn với JSON trên STM32: viết mã boilerplate vô tận để đi qua các cây cJSON, săn lùng rò rỉ bộ nhớ và đoán xem malloc sẽ phản bội tôi ở đâu tiếp theo. Đó là khi JsonX ra đời - một lớp bọc nhẹ, tối giản quanh cJSON, được thiết kế đặc biệt cho các vi điều khiển và hệ điều hành thời gian thực (RTOS).
Những gì JsonX mang đến
- Ánh xạ tự động giữa JSON và cấu trúc C thông qua mô tả phẳng
JX_ELEMENT[]. - Kiểm soát bộ nhớ: không cần heap (baremetal) hoặc sử dụng bộ cấp phát của RTOS (ThreadX/FreeRTOS).
- Cấu hình đơn giản thông qua jx_config.h.
- Giảm bớt mã boilerplate khi đọc/ghi cấu hình và báo cáo.
Tại sao không chỉ sử dụng cJSON?
Đây là một câu hỏi hay. JsonX không thay thế cJSON - nó bổ sung cho nó. Bên trong, cJSON vẫn thực hiện việc phân tích cú pháp và xây dựng cây đối tượng của nó. JsonX thêm vào những gì thường thiếu trong các dự án nhúng:
- Ánh xạ thay vì đi bộ thủ công: mô tả sơ đồ của bạn một lần, JsonX sẽ lo phần còn lại.
- Quản lý bộ nhớ tập trung: tất cả các phân bổ đều thông qua một pool hoặc một bộ cấp phát tùy chỉnh, vì vậy bạn kiểm soát được sự phân mảnh và rò rỉ.
- Tích hợp thân thiện với RTOS: ThreadX, FreeRTOS, baremetal với bộ đệm tĩnh, hoặc thậm chí POSIX với các bộ cấp phát tùy chỉnh.
Tóm lại: bạn giữ lại hệ sinh thái của cJSON, nhưng không phải chịu đựng những cơn đau của malloc/free thô trên các vi điều khiển và không phải viết hàng trăm dòng mã dán lặp đi lặp lại.
Ví dụ
Cấu trúc cấu hình
c
typedef struct { char device_name[32]; uint32_t baudrate; bool debug; } config_t; static config_t config;
Mô tả ánh xạ
c
JX_ELEMENT config_desc[] = { JX_ELEMENT_STR ("device_name", config.device_name), JX_ELEMENT_NUM ("baudrate", config.baudrate), JX_ELEMENT_BOOL("debug", config.debug), JX_ELEMENT_END() };
Phân tích JSON
c
jx_json_to_struct(json_str, config_desc);
Tạo JSON
c
char buffer[256]; jx_struct_to_json(config_desc, buffer, sizeof(buffer), JX_FORMAT_PRETTY);
Giới hạn
- Các số hiện tại là kiểu double (như trong cJSON). Một chế độ int nghiêm ngặt đang được lên kế hoạch.
- Độ dài tên thuộc tính tối đa được cố định thông qua JX_PROPERTY_MAX_SIZE.
- Không có tự động mở rộng mảng phần tử — bạn định nghĩa giới hạn tại thời điểm biên dịch.
Nơi lấy JsonX
- GitHub:
embedmind/JsonX - Ví dụ sử dụng STM32:
src/example.c
Lộ trình
Hiện tại JsonX dựa vào cJSON cho việc phân tích và tạo. Nhưng tôi đang xem xét việc chuyển sang một bộ phân tích tùy chỉnh mà sẽ:
- Làm việc trực tiếp với các pool bộ nhớ (ThreadX block pool, FreeRTOS safe allocator).
- Hoạt động hoàn toàn mà không cần malloc/free.
- Giảm thiểu chi phí và cải thiện độ dự đoán trong các hệ thống hạn chế.
Việc này có diễn ra hay không phụ thuộc vào mức độ nhu cầu từ cộng đồng nhúng.
Kết luận
JsonX là cách để sử dụng cJSON trên các vi điều khiển mà không gặp phải các phân bổ không thể đoán trước và mã dán vô tận. Nó đặc biệt hữu ích trong các dự án mà từng byte và mili giây đều quan trọng — nhưng bạn vẫn muốn JSON dễ làm việc như trên máy tính cá nhân.