initial commit
This commit is contained in:
38
.clang-format
Normal file
38
.clang-format
Normal 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
43
.gitignore
vendored
Normal 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
9
.vscode/settings.json
vendored
Normal 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
20
CMakeLists.txt
Normal 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
182
by_cmd.c
Normal 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
22
by_cmd.h
Normal 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
169
by_frame.c
Normal 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
29
by_frame.h
Normal 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
219
by_serial.c
Normal 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
22
by_serial.h
Normal 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
137
crc16/crc16.c
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
|
||||||
|
#include "crc16.h"
|
||||||
|
|
||||||
|
//ModBUS CRC-16 码(modbus)校验
|
||||||
|
|
||||||
|
/*
|
||||||
|
1、实时计算 CRC16
|
||||||
|
该种方式耗时比较多,但占用 FLASH、RAM 小
|
||||||
|
|
||||||
|
1)CRC 寄存器初始值为 FFFF;即 16 个字节全为 1;
|
||||||
|
2)CRC-16 / MODBUS 的多项式 A001H (1010 0000 0000 0001B) ‘H’表示 16 进制数,‘B’表示二进制数
|
||||||
|
|
||||||
|
计算步骤为:
|
||||||
|
(1).预置 16 位寄存器为十六进制 FFFF(即全为 1) ,称此寄存器为 CRC 寄存器;
|
||||||
|
(2).把第一个 8 位数据与 16 位 CRC 寄存器的低位相异或,把结果放于 CRC 寄存器;
|
||||||
|
(3).检测相异或后的 CRC 寄存器的最低位,若最低位为 1:CRC 寄存器先右移 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
9
crc16/crc16.h
Normal 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
19
logc/LICENSE
Normal 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
83
logc/README.md
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
# log.c
|
||||||
|
A simple logging library implemented in C99
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## 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
168
logc/log.c
Normal 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
49
logc/log.h
Normal 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
36
test.c
Normal 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
2392
tomlc99/toml.c
Normal file
File diff suppressed because it is too large
Load Diff
175
tomlc99/toml.h
Normal file
175
tomlc99/toml.h
Normal 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 */
|
||||||
Reference in New Issue
Block a user