initial commit

This commit is contained in:
bmy
2024-05-17 01:57:18 +08:00
commit 478e698ae9
19 changed files with 3821 additions and 0 deletions

38
.clang-format Normal file
View File

@@ -0,0 +1,38 @@
---
BasedOnStyle: Microsoft
Language: Cpp
###################################
# indent conf
###################################
UseTab: Never
IndentWidth: 2
TabWidth: 2
ColumnLimit: 0
AccessModifierOffset: -4
NamespaceIndentation: All
FixNamespaceComments: false
BreakBeforeBraces: Linux
###################################
# other styles
###################################
#
# for more conf, you can ref: https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AllowShortBlocksOnASingleLine: true
IndentCaseLabels: true
SortIncludes: false
AlignConsecutiveMacros: AcrossEmptyLines
AlignConsecutiveAssignments: Consecutive

43
.gitignore vendored Normal file
View File

@@ -0,0 +1,43 @@
# Created by https://www.toptal.com/developers/gitignore/api/cmake,visualstudiocode
# Edit at https://www.toptal.com/developers/gitignore?templates=cmake,visualstudiocode
### CMake ###
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
### CMake Patch ###
# External projects
*-prefix/
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# End of https://www.toptal.com/developers/gitignore/api/cmake,visualstudiocode
#build path
build/*

9
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,9 @@
{
"files.associations": {
"stdio.h": "c",
"string.h": "c",
"stdint.h": "c",
"by_serial.h": "c",
"log.h": "c"
}
}

20
CMakeLists.txt Normal file
View File

@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 3.16)
project(bycmd)
# set(CRC16 by_cmd/crc16/crc16.cc)
set(TEST_MAIN test.c)
set(BYCMD by_serial.c
by_frame.c
by_cmd.c)
set(TOML tomlc99/toml.c)
set(CRC16 crc16/crc16.c)
set(LOGC logc/log.c)
# add_library(bycmd SHARED ${BYCMD} ${FRAME} ${CRC16})
# add_library(bycmd ${BYCMD} ${FRAME} ${CRC16})
# add_executable(${test} ${TEST_MAIN} ${FRAME})
add_executable(bycmd_test ${BYCMD} ${TOML} ${CRC16} ${LOGC} ${TEST_MAIN})
target_link_libraries(bycmd_test pthread)
# target_link_libraries(${test} bycmd)

182
by_cmd.c Normal file
View File

@@ -0,0 +1,182 @@
#include "by_cmd.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include "by_frame.h"
#include "logc/log.h"
uint8_t cmd;
uint32_t received_data[2];
uint8_t listerning_cmd;
int received_flag;
int by_cmd_init(void)
{
log_debug("by_cmd init");
return (by_frame_init());
}
void *by_cmd_loop(void *timeout)
{
while (*(int *)timeout > 0) {
int ret = by_frame_parse(&cmd, received_data);
if (!ret && cmd == listerning_cmd) {
// log_debug("got frame cmd %2X", cmd);
break;
}
usleep(10);
}
received_flag = 1;
listerning_cmd = 0;
return NULL;
}
/**
* @brief 注册监听的
*s
* @param cmd
*/
int by_cmd_reg_listerning(uint8_t cmd, int timeout)
{
listerning_cmd = cmd;
received_flag = 0;
pthread_t thread_listerning;
pthread_create(&thread_listerning, NULL, by_cmd_loop, &timeout);
while (timeout--) {
if (received_flag) {
// log_debug("received done! using %fSEC", (float)timeout_cnt * 0.00005);
listerning_cmd = 0;
received_flag = 0;
return 0;
}
usleep(10);
}
listerning_cmd = 0;
received_flag = 0;
log_warn("get cmd time out");
return -1;
}
/**
* @brief 发送 x 方向速度指令(无应答)
*
* @param speed
*/
void by_cmd_send_speed_x(float speed)
{
uint8_t buff[4] = {0};
memcpy(buff, &speed, 4);
by_frame_send(0x31, buff, 4);
}
/**
* @brief 发送 y 方向速度指令(无应答)
*
* @param speed
*/
void by_cmd_send_speed_y(float speed)
{
uint8_t buff[4] = {0};
memcpy(buff, &speed, 4);
by_frame_send(0x32, buff, 4);
}
/**
* @brief 发送角速度指令(无应答)
*
* @param speed
*/
void by_cmd_send_speed_omega(float speed)
{
uint8_t buff[4] = {0};
memcpy(buff, &speed, 4);
by_frame_send(0x33, buff, 4);
}
/**
* @brief 发送 x 方向移动距离指令(等待应答)
*
* @param speed
* @param time
* @return true 发送成功
* @return false 应答超时
*/
int by_cmd_send_distance_x(float speed, uint32_t time)
{
uint8_t buff[4] = {0};
memcpy(buff, &speed, 4);
memcpy(buff + 4, &time, 4);
by_frame_send(0x34, buff, 8);
return (by_cmd_reg_listerning(0x34, 1000));
}
/**
* @brief 发送 y 方向移动距离指令(等待应答)
*
* @param speed
* @param time
* @return true 发送成功
* @return false 应答超时
*/
int by_cmd_send_distance_y(float speed, uint32_t time)
{
uint8_t buff[4] = {0};
memcpy(buff, &speed, 4);
memcpy(buff + 4, &time, 4);
by_frame_send(0x35, buff, 8);
return (by_cmd_reg_listerning(0x35, 1000));
}
/**
* @brief 发送 omega 方向旋转角度指令(等待应答)
*
* @param speed
* @param time
* @return true 发送成功
* @return false 应答超时
*/
int by_cmd_send_angle_omega(float speed, uint32_t time)
{
uint8_t buff[4] = {0};
memcpy(buff, &speed, 4);
memcpy(buff + 4, &time, 4);
by_frame_send(0x36, buff, 8);
return (by_cmd_reg_listerning(0x36, 1000));
}
int by_cmd_send_reset_axis_x(void)
{
uint8_t buff[4] = {0};
by_frame_send(0x41, buff, 4);
return (by_cmd_reg_listerning(0x41, 1000));
}
int by_cmd_send_reset_axis_z(void)
{
uint8_t buff[4] = {0};
by_frame_send(0x42, buff, 4);
return (by_cmd_reg_listerning(0x42, 1000));
}
int by_cmd_send_reset_end_effector(void)
{
uint8_t buff[4] = {0};
by_frame_send(0x43, buff, 4);
return (by_cmd_reg_listerning(0x43, 1000));
}

