Add Angle、ToF、Encoder

This commit is contained in:
renletao
2025-11-13 18:16:14 +08:00
parent efcefa420d
commit 15b8038fbb
18 changed files with 1914 additions and 63 deletions
+16 -35
View File
@@ -1,48 +1,29 @@
# Product Name
# Chain Joystick
## Overview
Chain Joystick is a highprecision Halleffect joystick input node in the M5Stack Chain series.
It supports threeaxis control signal input, including analog inputs for the X and Y axes and a digital button input for the Z axis.
The device adopts a Halleffect joystick, which achieves highprecision control by detecting changes in the magnetic field.
It features a contactless design, high durability, excellent precision, and strong antiinterference capability, ensuring product stability and long service life.
An integrated programmable RGB LED is included for status indication and interactive display.
It is suitable for applications such as humanmachine interaction and robot control.
### SKU:xxx
Description of the product
### SKU: U205
## Related Link
https://docs.m5stack.com/en/products/sku/U205
- [Document & Datasheet](https://docs.m5stack.com/en/unit/product_Link)
## Required Libraries:
- [Adafruit_BMP280_Library](https://github.com/adafruit/Required_Libraries_Link)
## License
- [Product Name- MIT](LICENSE)
## Remaining steps(Editorial Staff Look,After following the steps, remember to delete all the content below)
1. Change [clang format check path](./.github/workflows/clang-format-check.yml#L42-L47).
2. Add License content to [LICENSE](/LICENSE).
3. Change link on line 78 of [bug-report.yml](./.github/ISSUE_TEMPLATE/bug-report.yml#L79).
```cpp
Example
# M5Unit-ENV
# Chain Key
## Overview
Chain Key is a singlebutton input node in the M5Stack Chain series.
The button adopts a hotswappable mechanical keyboard switch design, featuring a tactile Blue switch with a distinct click feel, and also integrates a programmable RGB LED.
It is suitable for applications such as humanmachine interaction and smart home control.
### SKU:U001 & U001-B & U001-C
Contains M5Stack-**UNIT ENV** series related case programs.ENV is an environmental sensor with integrated SHT30 and QMP6988 internally to detect temperature, humidity, and atmospheric pressure data.
### SKU: U206
## Related Link
- [Document & Datasheet](https://docs.m5stack.com/en/unit/envIII)
## Required Libraries:
- [Adafruit_BMP280_Library](https://github.com/adafruit/Adafruit_BMP280_Library)
https://docs.m5stack.com/en/products/sku/U206
## License
- [M5Unit-ENV - MIT](LICENSE)
```
- [MIT](https://github.com/m5stack/M5Chain/blob/main/LICENSE)
+165
View File
@@ -0,0 +1,165 @@
/*
*SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
*SPDX-License-Identifier: MIT
*/
#include "M5Chain.h"
#define TXD_PIN GPIO_NUM_21 // Tx
#define RXD_PIN GPIO_NUM_22 // Rx
Chain M5Chain;
device_list_t *devices_list = NULL;
uint16_t device_nums = 0;
uint8_t operation_status = 0;
chain_status_t chain_status = CHAIN_OK;
uint8_t rgb_test[5][3] = {
{0xFF, 0x00, 0x00}, {0x00, 0xFF, 0x00}, {0x00, 0x00, 0xFF}, {0xFF, 0xFF, 0xFF}, {0x00, 0x00, 0x00},
};
void printDeviceList(device_list_t *devices)
{
if (devices == NULL) {
Serial.println("devices is NULL");
return;
}
Serial.print("devices count: ");
Serial.println(devices->count);
for (uint8_t i = 0; i < devices->count; i++) {
Serial.print("devices ID: ");
Serial.println(devices->devices[i].id);
Serial.print("devices type: ");
Serial.println(devices->devices[i].device_type);
}
}
void setup()
{
Serial.begin(115200);
Serial.println("M5Chain Angle Test");
M5Chain.begin(&Serial2, 115200, RXD_PIN, TXD_PIN);
if (M5Chain.isDeviceConnected()) {
Serial.println("devices is connected");
chain_status = M5Chain.getDeviceNum(&device_nums);
if (chain_status == CHAIN_OK) {
devices_list = (device_list_t *)malloc(sizeof(device_list_t));
devices_list->count = device_nums;
devices_list->devices = (device_info_t *)malloc(sizeof(device_info_t) * device_nums);
if (M5Chain.getDeviceList(devices_list)) {
Serial.println("get devices list success");
printDeviceList(devices_list);
} else {
Serial.println("get devices list failed");
}
} else {
Serial.printf("error status:%d \r\n", chain_status);
Serial.printf("devices num get failed.\r\n");
}
} else {
Serial.println("devices is not connected.");
}
if (devices_list) {
for (uint8_t i = 0; i < devices_list->count; i++) {
if (devices_list->devices[i].device_type == CHAIN_ANGLE_TYPE_CODE) {
chain_status = M5Chain.setRGBLight(devices_list->devices[i].id, 100, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] set rgb light success\r\n", devices_list->devices[i].id);
} else {
Serial.printf("ID[%d] set rgb light failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, chain_status, operation_status);
}
for (uint8_t j = 0; j < 5; j++) {
uint8_t rgb[3] = {0};
chain_status =
M5Chain.setRGBValue(devices_list->devices[i].id, 0, 1, rgb_test[j], 3, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] set rgb %d %d %d success\r\n", devices_list->devices[i].id,
rgb_test[j][0], rgb_test[j][1], rgb_test[j][2]);
} else {
Serial.printf("ID[%d] set rgb %d %d %d failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, rgb_test[j][0], rgb_test[j][1], rgb_test[j][2],
chain_status, operation_status);
}
chain_status = M5Chain.getRGBValue(devices_list->devices[i].id, 0, 1, rgb, 3, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] get rgb %d %d %d success \r\n", devices_list->devices[i].id, rgb[0],
rgb[1], rgb[2]);
} else {
Serial.printf("ID[%d] get rgb %d %d %d failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, rgb[0], rgb[1], rgb[2], chain_status,
operation_status);
}
delay(500);
}
// M5Chain.setAngleRotationDirection(devices_list->devices[i].id, ANGLE_ROTATION_DECREASING,
// &operation_status,
// CHAIN_SAVE_FLASH_ENABLE); // Angle rotation direction decreasing, save to flash
// M5Chain.setAngleRotationDirection(devices_list->devices[i].id, ANGLE_ROTATION_INCREASING,
// &operation_status,
// CHAIN_SAVE_FLASH_ENABLE); // Angle rotation direction increasing, save to flash
// chain_status = M5Chain.setAngleRotationDirection(devices_list->devices[i].id,
// ANGLE_ROTATION_DECREASING,
// &operation_status,
// CHAIN_SAVE_FLASH_DISABLE); // Angle rotation direction decreasing, not save to flash
M5Chain.setAngleRotationDirection(devices_list->devices[i].id, ANGLE_ROTATION_INCREASING,
&operation_status,
CHAIN_SAVE_FLASH_DISABLE); // Angle rotation direction increasing, not save to flash
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("Angle ID[%d] set angle rotation direction success \r\n", devices_list->devices[i].id);
} else {
Serial.printf(
"Angle ID[%d] set angle rotation direction failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, chain_status, operation_status);
}
}
}
} else {
Serial.println("devices list is NULL");
}
}
void loop()
{
if (devices_list) {
for (uint8_t i = 0; i < devices_list->count; i++) {
if (devices_list->devices[i].device_type == CHAIN_ANGLE_TYPE_CODE) {
uint16_t angle12Bit = 0;
uint8_t angle8Bit = 0;
angle_rotation_direction_t angle_rotation_direction;
chain_status = M5Chain.getAngle12BitAdc(devices_list->devices[i].id, &angle12Bit);
if (chain_status == CHAIN_OK) {
Serial.printf("Angle ID[%d] angle12Bit:%d \r\n", devices_list->devices[i].id, angle12Bit);
} else {
Serial.printf("Angle ID[%d] get 12bit adc failed, chain_status:%d \r\n", devices_list->devices[i].id,
chain_status);
}
chain_status = M5Chain.getAngle8BitAdc(devices_list->devices[i].id, &angle8Bit);
if (chain_status == CHAIN_OK) {
Serial.printf("Angle ID[%d] angle8Bit:%d \r\n", devices_list->devices[i].id, angle8Bit);
} else {
Serial.printf("Angle ID[%d] get 8bit adc failed, chain_status:%d \r\n", devices_list->devices[i].id,
chain_status);
}
chain_status =
M5Chain.getAngleRotationDirection(devices_list->devices[i].id, &angle_rotation_direction);
if (chain_status == CHAIN_OK) {
Serial.printf("Angle ID[%d] angle_rotation_direction:%d \r\n", devices_list->devices[i].id,
angle_rotation_direction);
} else {
Serial.printf("Angle ID[%d] get rotation direction failed, chain_status:%d \r\n",
devices_list->devices[i].id, chain_status);
}
}
}
}
delay(100);
}
@@ -0,0 +1,201 @@
/*
*SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
*SPDX-License-Identifier: MIT
*/
#include "M5Chain.h"
#define TXD_PIN GPIO_NUM_21 // Tx
#define RXD_PIN GPIO_NUM_22 // Rx
Chain M5Chain;
device_list_t *devices_list = NULL;
uint16_t device_nums = 0;
uint8_t operation_status = 0;
chain_status_t chain_status = CHAIN_OK;
uint8_t rgb_test[5][3] = {
{0xFF, 0x00, 0x00}, {0x00, 0xFF, 0x00}, {0x00, 0x00, 0xFF}, {0xFF, 0xFF, 0xFF}, {0x00, 0x00, 0x00},
};
void printDeviceList(device_list_t *devices)
{
if (devices == NULL) {
Serial.println("devices is NULL");
return;
}
Serial.print("devices count: ");
Serial.println(devices->count);
for (uint8_t i = 0; i < devices->count; i++) {
Serial.print("devices ID: ");
Serial.println(devices->devices[i].id);
Serial.print("devices type: ");
Serial.println(devices->devices[i].device_type);
}
}
void setup()
{
Serial.begin(115200);
Serial.println("M5Chain Encoder Test");
M5Chain.begin(&Serial2, 115200, RXD_PIN, TXD_PIN);
if (M5Chain.isDeviceConnected()) {
Serial.println("devices is connected");
chain_status = M5Chain.getDeviceNum(&device_nums);
if (chain_status == CHAIN_OK) {
devices_list = (device_list_t *)malloc(sizeof(device_list_t));
devices_list->count = device_nums;
devices_list->devices = (device_info_t *)malloc(sizeof(device_info_t) * device_nums);
if (M5Chain.getDeviceList(devices_list)) {
Serial.println("get devices list success");
printDeviceList(devices_list);
} else {
Serial.println("get devices list failed");
}
} else {
Serial.printf("error status:%d \r\n", chain_status);
Serial.printf("devices num get failed.\r\n");
}
} else {
Serial.println("devices is not connected.");
}
if (devices_list) {
for (uint8_t i = 0; i < devices_list->count; i++) {
if (devices_list->devices[i].device_type == CHAIN_ENCODER_TYPE_CODE) {
chain_status = M5Chain.setRGBLight(devices_list->devices[i].id, 100, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] set rgb light success\r\n", devices_list->devices[i].id);
} else {
Serial.printf("ID[%d] set rgb light failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, chain_status, operation_status);
}
for (uint8_t j = 0; j < 5; j++) {
uint8_t rgb[3] = {0};
chain_status =
M5Chain.setRGBValue(devices_list->devices[i].id, 0, 1, rgb_test[j], 3, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] set rgb %d %d %d success\r\n", devices_list->devices[i].id,
rgb_test[j][0], rgb_test[j][1], rgb_test[j][2]);
} else {
Serial.printf("ID[%d] set rgb %d %d %d failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, rgb_test[j][0], rgb_test[j][1], rgb_test[j][2],
chain_status, operation_status);
}
chain_status = M5Chain.getRGBValue(devices_list->devices[i].id, 0, 1, rgb, 3, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] get rgb %d %d %d success \r\n", devices_list->devices[i].id, rgb[0],
rgb[1], rgb[2]);
} else {
Serial.printf("ID[%d] get rgb %d %d %d failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, rgb[0], rgb[1], rgb[2], chain_status,
operation_status);
}
delay(500);
}
chain_status =
M5Chain.setKeyButtonTriggerInterval(devices_list->devices[i].id, BUTTON_DOUBLE_CLICK_TIME_200MS,
BUTTON_LONG_PRESS_TIME_3S, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] set key button trigger interval success\r\n", devices_list->devices[i].id);
} else {
Serial.printf(
"ID[%d] set key button trigger interval failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, chain_status, operation_status);
}
chain_status =
M5Chain.setKeyButtonMode(devices_list->devices[i].id, CHAIN_BUTTON_REPORT_MODE, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] set key button mode success\r\n", devices_list->devices[i].id);
} else {
Serial.printf("ID[%d] set key button mode failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, chain_status, operation_status);
}
}
}
} else {
Serial.println("devices list is NULL");
}
}
void loop()
{
if (devices_list) {
for (uint8_t i = 0; i < devices_list->count; i++) {
if (devices_list->devices[i].device_type == CHAIN_ENCODER_TYPE_CODE) {
int16_t encoder = 0;
int16_t inc_encoder = 0;
encoder_ab_t direct;
uint8_t button_status = 0;
button_double_click_time_t button_double_click_time;
button_long_press_time_t button_long_press_time;
chain_button_press_type_t button_press_type;
chain_button_mode_t button_mode;
chain_status = M5Chain.getEncoderValue(devices_list->devices[i].id, &encoder);
if (chain_status == CHAIN_OK) {
Serial.printf("ENCODER ID[%d] encoder:%d \r\n", devices_list->devices[i].id, encoder);
} else {
Serial.printf("ENCODER ID[%d] get encoder status failed, chain_status:%d \r\n",
devices_list->devices[i].id, chain_status);
}
chain_status = M5Chain.getEncoderIncValue(devices_list->devices[i].id, &inc_encoder);
if (chain_status == CHAIN_OK) {
Serial.printf("ENCODER ID[%d] inc encoder:%d \r\n", devices_list->devices[i].id, inc_encoder);
} else {
Serial.printf("ENCODER ID[%d] get inc encoder status failed, chain_status:%d \r\n",
devices_list->devices[i].id, chain_status);
}
chain_status = M5Chain.getEncoderABDirect(devices_list->devices[i].id, &direct);
if (chain_status == CHAIN_OK) {
Serial.printf("ENCODER ID[%d] ab direct:%d \r\n", devices_list->devices[i].id, direct);
} else {
Serial.printf("ENCODER ID[%d] get direct status failed, chain_status:%d \r\n",
devices_list->devices[i].id, chain_status);
}
chain_status = M5Chain.getEncoderButtonStatus(devices_list->devices[i].id, &button_status);
if (chain_status == CHAIN_OK) {
Serial.printf("ENCODER ID[%d] button status:%d \r\n", devices_list->devices[i].id, button_status);
} else {
Serial.printf("ENCODER ID[%d] get button status failed, chain_status:%d \r\n",
devices_list->devices[i].id, chain_status);
}
chain_status = M5Chain.getEncoderButtonTriggerInterval(
devices_list->devices[i].id, &button_double_click_time, &button_long_press_time);
if (chain_status == CHAIN_OK) {
Serial.printf("ENCODER ID[%d] button double click time:%d, button long press time:%d \r\n",
devices_list->devices[i].id, button_double_click_time, button_long_press_time);
} else {
Serial.printf("ENCODER ID[%d] get button trigger interval failed, chain_status:%d \r\n",
devices_list->devices[i].id, chain_status);
}
chain_status = M5Chain.getEncoderButtonMode(devices_list->devices[i].id, &button_mode);
if (chain_status == CHAIN_OK) {
Serial.printf("ENCODER ID[%d] button mode:%d \r\n", devices_list->devices[i].id, button_mode);
} else {
Serial.printf("ENCODER ID[%d] get button mode failed, chain_status:%d \r\n",
devices_list->devices[i].id, chain_status);
}
while (M5Chain.getEncoderButtonPressStatus(devices_list->devices[i].id, &button_press_type)) {
switch (button_press_type) {
case CHAIN_BUTTON_PRESS_SINGLE:
Serial.printf("ENCODER ID[%d] button press type: single \r\n", devices_list->devices[i].id);
break;
case CHAIN_BUTTON_PRESS_DOUBLE:
Serial.printf("ENCODER ID[%d] button press type: double \r\n", devices_list->devices[i].id);
break;
case CHAIN_BUTTON_PRESS_LONG:
Serial.printf("ENCODER ID[%d] button press type: long \r\n", devices_list->devices[i].id);
break;
}
}
}
}
}
delay(100);
}
@@ -0,0 +1,174 @@
/*
*SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
*SPDX-License-Identifier: MIT
*/
#include "M5Chain.h"
#define TXD_PIN GPIO_NUM_21 // Tx
#define RXD_PIN GPIO_NUM_22 // Rx
Chain M5Chain;
device_list_t *devices_list;
uint16_t device_nums = 0;
uint8_t operation_status = 0;
chain_status_t chain_status = CHAIN_OK;
uint8_t rgb_test[5][3] = {
{0xFF, 0x00, 0x00}, {0x00, 0xFF, 0x00}, {0x00, 0x00, 0xFF}, {0xFF, 0xFF, 0xFF}, {0x00, 0x00, 0x00},
};
void printDeviceList(device_list_t *devices)
{
if (devices == NULL) {
Serial.println("devices is NULL");
return;
}
Serial.print("devices count: ");
Serial.println(devices->count);
for (uint8_t i = 0; i < devices->count; i++) {
Serial.print("devices ID: ");
Serial.println(devices->devices[i].id);
Serial.print("devices type: ");
Serial.println(devices->devices[i].device_type);
}
}
void setup()
{
Serial.begin(115200);
Serial.println("M5Chain ToF Test");
M5Chain.begin(&Serial2, 115200, RXD_PIN, TXD_PIN);
if (M5Chain.isDeviceConnected()) {
Serial.println("devices is connected");
chain_status = M5Chain.getDeviceNum(&device_nums);
if (chain_status == CHAIN_OK) {
devices_list = (device_list_t *)malloc(sizeof(device_list_t));
devices_list->count = device_nums;
devices_list->devices = (device_info_t *)malloc(sizeof(device_info_t) * device_nums);
if (M5Chain.getDeviceList(devices_list)) {
Serial.println("devices list get success");
printDeviceList(devices_list);
} else {
Serial.println("devices list get failed");
}
} else {
Serial.printf("error status:%d \r\n", chain_status);
Serial.printf("devices num get failed.\r\n");
}
} else {
Serial.println("devices is not connected.");
}
if (devices_list) {
for (uint8_t i = 0; i < devices_list->count; i++) {
if (devices_list->devices[i].device_type == CHAIN_TOF_TYPE_CODE) {
chain_status = M5Chain.setRGBLight(devices_list->devices[i].id, 100, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] set rgb light success\r\n", devices_list->devices[i].id);
} else {
Serial.printf("ID[%d] set rgb light failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, chain_status, operation_status);
}
for (uint8_t j = 0; j < 5; j++) {
uint8_t rgb[3] = {0};
chain_status =
M5Chain.setRGBValue(devices_list->devices[i].id, 0, 1, rgb_test[j], 3, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] set rgb %d %d %d success\r\n", devices_list->devices[i].id,
rgb_test[j][0], rgb_test[j][1], rgb_test[j][2]);
} else {
Serial.printf("ID[%d] set rgb %d %d %d failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, rgb_test[j][0], rgb_test[j][1], rgb_test[j][2],
chain_status, operation_status);
}
chain_status = M5Chain.getRGBValue(devices_list->devices[i].id, 0, 1, rgb, 3, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] get rgb %d %d %d success \r\n", devices_list->devices[i].id, rgb[0],
rgb[1], rgb[2]);
} else {
Serial.printf("ID[%d] get rgb %d %d %d failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, rgb[0], rgb[1], rgb[2], chain_status,
operation_status);
}
delay(500);
}
// 设置测量模式
chain_status = M5Chain.setToFMeasureMode(devices_list->devices[i].id, CHAIN_TOF_MODE_CONTINUOUS,
&operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("TOF ID[%d] set measure mode CONTINUOUS success\r\n", devices_list->devices[i].id);
} else {
Serial.printf(
"TOF ID[%d] set measure mode CONTINUOUS failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, chain_status, operation_status);
}
// 设置测量时间
uint8_t measurement_time = 33; // ms
chain_status =
M5Chain.setToFMeasureTime(devices_list->devices[i].id, measurement_time, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("TOF ID[%d] set measurement_time %d success\r\n", devices_list->devices[i].id,
measurement_time);
} else {
Serial.printf(
"TOF ID[%d] set measurement_time %d failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, measurement_time, chain_status, operation_status);
}
}
}
} else {
Serial.println("devices list is NULL");
}
}
void loop()
{
if (devices_list) {
for (uint8_t i = 0; i < devices_list->count; i++) {
if (devices_list->devices[i].device_type == CHAIN_TOF_TYPE_CODE) {
uint16_t distance = 0;
uint8_t measurement_time = 0;
chain_tof_mode_t mode;
chain_tof_measure_status_t measure_status;
chain_status = M5Chain.getToFDistance(devices_list->devices[i].id, &distance);
if (chain_status == CHAIN_OK) {
Serial.printf("TOF ID[%d] distance:%d \r\n", devices_list->devices[i].id, distance);
} else {
Serial.printf("TOF ID[%d] get distance failed, chain_status:%d \r\n", devices_list->devices[i].id,
chain_status);
}
chain_status = M5Chain.getToFMeasureTime(devices_list->devices[i].id, &measurement_time);
if (chain_status == CHAIN_OK) {
Serial.printf("TOF ID[%d] measurement_time:%d \r\n", devices_list->devices[i].id, measurement_time);
} else {
Serial.printf("TOF ID[%d] get measurement_time failed, chain_status:%d \r\n",
devices_list->devices[i].id, chain_status);
}
chain_status = M5Chain.getToFMeasureMode(devices_list->devices[i].id, &mode);
if (chain_status == CHAIN_OK) {
Serial.printf("TOF ID[%d] mode:%d \r\n", devices_list->devices[i].id, mode);
} else {
Serial.printf("TOF ID[%d] get mode failed, chain_status:%d \r\n", devices_list->devices[i].id,
chain_status);
}
chain_status = M5Chain.getToFMeasureStatus(devices_list->devices[i].id, &measure_status);
if (chain_status == CHAIN_OK) {
Serial.printf("TOF ID[%d] measure_status:%d \r\n", devices_list->devices[i].id, measure_status);
} else {
Serial.printf("TOF ID[%d] get measure_status failed, chain_status:%d \r\n",
devices_list->devices[i].id, chain_status);
}
}
}
}
delay(100);
}
+215
View File
@@ -0,0 +1,215 @@
/*
*SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
*SPDX-License-Identifier: MIT
*/
#include "M5Chain.h"
#define TXD_PIN GPIO_NUM_21 // Tx
#define RXD_PIN GPIO_NUM_22 // Rx
Chain M5Chain;
device_list_t *devices_list;
uint16_t device_nums = 0;
uint8_t operation_status = 0;
chain_status_t chain_status = CHAIN_OK;
uint8_t rgb_test[5][3] = {
{0xFF, 0x00, 0x00}, {0x00, 0xFF, 0x00}, {0x00, 0x00, 0xFF}, {0xFF, 0xFF, 0xFF}, {0x00, 0x00, 0x00},
};
void printDeviceList(device_list_t *devices)
{
if (devices == NULL) {
Serial.println("devices is NULL");
return;
}
Serial.print("devices count: ");
Serial.println(devices->count);
for (uint8_t i = 0; i < devices->count; i++) {
Serial.print("devices ID: ");
Serial.println(devices->devices[i].id);
Serial.print("devices type: ");
Serial.println(devices->devices[i].device_type);
}
}
void setup()
{
Serial.begin(115200);
Serial.println("M5Chain ToF Test");
M5Chain.begin(&Serial2, 115200, RXD_PIN, TXD_PIN);
if (M5Chain.isDeviceConnected()) {
Serial.println("devices is connected");
chain_status = M5Chain.getDeviceNum(&device_nums);
if (chain_status == CHAIN_OK) {
devices_list = (device_list_t *)malloc(sizeof(device_list_t));
devices_list->count = device_nums;
devices_list->devices = (device_info_t *)malloc(sizeof(device_info_t) * device_nums);
if (M5Chain.getDeviceList(devices_list)) {
Serial.println("devices list get success");
printDeviceList(devices_list);
} else {
Serial.println("devices list get failed");
}
} else {
Serial.printf("error status:%d \r\n", chain_status);
Serial.printf("devices num get failed.\r\n");
}
} else {
Serial.println("devices is not connected.");
}
if (devices_list) {
for (uint8_t i = 0; i < devices_list->count; i++) {
if (devices_list->devices[i].device_type == CHAIN_TOF_TYPE_CODE) {
chain_status = M5Chain.setRGBLight(devices_list->devices[i].id, 100, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] set rgb light success\r\n", devices_list->devices[i].id);
} else {
Serial.printf("ID[%d] set rgb light failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, chain_status, operation_status);
}
for (uint8_t j = 0; j < 5; j++) {
uint8_t rgb[3] = {0};
chain_status =
M5Chain.setRGBValue(devices_list->devices[i].id, 0, 1, rgb_test[j], 3, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] set rgb %d %d %d success\r\n", devices_list->devices[i].id,
rgb_test[j][0], rgb_test[j][1], rgb_test[j][2]);
} else {
Serial.printf("ID[%d] set rgb %d %d %d failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, rgb_test[j][0], rgb_test[j][1], rgb_test[j][2],
chain_status, operation_status);
}
chain_status = M5Chain.getRGBValue(devices_list->devices[i].id, 0, 1, rgb, 3, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("ID[%d] get rgb %d %d %d success \r\n", devices_list->devices[i].id, rgb[0],
rgb[1], rgb[2]);
} else {
Serial.printf("ID[%d] get rgb %d %d %d failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, rgb[0], rgb[1], rgb[2], chain_status,
operation_status);
}
delay(500);
}
// 设置测量模式
chain_status =
M5Chain.setToFMeasureMode(devices_list->devices[i].id, CHAIN_TOF_MODE_SINGLE, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("TOF ID[%d] set measure mode SINGLE success\r\n", devices_list->devices[i].id);
} else {
Serial.printf(
"TOF ID[%d] set measure mode SINGLE failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, chain_status, operation_status);
}
// 设置测量时间
uint8_t measurement_time = 33; // ms
chain_status =
M5Chain.setToFMeasureTime(devices_list->devices[i].id, measurement_time, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("TOF ID[%d] set measurement_time %d success\r\n", devices_list->devices[i].id,
measurement_time);
} else {
Serial.printf(
"TOF ID[%d] set measurement_time %d failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, measurement_time, chain_status, operation_status);
}
// 设置测量状态,单次测量必须手运触发
chain_status =
M5Chain.setToFMeasureStatus(devices_list->devices[i].id, CHAIN_TOF_STATUS_START, &operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("TOF ID[%d] set measure status START success\r\n", devices_list->devices[i].id);
} else {
Serial.printf(
"TOF ID[%d] set measure status START failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, chain_status, operation_status);
}
}
}
} else {
Serial.println("devices list is NULL");
}
}
void loop()
{
if (devices_list) {
for (uint8_t i = 0; i < devices_list->count; i++) {
if (devices_list->devices[i].device_type == CHAIN_TOF_TYPE_CODE) {
uint16_t distance = 0;
uint8_t measurement_time = 0;
chain_tof_mode_t mode;
chain_tof_measure_status_t measure_status;
uint8_t complete_flag = 0;
// 读取测量时间
chain_status = M5Chain.getToFMeasureTime(devices_list->devices[i].id, &measurement_time);
if (chain_status == CHAIN_OK) {
Serial.printf("TOF ID[%d] measurement_time:%d \r\n", devices_list->devices[i].id, measurement_time);
} else {
Serial.printf("TOF ID[%d] get measurement_time failed, chain_status:%d \r\n",
devices_list->devices[i].id, chain_status);
}
// 读取测量模式
chain_status = M5Chain.getToFMeasureMode(devices_list->devices[i].id, &mode);
if (chain_status == CHAIN_OK) {
Serial.printf("TOF ID[%d] mode:%d \r\n", devices_list->devices[i].id, mode);
} else {
Serial.printf("TOF ID[%d] get mode failed, chain_status:%d \r\n", devices_list->devices[i].id,
chain_status);
}
// 读取测量状态
chain_status = M5Chain.getToFMeasureStatus(devices_list->devices[i].id, &measure_status);
if (chain_status == CHAIN_OK) {
Serial.printf("TOF ID[%d] measure_status:%d \r\n", devices_list->devices[i].id, measure_status);
} else {
Serial.printf("TOF ID[%d] get measure_status failed, chain_status:%d \r\n",
devices_list->devices[i].id, chain_status);
}
// 读取测量完成标志
chain_status = M5Chain.getToFMeasureCompleteFlag(devices_list->devices[i].id, &complete_flag);
if (chain_status == CHAIN_OK) {
Serial.printf("TOF ID[%d] complete_flag:%d \r\n", devices_list->devices[i].id, complete_flag);
} else {
Serial.printf("TOF ID[%d] get complete_flag failed, chain_status:%d \r\n",
devices_list->devices[i].id, chain_status);
}
// 如果是单次测量模式,且测量完成,则读取距离值,并重新触发测量
if (measure_status == 0 && complete_flag == 1) {
chain_status = M5Chain.getToFDistance(devices_list->devices[i].id, &distance);
if (chain_status == CHAIN_OK) {
Serial.printf("TOF ID[%d] distance:%d \r\n", devices_list->devices[i].id, distance);
} else {
Serial.printf("TOF ID[%d] get distance failed, chain_status:%d \r\n",
devices_list->devices[i].id, chain_status);
}
// 重新触发单次测量
chain_status = M5Chain.setToFMeasureStatus(devices_list->devices[i].id, CHAIN_TOF_STATUS_START,
&operation_status);
if (chain_status == CHAIN_OK && operation_status) {
Serial.printf("TOF ID[%d] set measure status START success\r\n", devices_list->devices[i].id);
} else {
Serial.printf(
"TOF ID[%d] set measure status START failed, chain_status:%d operation_status:%d \r\n",
devices_list->devices[i].id, chain_status, operation_status);
}
}
}
}
delay(100);
}
}
+4 -1
View File
@@ -26,7 +26,10 @@
"-Isrc/Chain",
"-Isrc/ChainCommon",
"-Isrc/ChainJoystick",
"-Isrc/ChainKey"
"-Isrc/ChainKey",
"-Isrc/ChainEncoder",
"-Isrc/ChainAngle",
"-Isrc/ChainToF"
]
},
"headers": [
+5 -4
View File
@@ -1,9 +1,10 @@
name=M5Chain
version=0.0.1
version=1.0.0
author=M5Stack
maintainer=M5Stack
sentence=M5Stack Chain series support library.
paragraph=Library for M5Stack Chain series units.
category=Uncategorized
url=https://github.com/m5stack
architectures=*
category=Device Control
url=https://github.com/m5stack/M5Chain
architectures=*
includes=M5Chain.hpp
+7 -1
View File
@@ -10,10 +10,16 @@
#include "ChainCommon/ChainCommon.hpp"
#include "ChainJoystick/ChainJoystick.hpp"
#include "ChainKey/ChainKey.hpp"
#include "ChainAngle/ChainAngle.hpp"
#include "ChainEncoder/ChainEncoder.hpp"
#include "ChainToF/ChainToF.hpp"
class Chain : virtual public ChainCommon,
virtual public ChainJoystick,
virtual public ChainKey {
virtual public ChainKey,
virtual public ChainAngle,
virtual public ChainEncoder,
virtual public ChainToF {
public:
private:
};
+112
View File
@@ -0,0 +1,112 @@
/*
*SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
*SPDX-License-Identifier: MIT
*/
#include "ChainAngle/ChainAngle.hpp"
chain_status_t ChainAngle::getAngle12BitAdc(uint8_t id, uint16_t *adcValue, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_ANGLE_GET_12ADC, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_ANGLE_GET_12ADC, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*adcValue = (returnPacket[7] << 8) | returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainAngle::getAngle8BitAdc(uint8_t id, uint8_t *adcValue, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_ANGLE_GET_8ADC, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_ANGLE_GET_8ADC, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*adcValue = returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainAngle::setAngleRotationDirection(uint8_t id, angle_rotation_direction_t direction,
uint8_t *operationStatus, chain_save_flash_t saveToFlash,
unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (direction > ANGLE_ROTATION_INCREASING) {
return CHAIN_PARAMETER_ERROR;
}
if (acquireMutex()) {
cmdBufferSize = 0;
cmdBuffer[cmdBufferSize++] = direction;
cmdBuffer[cmdBufferSize++] = saveToFlash;
sendPacket(id, CHAIN_ANGLE_SET_CLOCKWISE_STATUS, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_ANGLE_SET_CLOCKWISE_STATUS, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*operationStatus = returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainAngle::getAngleRotationDirection(uint8_t id, angle_rotation_direction_t *direction,
unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_ANGLE_GET_CLOCKWISE_STATUS, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_ANGLE_GET_CLOCKWISE_STATUS, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*direction = (angle_rotation_direction_t)returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
+103
View File
@@ -0,0 +1,103 @@
/*
*SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
*SPDX-License-Identifier: MIT
*/
#ifndef _CHAIN_ANGLE_HPP_
#define _CHAIN_ANGLE_HPP_
#include "ChainCommon/ChainCommon.hpp"
/**
* @brief RotationDirection status for Angle device.
*
* This enumeration records whether the Angle device's clockwise direction
* is increasing or decreasing.
*/
typedef enum {
ANGLE_ROTATION_DECREASING = 0x00, /**< Rotation direction decreasing angle. */
ANGLE_ROTATION_INCREASING = 0x01, /**< Rotation direction increasing angle. */
} angle_rotation_direction_t;
/**
* @brief Enumeration for Chain_Angle device commands.
*
* This enumeration defines command codes for various operations of the Chain_Angle device.
*/
typedef enum {
CHAIN_ANGLE_GET_12ADC = 0x30, /**< Command to get the latest 12-bit ADC value */
CHAIN_ANGLE_GET_8ADC = 0x31, /**< Command to get the latest 8-bit mapped ADC value */
CHAIN_ANGLE_SET_CLOCKWISE_STATUS = 0x32, /**< Command to set the clockwise direction status */
CHAIN_ANGLE_GET_CLOCKWISE_STATUS = 0x33, /**< Command to get the current clockwise direction status */
} CHAIN_ANGLE_CMD_T; /**< Command types for Chain_Angle device operations */
class ChainAngle : virtual public ChainCommon {
public:
/**
* @brief Retrieves the 12-bit ADC value of the Angle device.
*
* This function fetches the 12-bit ADC value from the specified Angle device.
*
* @param id The position of the Angle device in the chain (starting from 1).
* @param adcValue Pointer to store the retrieved 12-bit ADC value.
* @param timeout Timeout duration in milliseconds (default is 100ms).
*
* @return The operation status (e.g., CHAIN_OK, CHAIN_TIMEOUT, etc.).
*/
chain_status_t getAngle12BitAdc(uint8_t id, uint16_t *adcValue, unsigned long timeout = 100);
/**
* @brief Retrieves the 8-bit ADC value of the Angle device.
*
* This function fetches the 8-bit ADC value from the specified Angle device.
*
* @param id The position of the Angle device in the chain (starting from 1).
* @param adcValue Pointer to store the retrieved 8-bit ADC value.
* @param timeout Timeout duration in milliseconds (default is 100ms).
*
* @return The operation status (e.g., CHAIN_OK, CHAIN_TIMEOUT, etc.).
*/
chain_status_t getAngle8BitAdc(uint8_t id, uint8_t *adcValue, unsigned long timeout = 100);
/**
* @brief Sets the rotation direction change status for the angle device at the specified position in the chain.
*
* This function sets the rotation direction change status for the angle device. The direction can either be
* increasing or decreasing in the clockwise direction. By default, the clockwise direction is set to increasing.
*
* @param id The position of the angle device in the chain (starting from 1).
* @param direction The clockwise direction status. Use `ANGLE_ROTATION_INCREASING` for increasing and
* `ANGLE_ROTATION_DECREASING` for decreasing.
* @param operationStatus Pointer to store the operation status after execution (1 for success, 0 for failure).
* @param saveToFlash Optional parameter to specify whether to save the setting to flash memory (default is 0, no
* save).
* @param timeout The timeout duration for the operation in milliseconds (default is 100ms).
*
* @return The operation status (e.g., `CHAIN_OK`, `CHAIN_PARAMETER_ERROR`, etc.).
*/
chain_status_t setAngleRotationDirection(uint8_t id, angle_rotation_direction_t direction, uint8_t *operationStatus,
chain_save_flash_t saveToFlash = CHAIN_SAVE_FLASH_DISABLE,
unsigned long timeout = 100);
/**
* @brief Retrieves the current clockwise rotation change status of the angle device at the specified position in
* the chain.
*
* This function gets the current clockwise rotation change status of the angle device. It determines whether the
* rotation direction is increasing or decreasing in the clockwise direction.
*
* @param id The position of the angle device in the chain (starting from 1).
* @param direction Pointer to store the current clockwise rotation change status. It will hold
* `ANGLE_ROTATION_INCREASING` for increasing and `ANGLE_ROTATION_DECREASING` for decreasing.
* @param timeout The timeout duration for the operation in milliseconds (default is 100ms).
*
* @return The operation status (e.g., `CHAIN_OK`, `CHAIN_TIMEOUT`, etc.).
*/
chain_status_t getAngleRotationDirection(uint8_t id, angle_rotation_direction_t *direction,
unsigned long timeout = 100);
private:
};
#endif // CHAIN_ANGLE_H
+6 -6
View File
@@ -182,12 +182,12 @@ typedef enum {
CHAIN_KEY_TYPE_CODE = 0x0003, /**< Key device type. */
CHAIN_JOYSTICK_TYPE_CODE = 0x0004, /**< Joystick device type. */
CHAIN_TOF_TYPE_CODE = 0x0005, /**< TOF device type. */
CHAIN_UART_TYPE_CODE = 0x0006, /**< UART device type. */
CHAIN_SWITCH_TYPE_CODE = 0x0007, /**< Switch device type. */
CHAIN_PEDAL_TYPE_CODE = 0x0008, /**< Pedal device type. */
CHAIN_PIR_TYPE_CODE = 0x0009, /**< PIR device type. */
CHAIN_MIC_TYPE_CODE = 0x000A, /**< Microphone device type. */
CHAIN_BUZZER_TYPE_CODE = 0x000B, /**< Buzzer device type. */
// CHAIN_UART_TYPE_CODE = 0x0006, /**< UART device type. */
// CHAIN_SWITCH_TYPE_CODE = 0x0007, /**< Switch device type. */
// CHAIN_PEDAL_TYPE_CODE = 0x0008, /**< Pedal device type. */
// CHAIN_PIR_TYPE_CODE = 0x0009, /**< PIR device type. */
// CHAIN_MIC_TYPE_CODE = 0x000A, /**< Microphone device type. */
// CHAIN_BUZZER_TYPE_CODE = 0x000B, /**< Buzzer device type. */
} chain_device_type_t;
/**
+295
View File
@@ -0,0 +1,295 @@
/*
*SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
*SPDX-License-Identifier: MIT
*/
#include "ChainEncoder/ChainEncoder.hpp"
chain_status_t ChainEncoder::getEncoderValue(uint8_t id, int16_t *value, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_ENCODER_GET_VALUE, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_ENCODER_GET_VALUE, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*value = (int16_t)((returnPacket[7] << 8) | returnPacket[6]);
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainEncoder::getEncoderIncValue(uint8_t id, int16_t *incValue, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_ENCODER_GET_INC_VALUE, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_ENCODER_GET_INC_VALUE, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*incValue = (int16_t)((returnPacket[7] << 8) | returnPacket[6]);
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainEncoder::resetEncoderValue(uint8_t id, uint8_t *operationStatus, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_ENCODER_RESET_VALUE, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_ENCODER_RESET_VALUE, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*operationStatus = returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainEncoder::resetEncoderIncValue(uint8_t id, uint8_t *operationStatus, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_ENCODER_RESET_INC_VALUE, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_ENCODER_RESET_INC_VALUE, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*operationStatus = returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainEncoder::setEncoderABDirect(uint8_t id, encoder_ab_t direct, uint8_t *operationStatus,
chain_save_flash_t saveToFlash, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
cmdBuffer[cmdBufferSize++] = direct;
cmdBuffer[cmdBufferSize++] = saveToFlash;
sendPacket(id, CHAIN_ENCODER_SET_AB_STATUS, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_ENCODER_SET_AB_STATUS, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*operationStatus = returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainEncoder::getEncoderABDirect(uint8_t id, encoder_ab_t *direct, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_ENCODER_GET_AB_STATUS, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_ENCODER_GET_AB_STATUS, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*direct = (encoder_ab_t)returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainEncoder::getEncoderButtonStatus(uint8_t id, uint8_t *buttonStatus, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_BUTTON_GET_STATUS, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_BUTTON_GET_STATUS, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*buttonStatus = returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainEncoder::setEncoderButtonTriggerInterval(uint8_t id, button_double_click_time_t doubleClickTimeout,
button_long_press_time_t longPressTimeout,
uint8_t *operationStatus, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
cmdBuffer[cmdBufferSize++] = doubleClickTimeout;
cmdBuffer[cmdBufferSize++] = longPressTimeout;
sendPacket(id, CHAIN_BUTTON_SET_TRIGGER_TIMEOUT, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_BUTTON_SET_TRIGGER_TIMEOUT, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*operationStatus = returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainEncoder::getEncoderButtonTriggerInterval(uint8_t id, button_double_click_time_t *doubleClickTimeout,
button_long_press_time_t *longPressTimeout,
unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_BUTTON_GET_TRIGGER_TIMEOUT, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_BUTTON_GET_TRIGGER_TIMEOUT, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*doubleClickTimeout = (button_double_click_time_t)returnPacket[6];
*longPressTimeout = (button_long_press_time_t)returnPacket[7];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainEncoder::setEncoderButtonMode(uint8_t id, chain_button_mode_t mode, uint8_t *operationStatus,
unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
cmdBuffer[cmdBufferSize++] = mode;
sendPacket(id, CHAIN_BUTTON_SET_MODE, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_BUTTON_SET_MODE, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*operationStatus = returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainEncoder::getEncoderButtonMode(uint8_t id, chain_button_mode_t *mode, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_BUTTON_GET_MODE, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_BUTTON_GET_MODE, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*mode = (chain_button_mode_t)returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
bool ChainEncoder::getEncoderButtonPressStatus(uint8_t id, chain_button_press_type_t *buttonStatus)
{
processIncomingData();
bool findStatus = 0;
record_info_t result;
findStatus = findRecord(&recordList, id, &result);
if (findStatus == true) {
*buttonStatus = (chain_button_press_type_t)result.type;
return true;
}
return false;
}
+210
View File
@@ -0,0 +1,210 @@
/*
*SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
*SPDX-License-Identifier: MIT
*/
#ifndef _CHAIN_ENCODER_HPP_
#define _CHAIN_ENCODER_HPP_
#include "ChainCommon/ChainCommon.hpp"
/**
* @brief Enumeration for AB pin status.
*/
typedef enum {
ENCODER_AB = 0x00, /**< AB encoding, clockwise increment. */
ENCODER_BA = 0x01, /**< BA encoding, counterclockwise increment. */
} encoder_ab_t;
/**
* @brief Command types for the Chain_Encoder.
*/
typedef enum {
CHAIN_ENCODER_GET_VALUE = 0x10, /**< Get encoder value. */
CHAIN_ENCODER_GET_INC_VALUE = 0x11, /**< Get encoder increment value. */
CHAIN_ENCODER_RESET_VALUE = 0x13, /**< Reset encoder value. */
CHAIN_ENCODER_RESET_INC_VALUE = 0x14, /**< Reset encoder increment value. */
CHAIN_ENCODER_SET_AB_STATUS = 0x15, /**< Set AB status, 0->AB, 1->BA. */
CHAIN_ENCODER_GET_AB_STATUS = 0x16, /**< Get AB status, 0->AB, 1->BA. */
} chain_encoder_cmd_t;
class ChainEncoder : virtual public ChainCommon {
public:
/**
* @brief Retrieves the encoder value.
*
* This function retrieves the current encoder value for the specified device in the chain.
*
* @param id The position of the device in the chain (starting from 1).
* @param value Pointer to the variable where the encoder value will be stored.
* @param timeout The timeout period for the operation (default is 100ms).
*
* @return Returns the status of the operation (e.g., success or failure).
*/
chain_status_t getEncoderValue(uint8_t id, int16_t *value, unsigned long timeout = 100);
/**
* @brief Retrieves the encoder increment value.
*
* This function retrieves the increment value of the encoder for the specified device in the chain.
* The increment value represents the change in encoder position since the last read.
*
* @param id The position of the device in the chain (starting from 1).
* @param incValue Pointer to the variable where the increment value will be stored.
* @param timeout The timeout period for the operation (default is 100ms).
*
* @return Returns the status of the operation (e.g., success or failure).
*/
chain_status_t getEncoderIncValue(uint8_t id, int16_t *incValue, unsigned long timeout = 100);
/**
* @brief Resets the encoder value.
*
* This function resets the encoder value to its initial state for the specified device in the chain.
* It is typically used when the encoder value needs to be cleared or initialized.
*
* @param id The position of the device in the chain (starting from 1).
* @param operationStatus Pointer to the variable where the operation status (1 for success, 0 for failure) will be
* stored.
* @param timeout The timeout period for the operation (default is 100ms).
*
* @return Returns the status of the operation (1 for success, 0 for failure).
*/
chain_status_t resetEncoderValue(uint8_t id, uint8_t *operationStatus, unsigned long timeout = 100);
/**
* @brief Resets the encoder increment value.
*
* This function resets the encoder increment value to its initial state for the specified device in the chain.
* It is typically used when the increment value needs to be cleared or initialized.
*
* @param id The position of the device in the chain (starting from 1).
* @param operationStatus Pointer to the variable where the operation status (1 for success, 0 for failure) will be
* stored.
* @param timeout The timeout period for the operation (default is 100ms).
*
* @return Returns the status of the operation (1 for success, 0 for failure).
*/
chain_status_t resetEncoderIncValue(uint8_t id, uint8_t *operationStatus, unsigned long timeout = 100);
/**
* @brief Sets the encoder AB direction.
*
* This function sets the AB direction of the encoder for the specified device in the chain.
* AB means the direction increases clockwise, and BA means the direction increases counterclockwise.
*
* @param id The position of the device in the chain (starting from 1).
* @param direct The direction to set: 0 for AB (clockwise increase), 1 for BA (counterclockwise increase).
* @param operationStatus Pointer to the variable where the operation status (1 for success, 0 for failure) will be
* stored.
* @param saveToFlash Optional parameter to save the setting to flash memory (default is CHAIN_SAVE_FLASH_DISABLE,
* not save).
* @param timeout The timeout period for the operation (default is 100ms).
*
* @return Returns the status of the operation (1 for success, 0 for failure).
*/
chain_status_t setEncoderABDirect(uint8_t id, encoder_ab_t direct, uint8_t *operationStatus,
chain_save_flash_t saveToFlash = CHAIN_SAVE_FLASH_DISABLE,
unsigned long timeout = 100);
/**
* @brief Gets the encoder AB direction.
*
* This function retrieves the current AB direction of the encoder for the specified device in the chain.
* AB means the direction increases clockwise, and BA means the direction increases counterclockwise.
*
* @param id The position of the device in the chain (starting from 1).
* @param direct Pointer to the variable where the direction (0 for AB, 1 for BA) will be stored.
* @param timeout The timeout period for the operation (default is 100ms).
*
* @return Returns the status of the operation (1 for success, 0 for failure).
*/
chain_status_t getEncoderABDirect(uint8_t id, encoder_ab_t *direct, unsigned long timeout = 100);
/**
* @brief Get the status of the encoder button device at a specified chain position.
*
* Retrieves whether the encoder button is currently pressed.
*
* @param id The encoder button device position in the chain (starting from 1).
* @param buttonStatus Pointer to receive the status (1: pressed, 0: not pressed).
* @param timeout Operation timeout in milliseconds (default 100ms).
* @return Operation result status code (e.g., CHAIN_OK, CHAIN_PARAMETER_ERROR).
*/
chain_status_t getEncoderButtonStatus(uint8_t id, uint8_t *buttonStatus, unsigned long timeout = 100);
/**
* @brief Set the double-click and long-press interval times for the encoder button device.
*
* Configure the required interval durations (in milliseconds) to detect double-click and long-press actions.
*
* @param id The position of the encoder button device in the chain (starting from 1).
* @param doubleClickIntervalMs Pointer to a variable storing the double-click interval time in milliseconds.
* @param longPressIntervalMs Pointer to a variable storing the long-press interval time in milliseconds.
* @param operationStatus Pointer to store the operation result (1 for success, 0 for failure).
* @param timeout Operation timeout in milliseconds (default is 100 ms).
*
* @return Operation status code, e.g., CHAIN_OK for success, CHAIN_PARAMETER_ERROR for invalid parameters.
*/
chain_status_t setEncoderButtonTriggerInterval(uint8_t id, button_double_click_time_t doubleClickIntervalMs,
button_long_press_time_t longPressIntervalMs,
uint8_t *operationStatus, unsigned long timeout = 100);
/**
* @brief Get the double-click and long-press interval times for the encoder button device.
*
* Retrieve the current interval durations (in milliseconds) used for detecting double-click and long-press actions.
*
* @param id The position of the encoder button device in the chain (starting from 1).
* @param doubleClickIntervalMs Pointer to a variable storing the double-click interval time in milliseconds.
* @param longPressIntervalMs Pointer to a variable storing the long-press interval time in milliseconds.
* @param timeout Operation timeout in milliseconds (default is 100 ms).
*
* @return Operation status code, e.g., CHAIN_OK for success, CHAIN_PARAMETER_ERROR for invalid parameters.
*/
chain_status_t getEncoderButtonTriggerInterval(uint8_t id, button_double_click_time_t *doubleClickIntervalMs,
button_long_press_time_t *longPressIntervalMs,
unsigned long timeout = 100);
/**
* @brief Set the operating mode of the encoder button device.
*
* Defines the button behavior mode, such as single-click, double-click, or long-press.
*
* @param id The encoder device position in the chain (starting from 1).
* @param mode Desired encoder button mode.
* @param operationStatus Pointer to receive operation result (1: success, 0: failure).
* @param timeout Operation timeout in milliseconds (default 100ms).
* @return Operation result status code.
*/
chain_status_t setEncoderButtonMode(uint8_t id, chain_button_mode_t mode, uint8_t *operationStatus,
unsigned long timeout = 100);
/**
* @brief Get the current operating mode of the encoder button device.
*
* Retrieves the current button mode setting.
*
* @param id The encoder device position in the chain (starting from 1).
* @param mode Pointer to receive the current mode.
* @param timeout Operation timeout in milliseconds (default 100ms).
* @return Operation result status code.
*/
chain_status_t getEncoderButtonMode(uint8_t id, chain_button_mode_t *mode, unsigned long timeout = 100);
/**
* @brief Get the press type status of the encoder button device.
*
* Determines the type of press event (single, double, long).
*
* @param id The encoder device position in the chain (starting from 1).
* @param encoderPressType Pointer to receive the press type.
* @return true if the encoder button is currently pressed; false otherwise.
*/
bool getEncoderButtonPressStatus(uint8_t id, chain_button_press_type_t *encoderPressType);
private:
};
#endif // _CHAIN_ENCODER_HPP_
+11 -10
View File
@@ -60,8 +60,7 @@ chain_status_t ChainJoystick::getJoystickMappedRange(uint8_t id, uint16_t *mapBu
{
chain_status_t status = CHAIN_OK;
if(size != JOYSTICK_MAP_SIZE)
{
if (size != JOYSTICK_MAP_SIZE) {
return CHAIN_PARAMETER_ERROR;
}
@@ -93,8 +92,7 @@ chain_status_t ChainJoystick::setJoystickMappedRange(uint8_t id, uint16_t *mapBu
{
chain_status_t status = CHAIN_OK;
if(size != JOYSTICK_MAP_SIZE)
{
if (size != JOYSTICK_MAP_SIZE) {
return CHAIN_PARAMETER_ERROR;
}
@@ -119,7 +117,7 @@ chain_status_t ChainJoystick::setJoystickMappedRange(uint8_t id, uint16_t *mapBu
} else {
status = CHAIN_BUSY;
}
return status;
}
@@ -200,9 +198,10 @@ chain_status_t ChainJoystick::getJoystickButtonStatus(uint8_t id, uint8_t *keySt
return status;
}
chain_status_t ChainJoystick::setJoystickButtonTriggerInterval(uint8_t id, button_double_click_time_t doubleClickIntervalMs,
button_long_press_time_t longPressIntervalMs, uint8_t *operationStatus,
unsigned long timeout)
chain_status_t ChainJoystick::setJoystickButtonTriggerInterval(uint8_t id,
button_double_click_time_t doubleClickIntervalMs,
button_long_press_time_t longPressIntervalMs,
uint8_t *operationStatus, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
@@ -228,8 +227,10 @@ chain_status_t ChainJoystick::setJoystickButtonTriggerInterval(uint8_t id, butto
return status;
}
chain_status_t ChainJoystick::getJoystickButtonTriggerInterval(uint8_t id, button_double_click_time_t *doubleClickIntervalMs,
button_long_press_time_t *longPressIntervalMs, unsigned long timeout)
chain_status_t ChainJoystick::getJoystickButtonTriggerInterval(uint8_t id,
button_double_click_time_t *doubleClickIntervalMs,
button_long_press_time_t *longPressIntervalMs,
unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
+5 -5
View File
@@ -7,7 +7,7 @@
#ifndef _CHAIN_JOYSTICK_HPP_
#define _CHAIN_JOYSTICK_HPP_
#include <ChainCommon/ChainCommon.hpp>
#include "ChainCommon/ChainCommon.hpp"
/**
* @brief Size of the joystick map buffer.
@@ -155,8 +155,8 @@ public:
* @return Operation status code, e.g., CHAIN_OK for success, CHAIN_PARAMETER_ERROR for invalid parameters.
*/
chain_status_t setJoystickButtonTriggerInterval(uint8_t id, button_double_click_time_t doubleClickIntervalMs,
button_long_press_time_t longPressIntervalMs, uint8_t *operationStatus,
unsigned long timeout = 100);
button_long_press_time_t longPressIntervalMs,
uint8_t *operationStatus, unsigned long timeout = 100);
/**
* @brief Get the double-click and long-press interval times for the joystick button device.
@@ -171,8 +171,8 @@ public:
* @return Operation status code, e.g., CHAIN_OK for success, CHAIN_PARAMETER_ERROR for invalid parameters.
*/
chain_status_t getJoystickButtonTriggerInterval(uint8_t id, button_double_click_time_t *doubleClickIntervalMs,
button_long_press_time_t *longPressIntervalMs,
unsigned long timeout = 100);
button_long_press_time_t *longPressIntervalMs,
unsigned long timeout = 100);
/**
* @brief Set the operating mode of the joystick button device.
+1 -1
View File
@@ -7,7 +7,7 @@
#ifndef _CHAIN_KEY_HPP_
#define _CHAIN_KEY_HPP_
#include <ChainCommon/ChainCommon.hpp>
#include "ChainCommon/ChainCommon.hpp"
class ChainKey : virtual public ChainCommon {
public:
+218
View File
@@ -0,0 +1,218 @@
/*
*SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
*SPDX-License-Identifier: MIT
*/
#include "ChainToF/ChainToF.hpp"
chain_status_t ChainToF::getToFDistance(uint8_t id, uint16_t *distance, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_TOF_GET_DISTANCE, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_TOF_GET_DISTANCE, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*distance = (returnPacket[7] << 8) | returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainToF::setToFMeasureTime(uint8_t id, uint8_t time, uint8_t *operationStatus, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (time < TOF_MEASUREMENT_TIME_MIN || time > TOF_MEASUREMENT_TIME_MAX) {
return CHAIN_PARAMETER_ERROR;
}
if (acquireMutex()) {
cmdBufferSize = 0;
cmdBuffer[cmdBufferSize++] = time;
sendPacket(id, CHAIN_TOF_SET_MEASURE_TIME, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_TOF_SET_MEASURE_TIME, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*operationStatus = returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainToF::getToFMeasureTime(uint8_t id, uint8_t *time, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_TOF_GET_MEASURE_TIME, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_TOF_GET_MEASURE_TIME, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*time = returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainToF::setToFMeasureMode(uint8_t id, chain_tof_mode_t mode, uint8_t *operationStatus,
unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (mode < CHAIN_TOF_MODE_STOP || mode > CHAIN_TOF_MODE_CONTINUOUS) {
return CHAIN_PARAMETER_ERROR;
}
if (acquireMutex()) {
cmdBufferSize = 0;
cmdBuffer[cmdBufferSize++] = mode;
sendPacket(id, CHAIN_TOF_SET_MEASURE_MODE, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_TOF_SET_MEASURE_MODE, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*operationStatus = returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainToF::getToFMeasureMode(uint8_t id, chain_tof_mode_t *mode, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_TOF_GET_MEASURE_MODE, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_TOF_GET_MEASURE_MODE, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*mode = (chain_tof_mode_t)returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainToF::setToFMeasureStatus(uint8_t id, chain_tof_measure_status_t measureStatus,
uint8_t *operationStatus, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (measureStatus < CHAIN_TOF_STATUS_STOP || measureStatus > CHAIN_TOF_STATUS_START) {
return CHAIN_PARAMETER_ERROR;
}
if (acquireMutex()) {
cmdBufferSize = 0;
cmdBuffer[cmdBufferSize++] = measureStatus;
sendPacket(id, CHAIN_TOF_SET_MEASURE_STATUS, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_TOF_SET_MEASURE_STATUS, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*operationStatus = returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainToF::getToFMeasureStatus(uint8_t id, chain_tof_measure_status_t *measureStatus,
unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_TOF_GET_MEASURE_STATUS, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_TOF_GET_MEASURE_STATUS, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*measureStatus = (chain_tof_measure_status_t)returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
chain_status_t ChainToF::getToFMeasureCompleteFlag(uint8_t id, uint8_t *completeFlag, unsigned long timeout)
{
chain_status_t status = CHAIN_OK;
if (acquireMutex()) {
cmdBufferSize = 0;
sendPacket(id, CHAIN_TOF_GET_MEASURE_COMPLETE_FLAG, cmdBuffer, cmdBufferSize);
if (waitForData(id, CHAIN_TOF_GET_MEASURE_COMPLETE_FLAG, timeout)) {
if (checkPacket(returnPacket, returnPacketSize)) {
*completeFlag = returnPacket[6];
} else {
status = CHAIN_RETURN_PACKET_ERROR;
}
} else {
status = CHAIN_TIMEOUT;
}
releaseMutex();
} else {
status = CHAIN_BUSY;
}
return status;
}
+166
View File
@@ -0,0 +1,166 @@
/*
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
#ifndef _CHAIN_TOF_HPP_
#define _CHAIN_TOF_HPP_
#include "ChainCommon/ChainCommon.hpp"
/**
* @brief Minimum allowable measurement time for the Chain_ToF sensor (in milliseconds).
*
* Shorter integration time results in faster updates but lower accuracy.
*/
#define TOF_MEASUREMENT_TIME_MIN (20)
/**
* @brief Maximum allowable measurement time for the Chain_ToF sensor (in milliseconds).
*
* Longer integration time generally increases accuracy but reduces the update rate.
*/
#define TOF_MEASUREMENT_TIME_MAX (200)
/**
* @brief Command codes for Chain_ToF sensor operations.
*
* These codes are used when communicating with the device over the chain protocol.
*/
typedef enum {
CHAIN_TOF_GET_DISTANCE = 0x50, /**< Retrieve distance measurement from the sensor */
CHAIN_TOF_SET_MEASURE_TIME = 0x51, /**< Set the measurement (integration) time */
CHAIN_TOF_GET_MEASURE_TIME = 0x52, /**< Get the current measurement time */
CHAIN_TOF_SET_MEASURE_MODE = 0x53, /**< Set the measurement mode (STOP / SINGLE / CONTINUOUS) */
CHAIN_TOF_GET_MEASURE_MODE = 0x54, /**< Get the current measurement mode */
CHAIN_TOF_SET_MEASURE_STATUS = 0x55, /**< Start or stop measurement explicitly */
CHAIN_TOF_GET_MEASURE_STATUS = 0x56, /**< Get the current measurement status */
CHAIN_TOF_GET_MEASURE_COMPLETE_FLAG = 0x57 /**< Check if the latest measurement is complete */
} chain_tof_cmd_t;
/**
* @brief Measure modes for Chain_ToF sensor.
*/
typedef enum {
CHAIN_TOF_MODE_STOP = 0, /**< Stop measurements; sensor idle */
CHAIN_TOF_MODE_SINGLE = 1, /**< Take a single measurement then stop */
CHAIN_TOF_MODE_CONTINUOUS = 2 /**< Continue measuring until stopped */
} chain_tof_mode_t;
/**
* @brief Measure status values for Chain_ToF sensor.
*
* Used to explicitly start or stop measurements.
*/
typedef enum {
CHAIN_TOF_STATUS_STOP = 0, /**< Stop the measurement process */
CHAIN_TOF_STATUS_START = 1 /**< Start the measurement process */
} chain_tof_measure_status_t;
/**
* @class ChainToF
* @brief Interface for controlling chained Time-of-Flight (ToF) distance sensors.
*
* The ChainToF class inherits from ChainCommon and provides high-level methods
* for querying measurements, setting timing and modes, and controlling the measurement lifecycle.
* Sensors are addressed by their position in the chain starting from index 1.
*/
class ChainToF : virtual public ChainCommon {
public:
/**
* @brief Get the measured distance from the ToF device.
*
* @param id Position of the ToF device in the chain (starting from 1).
* @param distance Pointer to store the measured distance (in mm).
* @param timeout Timeout duration in milliseconds (default: 100 ms).
* @return Operation status (e.g., CHAIN_OK, CHAIN_TIMEOUT).
*/
chain_status_t getToFDistance(uint8_t id, uint16_t *distance, unsigned long timeout = 100);
/**
* @brief Set the measurement timing (integration time) for the ToF device.
*
* @param id Position of the ToF device in the chain (starting from 1).
* @param time Measure time in milliseconds.
* Must be between TOF_MEASUREMENT_TIME_MIN and TOF_MEASUREMENT_TIME_MAX.
* @param operationStatus Pointer to store the device's execution result (1 = accepted, 0 = rejected).
* @param timeout Timeout duration in milliseconds (default: 100 ms).
* @return Operation status.
*/
chain_status_t setToFMeasureTime(uint8_t id, uint8_t time, uint8_t *operationStatus, unsigned long timeout = 100);
/**
* @brief Get the current measurement timing from the ToF device.
*
* @param id Position of the ToF device in the chain (starting from 1).
* @param time Pointer to store the measurement time in milliseconds.
* @param timeout Timeout duration in milliseconds (default: 100 ms).
* @return Operation status.
*/
chain_status_t getToFMeasureTime(uint8_t id, uint8_t *time, unsigned long timeout = 100);
/**
* @brief Set the measurement mode.
*
* @param id Position of the ToF device in the chain (starting from 1).
* @param mode Desired measurement mode (`chain_tof_mode_t`).
* @param operationStatus Pointer to store the device's execution result (1 = accepted, 0 = rejected).
* @param timeout Timeout duration in milliseconds (default: 100 ms).
* @return Operation status.
*/
chain_status_t setToFMeasureMode(uint8_t id, chain_tof_mode_t mode, uint8_t *operationStatus,
unsigned long timeout = 100);
/**
* @brief Get the current measurement mode from the ToF device.
*
* @param id Position of the ToF device in the chain (starting from 1).
* @param mode Pointer to store the retrieved mode (`chain_tof_mode_t`).
* @param timeout Timeout duration in milliseconds (default: 100 ms).
* @return Operation status.
*/
chain_status_t getToFMeasureMode(uint8_t id, chain_tof_mode_t *mode, unsigned long timeout = 100);
/**
* @brief Set the measurement status (START / STOP) for the ToF device.
*
* Explicitly starts or stops the measurement process, regardless of the current mode.
*
* @param id Position of the ToF device in the chain (starting from 1).
* @param measureStatus Desired status (`chain_tof_measure_status_t`).
* @param operationStatus Pointer to store the device's execution result (1 = accepted, 0 = rejected).
* @param timeout Timeout duration in milliseconds (default: 100 ms).
* @return Operation status.
*/
chain_status_t setToFMeasureStatus(uint8_t id, chain_tof_measure_status_t measureStatus, uint8_t *operationStatus,
unsigned long timeout = 100);
/**
* @brief Get the current measurement status (START / STOP) from the ToF device.
*
* @param id Position of the ToF device in the chain (starting from 1).
* @param measureStatus Pointer to store the retrieved status (`chain_tof_measure_status_t`).
* @param timeout Timeout duration in milliseconds (default: 100 ms).
* @return Operation status.
*/
chain_status_t getToFMeasureStatus(uint8_t id, chain_tof_measure_status_t *measureStatus,
unsigned long timeout = 100);
/**
* @brief Check whether the current measurement cycle is complete.
*
* This flag can be used to determine if the latest measurement data is ready for retrieval.
*
* @param id Position of the ToF device in the chain (starting from 1).
* @param completeFlag Pointer to store the completion flag (1 = complete, 0 = not ready).
* @param timeout Timeout duration in milliseconds (default: 100 ms).
* @return Operation status.
*/
chain_status_t getToFMeasureCompleteFlag(uint8_t id, uint8_t *completeFlag, unsigned long timeout = 100);
private:
// No private members declared, potentially reserved for internal buffer or state tracking.
};
#endif // _CHAIN_TOF_HPP_