22
by_cmd.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef _BY_CMD_H__
#define _BY_CMD_H__
#include <stdio.h>
#include <stdint.h>
int by_cmd_init(void);
void *by_cmd_loop(void *ptr);
void by_cmd_send_speed_x(float speed);
void by_cmd_send_speed_y(float speed);
void by_cmd_send_speed_omega(float speed);
int by_cmd_send_distance_x(float speed, uint32_t time);
int by_cmd_send_distance_y(float speed, uint32_t time);
int by_cmd_send_angle_omega(float speed, uint32_t time);
int by_cmd_send_reset_axis_z(void);
int by_cmd_send_reset_axis_x(void);
int by_cmd_send_reset_end_effector(void);
#endif

169
by_frame.c Normal file
View File

@@ -0,0 +1,169 @@
#include "by_frame.h"
#include "by_serial.h"
#include "crc16/crc16.h"
#include "logc/log.h"
by_serial_t serial_port;
by_frame_queue_t queue_recv;
uint8_t frame_buffer_recv[100];
uint8_t frame_buffer_send[4 + BY_FRAME_DATA_NUM * sizeof(uint32_t)];
int frame_parse_busy;
int by_frame_queue_pop(by_frame_queue_t *queue, uint8_t *element)
{
if (!queue->len) {
return -1;
}
*element = queue->buff[0];
queue->len -= 1;
memmove(queue->buff, queue->buff + 1, queue->len);
return 0;
}
int by_frame_queue_add(by_frame_queue_t *queue, uint8_t element)
{
if (queue->size == queue->len) {
return -1;
}
queue->buff[queue->len] = element;
queue->len += 1;
return 0;
}
int by_frame_queue_copy(by_frame_queue_t *queue, uint8_t *buff_out, int num)
{
int copy_num = (queue->len < num) ? queue->len : num;
memcpy(buff_out, queue->buff, copy_num);
return copy_num;
}
int by_frame_queue_drop(by_frame_queue_t *queue, int num)
{
int drop_num = 0;
uint8_t element_temp;
for (int i = 0; i < num; i++) {
drop_num += (!by_frame_queue_pop(queue, &element_temp));
}
return drop_num;
}
int by_frame_queue_find(by_frame_queue_t *queue, const uint8_t element)
{
int found_num = -1;
for (int i = 0; i < queue->len; i++) {
if (queue->buff[i] == element) {
found_num = i;
break;
}
}
return found_num;
}
int by_frame_queue_get_used(by_frame_queue_t *queue)
{
return queue->len;
}
void by_frame_queue_init(by_frame_queue_t *queue, uint8_t *buff, int buff_len)
{
memset(queue, 0, sizeof(by_frame_queue_t));
memset(buff, 0, buff_len);
queue->buff = buff;
queue->size = buff_len;
}
void by_frame_send(uint8_t cmd, uint8_t *data_array, uint8_t len)
{
uint16_t crc_cal = 0;
const uint8_t data_byte_num = BY_FRAME_DATA_NUM * sizeof(uint32_t);
memset(frame_buffer_send, 0, sizeof(frame_buffer_send));
frame_buffer_send[0] = BY_FRAME_HEAD;
frame_buffer_send[1] = cmd;
if (len > data_byte_num) {
len = data_byte_num;
}
memcpy(frame_buffer_send + 2, data_array, len);
crc_cal = crc16_check(frame_buffer_send, 2 + data_byte_num);
frame_buffer_send[2 + data_byte_num] = (uint8_t)(crc_cal >> 8);
frame_buffer_send[3 + data_byte_num] = (uint8_t)(crc_cal);
by_serial_write(&serial_port, frame_buffer_send, 4 + data_byte_num);
}
/**
* @brief
*
* @param data_num
* @param data_array
* @todo 将其中写死的数据长度按照宏定义给出
*/
int by_frame_parse(uint8_t *cmd, uint32_t *data_array)
{
uint8_t frame_buff[BY_FRANE_LEN] = {0};
// 先从缓冲区内复制数据到临时 buffer 里
for (int i = 0; i < by_serial_get_used_buffer_len(&serial_port); i++) {
uint8_t data = 0;
by_serial_read(&serial_port, &data, 1);
by_frame_queue_add(&queue_recv, data);
}
// 丢弃缓冲区头部无法解析的数据,如果剩下的数据过少则不解析
// log_debug("drop %d", by_frame_queue_find(&queue_recv, BY_FRAME_HEAD));
int used_num = by_frame_queue_find(&queue_recv, BY_FRAME_HEAD);
by_frame_queue_drop(&queue_recv, used_num);
// 不存在帧头时退出
if (-1 == used_num) {
return -1;
}
// 剩余数据过少时退出
if (BY_FRANE_LEN > by_frame_queue_get_used(&queue_recv)) {
return -1;
}
log_debug("start parsing");
by_frame_queue_copy(&queue_recv, frame_buff, BY_FRANE_LEN);
uint16_t crc_val = (uint16_t)frame_buff[BY_FRANE_LEN - 1];
crc_val |= (uint16_t)(frame_buff[BY_FRANE_LEN - 2] << 8);
uint16_t crc_cal = crc16_check(frame_buff, BY_FRANE_LEN - 2);
if (crc_val == crc_cal) {
log_info("received successful");
// 丢掉当前帧头,下次解析时就不从该帧头开始
by_frame_queue_drop(&queue_recv, 1);
// TODO 复制数据
*cmd = frame_buff[1];
memcpy(data_array, &frame_buff[2], BY_FRANE_DATA_LEN);
return 0;
} else {
log_warn("receive failed");
log_warn("cal crc 0x%04X, but got 0x%04X", crc_cal, crc_val);
// 丢掉当前帧头,下次解析时就不从该帧头开始
by_frame_queue_drop(&queue_recv, 1);
return -1;
}
}
int by_frame_init(void)
{
by_frame_queue_init(&queue_recv, frame_buffer_recv, sizeof(frame_buffer_recv));
return (by_serial_init(&serial_port, "/dev/ttyTHS0"));
}

29
by_frame.h Normal file
View File

@@ -0,0 +1,29 @@
#ifndef _BY_FRAME_H__
#define _BY_FRAME_H__
/* BY_TINY_FRAME 的超级减配版本(好吧基本上完全没有关系)
* 主要是等应答还是挺慢的,写数据场景只需要下位机校验数据合理性即可,读数据等应答即可
* 并且需要同步的参数并不多,所以考虑直接使用定长的特定结构的帧,一帧全部下发
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#define BY_FRAME_HEAD (0XEB)
#define BY_FRAME_DATA_NUM (2)
#define BY_FRANE_DATA_LEN (BY_FRAME_DATA_NUM * sizeof(uint32_t))
#define BY_FRANE_LEN (BY_FRANE_DATA_LEN + 4)
typedef struct by_frame_queue_t {
uint8_t *buff;
int len;
int size;
} by_frame_queue_t;
extern int by_frame_init(void);
extern int by_frame_parse(uint8_t *cmd, uint32_t *data_array);
extern void by_frame_send(uint8_t cmd, uint8_t *data_array, uint8_t len);
#endif

219
by_serial.c Normal file
View File

@@ -0,0 +1,219 @@
#include "by_serial.h"
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <termios.h>
#include "logc/log.h"
int by_serial_init(by_serial_t *serial_port, const char *dev_name)
{
serial_port->dev_name_len = strlen(dev_name);
assert(0 < serial_port->dev_name_len);
strcpy(serial_port->dev_name_str, dev_name);
int fd;
fd = open(serial_port->dev_name_str, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
if (fd < 0) {
log_error("open uart device error");
return -1;
} else {
serial_port->fd = fd;
by_serial_set_baudrate(serial_port, 115200);
by_serial_set_parity(serial_port, 8, 1, 'N');
log_info("serial %s init successful", serial_port->dev_name_str);
return 0;
}
}
int by_serial_set_baudrate(by_serial_t *serial_port, int baudrate)
{
int index = 0;
int status = 0;
int speed_arr[] = {
B115200,
B38400,
B19200,
B9600,
B4800,
B2400,
B1200};
int name_arr[] = {
115200,
38400,
19200,
9600,
4800,
2400,
1200};
struct termios Opt = {0};
tcgetattr(serial_port->fd, &Opt);
for (index = 0; index < sizeof(speed_arr) / sizeof(int); index++) {
if (baudrate == name_arr[index]) {
/*设置前 flush*/
tcflush(serial_port->fd, TCIOFLUSH);
cfsetispeed(&Opt, speed_arr[index]);
cfsetospeed(&Opt, speed_arr[index]);
/*tcsetattr(串口描述符,立即使用或者其他标示,指向 termios 的指针),通过
tcsetattr 函数把新的属性设置到串口上。*/
status = tcsetattr(serial_port->fd, TCSANOW, &Opt);
if (0 != status) {
log_error("tcsetattr COM error");
return -1;
}
/*设置后 flush*/
tcflush(serial_port->fd, TCIOFLUSH);
return 0;
}
}
return 0;
}
int by_serial_set_parity(by_serial_t *serial_port, int databits, int stopbits, char parity)
{
struct termios Opt = {0};
if (0 != tcgetattr(serial_port->fd, &Opt)) {
log_error("tcgetattr COM error");
return -1;
}
Opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
Opt.c_oflag &= ~OPOST; /*Output*/
Opt.c_iflag &= ~ICRNL; // 禁止将输入的 CR 转换为 NL
Opt.c_iflag &= ~(IXON); // 清 bit 位 关闭流控字符
/*设置数据位,取值为 7 或 8*/
Opt.c_cflag &= ~CSIZE;
switch (databits) {
case 7:
Opt.c_cflag |= CS7;
break;
case 8:
Opt.c_cflag |= CS8;
break;
default:
log_error("Unsupported data size");
return -1;
break;
}
/*设置停止位,取值为 1 或 2*/
switch (stopbits) {
case 1:
Opt.c_cflag &= ~CSTOPB;
break;
case 2:
Opt.c_cflag |= CSTOPB;
break;
default:
log_error("Unsupported stop bits");
return -1;
break;
}
/*设置校验位,取值为 E,N,O,S*/
switch (parity) {
case 'e':
case 'E': {
Opt.c_cflag |= PARENB; /*Enable parity*/
Opt.c_cflag &= ~PARODD; /*转换为偶效验*/
Opt.c_iflag |= INPCK; /*Disnable parity checking*/
} break;
case 'n':
case 'N': {
Opt.c_cflag &= ~PARENB; /*Clear parity enable*/
Opt.c_iflag &= ~INPCK; /*Enable parity checking*/
} break;
case 'o':
case 'O': {
Opt.c_cflag |= (PARODD | PARENB); /*设置为奇效验*/
Opt.c_iflag |= INPCK; /*Disnable parity checking*/
} break;
case 's': /*as no parity*/
case 'S': /*as no parity*/
{
Opt.c_cflag &= ~PARENB;
Opt.c_cflag &= ~CSTOPB;
} break;
default:
log_error("Unsupported parity\n");
return -1;
break;
}
/*设置结构体输入校验位*/
if ('n' != parity) {
Opt.c_iflag |= INPCK;
}
tcflush(serial_port->fd, TCIFLUSH);
Opt.c_cc[VTIME] = 150; /*设置超时 15 秒*/
Opt.c_cc[VMIN] = 0; /*更新结构体并立即执行*/
if (0 != tcsetattr(serial_port->fd, TCSANOW, &Opt)) {
log_error("tcsetattr COM error");
return -1;
}
return 0;
}
int by_serial_write(by_serial_t *serial_port, const char *buff, const int len)
{
int len_t;
if (serial_port->fd < 0) {
return -1;
}
len_t = write(serial_port->fd, buff, len);
if (0 > len_t) {
// log_error("write buff failed");
return -1;
} else {
// printf("write buff successful %d/%d\r\n", len_t, len);
return 0;
}
}
int by_serial_read(by_serial_t *serial_port, char *buff, const int len)
{
if (1 > by_serial_get_used_buffer_len(serial_port)) {
return -1;
}
int len_t = -1;
if (serial_port->fd < 0) {
return -1;
}
len_t = read(serial_port->fd, buff, len);
if (0 > len_t) {
// log_error("read buff failed");
return -1;
} else {
// printf("read buff successful %d/%d\r\n", len_t, len);
return len_t;
}
}
int by_serial_get_used_buffer_len(by_serial_t *serial_port)
{
int used_len = 0;
ioctl(serial_port->fd, FIONREAD, &used_len);
return used_len;
}

22
by_serial.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef _BY_SERIAL_H__
#define _BY_SERIAL_H__
#define BY_SERIAL_DEV_STATUS_STDBY 0x00
#define BY_SERIAL_DEV_STATUS_ERROR 0xFF
#define BY_SERIAL_DEV_STATUS_OPEND 0x01
typedef struct by_serial_t {
int fd;
char dev_name_str[40];
int dev_name_len;
int dev_status;
} by_serial_t;
extern int by_serial_init(by_serial_t *serial_port, const char *dev_name);
extern int by_serial_set_baudrate(by_serial_t *serial_port, int baudrate);
extern int by_serial_set_parity(by_serial_t *serial_port, int databits, int stopbits, char parity);
extern int by_serial_write(by_serial_t *serial_port, const char *buff, const int len);
extern int by_serial_read(by_serial_t *serial_port, char *buff, const int len);
extern int by_serial_get_used_buffer_len(by_serial_t *serial_port);
#endif

137
crc16/crc16.c Normal file
View File

@@ -0,0 +1,137 @@
#include "crc16.h"
//ModBUS CRC-16 码modbus校验
/*
1、实时计算 CRC16
该种方式耗时比较多,但占用 FLASH、RAM 小
1CRC 寄存器初始值为 FFFF即 16 个字节全为 1
2CRC-16 / MODBUS 的多项式 A001H (1010 0000 0000 0001B) H表示 16 进制数B表示二进制数
计算步骤为:
(1).预置 16 位寄存器为十六进制 FFFF即全为 1 ,称此寄存器为 CRC 寄存器;
(2).把第一个 8 位数据与 16 位 CRC 寄存器的低位相异或,把结果放于 CRC 寄存器;
(3).检测相异或后的 CRC 寄存器的最低位,若最低位为 1CRC 寄存器先右移 1 位,再与多项式 A001H 进行异或;若为 0则 CRC 寄存器右移 1 位,无需与多项式进行异或。
(4).重复步骤 3直到右移 8 次,这样整个 8 位数据全部进行了处理;
(5).重复步骤 2 到步骤 4进行下一个 8 位数据的处理;
(6).最后得到的 CRC 寄存器即为 CRC 码。
addr需要校验的字节数组
num需要校验的字节数
返回值16 位的 CRC 校验码
*/
uint16_t crc16(uint8_t *addr,uint32_t num)
{
int i,j,temp;
uint16_t crc=0xFFFF;
for(i=0;i<num;i++)
{
crc=crc^(*addr);
for(j=0;j<8;j++)
{
temp=crc&0x0001;
crc=crc>>1;
if(temp)
{
crc=crc^0xA001;
}
}
addr++;
}
return crc;
//将 CRC 校验的高低位对换位置
// uint16_t crc1;
// crc1 = crc >> 8;
// crc1 = crc1 | (crc << 8);
// return crc1;
}
/*
2、查表计算 CRC16耗时少
从上面代码中,可以看出 CRC-16 的漏洞。无非是将待计算的数组,从头到尾单个字节按照同一算法反复计算。每个元素只有 0~255 的输入可能性,算法固定,所以算出来的值也是固定的。
于是可以提前计算出校验值,按照输入为 0~255排列为一组校验输出表。计算过程中根据输入数据进行查表从头查到尾得到最终校验值。
这样的计算方式省去了单片机的反复计算,极大缩短了计算耗时。而且可以将查表的数组类型定义为 const存放在 Flash 中,运行时不占用 RAM。虽然都是空间换时间的策略但这种方式只占用 Flash 不占用珍贵的 RAM。
addr需要校验的字节数组
num需要校验的字节数
返回值16 位的 CRC 校验码
说 明:计算结果是高位在前,需要转换才能发送
*/
uint16_t crc16_check(uint8_t* addr, uint32_t num)
{
// CRC 高位字节值表
static const uint8_t auchCRCHi[] =
{
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
} ;
// CRC 低位字节值表
static const uint8_t auchCRCLo[] =
{
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40
};
uint8_t uchCRCHi = 0xFF;
uint8_t uchCRCLo = 0xFF;
uint16_t uIndex;
while(num--)
{
uIndex = uchCRCLo ^ *addr++;
uchCRCLo = uchCRCHi^auchCRCHi[uIndex];
uchCRCHi = auchCRCLo[uIndex];
}
return (uchCRCHi<<8|uchCRCLo);
}

9
crc16/crc16.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef __CRC_16_H
#define __CRC_16_H
#include <stdint.h>
extern uint16_t crc16(uint8_t *addr,uint32_t num); // 实时计算方式
extern uint16_t crc16_check(uint8_t* addr, uint32_t num); // 查表计算方式
#endif

19
logc/LICENSE Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2020 rxi
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

83
logc/README.md Normal file
View File

@@ -0,0 +1,83 @@
# log.c
A simple logging library implemented in C99
![screenshot](https://cloud.githubusercontent.com/assets/3920290/23831970/a2415e96-0723-11e7-9886-f8f5d2de60fe.png)
## Usage
**[log.c](src/log.c?raw=1)** and **[log.h](src/log.h?raw=1)** should be dropped
into an existing project and compiled along with it. The library provides 6
function-like macros for logging:
```c
log_trace(const char *fmt, ...);
log_debug(const char *fmt, ...);
log_info(const char *fmt, ...);
log_warn(const char *fmt, ...);
log_error(const char *fmt, ...);
log_fatal(const char *fmt, ...);
```
Each function takes a printf format string followed by additional arguments:
```c
log_trace("Hello %s", "world")
```
Resulting in a line with the given format printed to stderr:
```
20:18:26 TRACE src/main.c:11: Hello world
```
#### log_set_quiet(bool enable)
Quiet-mode can be enabled by passing `true` to the `log_set_quiet()` function.
While this mode is enabled the library will not output anything to `stderr`, but
will continue to write to files and callbacks if any are set.
#### log_set_level(int level)
The current logging level can be set by using the `log_set_level()` function.
All logs below the given level will not be written to `stderr`. By default the
level is `LOG_TRACE`, such that nothing is ignored.
#### log_add_fp(FILE *fp, int level)
One or more file pointers where the log will be written can be provided to the
library by using the `log_add_fp()` function. The data written to the file
output is of the following format:
```
2047-03-11 20:18:26 TRACE src/main.c:11: Hello world
```
Any messages below the given `level` are ignored. If the library failed to add a
file pointer a value less-than-zero is returned.
#### log_add_callback(log_LogFn fn, void *udata, int level)
One or more callback functions which are called with the log data can be
provided to the library by using the `log_add_callback()` function. A callback
function is passed a `log_Event` structure containing the `line` number,
`filename`, `fmt` string, `va` printf va\_list, `level` and the given `udata`.
#### log_set_lock(log_LockFn fn, void *udata)
If the log will be written to from multiple threads a lock function can be set.
The function is passed the boolean `true` if the lock should be acquired or
`false` if the lock should be released and the given `udata` value.
#### const char* log_level_string(int level)
Returns the name of the given log level as a string.
#### LOG_USE_COLOR
If the library is compiled with `-DLOG_USE_COLOR` ANSI color escape codes will
be used when printing.
## License
This library is free software; you can redistribute it and/or modify it under
the terms of the MIT license. See [LICENSE](LICENSE) for details.

168
logc/log.c Normal file
View File

@@ -0,0 +1,168 @@
/*
* Copyright (c) 2020 rxi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "log.h"
#define MAX_CALLBACKS 32
typedef struct {
log_LogFn fn;
void *udata;
int level;
} Callback;
static struct {
void *udata;
log_LockFn lock;
int level;
bool quiet;
Callback callbacks[MAX_CALLBACKS];
} L;
static const char *level_strings[] = {
"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"
};
#ifdef LOG_USE_COLOR
static const char *level_colors[] = {
"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"
};
#endif
static void stdout_callback(log_Event *ev) {
char buf[16];
buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0';
#ifdef LOG_USE_COLOR
fprintf(
ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ",
buf, level_colors[ev->level], level_strings[ev->level],
ev->file, ev->line);
#else
fprintf(
ev->udata, "%s %-5s %s:%d: ",
buf, level_strings[ev->level], ev->file, ev->line);
#endif
vfprintf(ev->udata, ev->fmt, ev->ap);
fprintf(ev->udata, "\n");
fflush(ev->udata);
}
static void file_callback(log_Event *ev) {
char buf[64];
buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0';
fprintf(
ev->udata, "%s %-5s %s:%d: ",
buf, level_strings[ev->level], ev->file, ev->line);
vfprintf(ev->udata, ev->fmt, ev->ap);
fprintf(ev->udata, "\n");
fflush(ev->udata);
}
static void lock(void) {
if (L.lock) { L.lock(true, L.udata); }
}
static void unlock(void) {
if (L.lock) { L.lock(false, L.udata); }
}
const char* log_level_string(int level) {
return level_strings[level];
}
void log_set_lock(log_LockFn fn, void *udata) {
L.lock = fn;
L.udata = udata;
}
void log_set_level(int level) {
L.level = level;
}
void log_set_quiet(bool enable) {
L.quiet = enable;
}
int log_add_callback(log_LogFn fn, void *udata, int level) {
for (int i = 0; i < MAX_CALLBACKS; i++) {
if (!L.callbacks[i].fn) {
L.callbacks[i] = (Callback) { fn, udata, level };
return 0;
}
}
return -1;
}
int log_add_fp(FILE *fp, int level) {
return log_add_callback(file_callback, fp, level);
}
static void init_event(log_Event *ev, void *udata) {
if (!ev->time) {
time_t t = time(NULL);
ev->time = localtime(&t);
}
ev->udata = udata;
}
void log_log(int level, const char *file, int line, const char *fmt, ...) {
log_Event ev = {
.fmt = fmt,
.file = file,
.line = line,
.level = level,
};
lock();
if (!L.quiet && level >= L.level) {
init_event(&ev, stderr);
va_start(ev.ap, fmt);
stdout_callback(&ev);
va_end(ev.ap);
}
for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++) {
Callback *cb = &L.callbacks[i];
if (level >= cb->level) {
init_event(&ev, cb->udata);
va_start(ev.ap, fmt);
cb->fn(&ev);
va_end(ev.ap);
}
}
unlock();
}

49
logc/log.h Normal file
View File

@@ -0,0 +1,49 @@
/**
* Copyright (c) 2020 rxi
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the MIT license. See `log.c` for details.
*/
#ifndef LOG_H
#define LOG_H
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>
#include <time.h>
#define LOG_VERSION "0.1.0"
typedef struct {
va_list ap;
const char *fmt;
const char *file;
struct tm *time;
void *udata;
int line;
int level;
} log_Event;
typedef void (*log_LogFn)(log_Event *ev);
typedef void (*log_LockFn)(bool lock, void *udata);
enum { LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL };
#define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
#define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
#define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
#define log_warn(...) log_log(LOG_WARN, __FILE__, __LINE__, __VA_ARGS__)
#define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
#define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
const char* log_level_string(int level);
void log_set_lock(log_LockFn fn, void *udata);
void log_set_level(int level);
void log_set_quiet(bool enable);
int log_add_callback(log_LogFn fn, void *udata, int level);
int log_add_fp(FILE *fp, int level);
void log_log(int level, const char *file, int line, const char *fmt, ...);
#endif

36
test.c Normal file
View File

@@ -0,0 +1,36 @@
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include "by_cmd.h"
#include "logc/log.h"
char test_data[] = "hello world\r\n";
char buff[20] = {0};
uint8_t cmd_temp;
uint32_t buff_temp[20];
int main(int argc, char **argv)
{
// by_serial_t serial;
// by_serial_init(&serial, "/dev/ttyTHS0");
// while (1) {
// // by_serial_write(&serial, test_data, sizeof(test_data) - 1);
// // if (0 < by_serial_read(&serial, buff, 1)) {
// // printf("%c", buff[0]);
// // }
// if (by_serial_get_used_buffer_len(&serial) > 1) {
// by_serial_read(&serial, buff, 6);
// }
// printf("used buff len %d\r\n", by_serial_get_used_buffer_len(&serial));
// sleep(1);
// }
by_cmd_init();
by_cmd_send_distance_x(20.0, 1000);
return 0;
}

2392
tomlc99/toml.c Normal file

File diff suppressed because it is too large Load Diff

175
tomlc99/toml.h Normal file
View File

@@ -0,0 +1,175 @@
/*
MIT License
Copyright (c) CK Tan
https://github.com/cktan/tomlc99
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef TOML_H
#define TOML_H
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#endif
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
#define TOML_EXTERN extern "C"
#else
#define TOML_EXTERN extern
#endif
typedef struct toml_timestamp_t toml_timestamp_t;
typedef struct toml_table_t toml_table_t;
typedef struct toml_array_t toml_array_t;
typedef struct toml_datum_t toml_datum_t;
/* Parse a file. Return a table on success, or 0 otherwise.
* Caller must toml_free(the-return-value) after use.
*/
TOML_EXTERN toml_table_t *toml_parse_file(FILE *fp, char *errbuf, int errbufsz);
/* Parse a string containing the full config.
* Return a table on success, or 0 otherwise.
* Caller must toml_free(the-return-value) after use.
*/
TOML_EXTERN toml_table_t *toml_parse(char *conf, /* NUL terminated, please. */
char *errbuf, int errbufsz);
/* Free the table returned by toml_parse() or toml_parse_file(). Once
* this function is called, any handles accessed through this tab
* directly or indirectly are no longer valid.
*/
TOML_EXTERN void toml_free(toml_table_t *tab);
/* Timestamp types. The year, month, day, hour, minute, second, z
* fields may be NULL if they are not relevant. e.g. In a DATE
* type, the hour, minute, second and z fields will be NULLs.
*/
struct toml_timestamp_t {
struct { /* internal. do not use. */
int year, month, day;
int hour, minute, second, millisec;
char z[10];
} __buffer;
int *year, *month, *day;
int *hour, *minute, *second, *millisec;
char *z;
};
/*-----------------------------------------------------------------
* Enhanced access methods
*/
struct toml_datum_t {
int ok;
union {
toml_timestamp_t *ts; /* ts must be freed after use */
char *s; /* string value. s must be freed after use */
int b; /* bool value */
int64_t i; /* int value */
double d; /* double value */
} u;
};
/* on arrays: */
/* ... retrieve size of array. */
TOML_EXTERN int toml_array_nelem(const toml_array_t *arr);
/* ... retrieve values using index. */
TOML_EXTERN toml_datum_t toml_string_at(const toml_array_t *arr, int idx);
TOML_EXTERN toml_datum_t toml_bool_at(const toml_array_t *arr, int idx);
TOML_EXTERN toml_datum_t toml_int_at(const toml_array_t *arr, int idx);
TOML_EXTERN toml_datum_t toml_double_at(const toml_array_t *arr, int idx);
TOML_EXTERN toml_datum_t toml_timestamp_at(const toml_array_t *arr, int idx);
/* ... retrieve array or table using index. */
TOML_EXTERN toml_array_t *toml_array_at(const toml_array_t *arr, int idx);
TOML_EXTERN toml_table_t *toml_table_at(const toml_array_t *arr, int idx);
/* on tables: */
/* ... retrieve the key in table at keyidx. Return 0 if out of range. */
TOML_EXTERN const char *toml_key_in(const toml_table_t *tab, int keyidx);
/* ... returns 1 if key exists in tab, 0 otherwise */
TOML_EXTERN int toml_key_exists(const toml_table_t *tab, const char *key);
/* ... retrieve values using key. */
TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t *arr,
const char *key);
TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t *arr, const char *key);
TOML_EXTERN toml_datum_t toml_int_in(const toml_table_t *arr, const char *key);
TOML_EXTERN toml_datum_t toml_double_in(const toml_table_t *arr,
const char *key);
TOML_EXTERN toml_datum_t toml_timestamp_in(const toml_table_t *arr,
const char *key);
/* .. retrieve array or table using key. */
TOML_EXTERN toml_array_t *toml_array_in(const toml_table_t *tab,
const char *key);
TOML_EXTERN toml_table_t *toml_table_in(const toml_table_t *tab,
const char *key);
/*-----------------------------------------------------------------
* lesser used
*/
/* Return the array kind: 't'able, 'a'rray, 'v'alue, 'm'ixed */
TOML_EXTERN char toml_array_kind(const toml_array_t *arr);
/* For array kind 'v'alue, return the type of values
i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp, 'm'ixed
0 if unknown
*/
TOML_EXTERN char toml_array_type(const toml_array_t *arr);
/* Return the key of an array */
TOML_EXTERN const char *toml_array_key(const toml_array_t *arr);
/* Return the number of key-values in a table */
TOML_EXTERN int toml_table_nkval(const toml_table_t *tab);
/* Return the number of arrays in a table */
TOML_EXTERN int toml_table_narr(const toml_table_t *tab);
/* Return the number of sub-tables in a table */
TOML_EXTERN int toml_table_ntab(const toml_table_t *tab);
/* Return the key of a table*/
TOML_EXTERN const char *toml_table_key(const toml_table_t *tab);
/*--------------------------------------------------------------
* misc
*/
TOML_EXTERN int toml_utf8_to_ucs(const char *orig, int len, int64_t *ret);
TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]);
TOML_EXTERN void toml_set_memutil(void *(*xxmalloc)(size_t),
void (*xxfree)(void *));
/*--------------------------------------------------------------
* deprecated
*/
/* A raw value, must be processed by toml_rto* before using. */
typedef const char *toml_raw_t;
TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t *tab, const char *key);
TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t *arr, int idx);
TOML_EXTERN int toml_rtos(toml_raw_t s, char **ret);
TOML_EXTERN int toml_rtob(toml_raw_t s, int *ret);
TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t *ret);
TOML_EXTERN int toml_rtod(toml_raw_t s, double *ret);
TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double *ret, char *buf, int buflen);
TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t *ret);
#endif /* TOML_H */