Initial commit: Livox SDK2 source (excluding build artifacts)
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
set(DEMO_NAME livox_lidar_rmc_time_sync)
|
||||
if (WIN32)
|
||||
add_executable(${DEMO_NAME} main.cpp win/synchro.cpp)
|
||||
elseif(UNIX)
|
||||
add_executable(${DEMO_NAME} main.cpp linux/synchro.cpp)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${DEMO_NAME}
|
||||
PUBLIC
|
||||
livox_lidar_sdk_static
|
||||
)
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"MID360": {
|
||||
"lidar_net_info" : {
|
||||
"cmd_data_port": 56100,
|
||||
"push_msg_port": 56200,
|
||||
"point_data_port": 56300,
|
||||
"imu_data_port": 56400,
|
||||
"log_data_port": 56500
|
||||
},
|
||||
"host_net_info" : {
|
||||
"cmd_data_ip" : "192.168.1.5",
|
||||
"cmd_data_port": 56101,
|
||||
"push_msg_ip": "192.168.1.5",
|
||||
"push_msg_port": 56201,
|
||||
"point_data_ip": "192.168.1.5",
|
||||
"point_data_port": 56301,
|
||||
"imu_data_ip" : "192.168.1.5",
|
||||
"imu_data_port": 56401,
|
||||
"log_data_ip" : "192.168.1.5",
|
||||
"log_data_port": 56501
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"HAP": {
|
||||
"lidar_net_info" : {
|
||||
"cmd_data_port" : 56000,
|
||||
"push_msg_port" : 0,
|
||||
"point_data_port": 57000,
|
||||
"imu_data_port" : 58000,
|
||||
"log_data_port" : 59000
|
||||
},
|
||||
"host_net_info" : [
|
||||
{
|
||||
"host_ip" : "192.168.1.5",
|
||||
"multicast_ip" : "224.1.1.5",
|
||||
"cmd_data_port" : 56000,
|
||||
"push_msg_port" : 0,
|
||||
"point_data_port": 57000,
|
||||
"imu_data_port" : 58000,
|
||||
"log_data_port" : 59000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2022 Livox. All rights reserved.
|
||||
//
|
||||
// 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 "../synchro.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
Synchro::Synchro() {
|
||||
fd_ = 0;
|
||||
is_quit_ = false;
|
||||
rmc_buff_.resize(128,0);
|
||||
}
|
||||
|
||||
Synchro::~Synchro() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void Synchro::SetBaudRate(BaudRate baudrate) {
|
||||
baudrate_ = baudrate;
|
||||
}
|
||||
|
||||
void Synchro::SetParity(Parity parity) {
|
||||
parity_ = parity;
|
||||
}
|
||||
|
||||
void Synchro::SetPortName(std::string port_name) {
|
||||
port_name_ = std::move(port_name);
|
||||
}
|
||||
|
||||
bool Synchro::Start() {
|
||||
if (!Open()) {
|
||||
return false;
|
||||
}
|
||||
is_quit_ = false;
|
||||
listener_ = std::make_shared<std::thread>(&Synchro::IOLoop, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Synchro::Stop() {
|
||||
is_quit_ = true;
|
||||
if (listener_) {
|
||||
listener_->join();
|
||||
listener_ = nullptr;
|
||||
}
|
||||
Close();
|
||||
}
|
||||
|
||||
void Synchro::IOLoop() {
|
||||
uint8_t buff[READ_BUF];
|
||||
size_t size = 0;
|
||||
while (!is_quit_) {
|
||||
if (0 < (size = Read(buff, READ_BUF))) {
|
||||
Decode(buff, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Synchro::ParseGps(uint8_t in_byte) {
|
||||
if (cur_len_ < strlen(kGPRMC)) {
|
||||
rmc_buff_[0] = rmc_buff_[1];
|
||||
rmc_buff_[1] = rmc_buff_[2];
|
||||
rmc_buff_[2] = rmc_buff_[3];
|
||||
rmc_buff_[3] = rmc_buff_[4];
|
||||
rmc_buff_[4] = rmc_buff_[5];
|
||||
rmc_buff_[5] = in_byte;
|
||||
cur_len_++;
|
||||
|
||||
if (cur_len_ == strlen(kGPRMC)) {
|
||||
if (strncmp((const char*)&rmc_buff_[0], kGPRMC, strlen(kGPRMC)) != 0 && \
|
||||
strncmp((const char*)&rmc_buff_[0], kGNRMC, strlen(kGNRMC)) != 0) {
|
||||
cur_len_--;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cur_len_ >= rmc_buff_.size()) {
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
rmc_buff_[cur_len_] = in_byte;
|
||||
/** Checksum $GPRMC/$GNRMC. */
|
||||
if (rmc_buff_[cur_len_ - 2] == '*') {
|
||||
uint8_t result = 0;
|
||||
for (int i = 1; i < cur_len_ - 2; i++) {
|
||||
result ^= rmc_buff_[i];
|
||||
}
|
||||
char crc[3] = {0};
|
||||
uint32_t crc_num = 0;
|
||||
strncpy(crc, &rmc_buff_[cur_len_ - 1], 2);
|
||||
sscanf(crc, "%x", &crc_num);
|
||||
result ^= (uint8_t)crc_num;
|
||||
if (result == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
cur_len_++;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Synchro::SetSyncTimerCallback(UtcTimerCallback cb) {
|
||||
sync_timer_cb_ = cb;
|
||||
}
|
||||
|
||||
void Synchro::Decode(uint8_t * buff, size_t size) {
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (ParseGps(buff[i])) {
|
||||
if (sync_timer_cb_) {
|
||||
sync_timer_cb_(&rmc_buff_.at(0), cur_len_);
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Synchro::Clear() {
|
||||
cur_len_ = 0;
|
||||
std::fill(rmc_buff_.begin(), rmc_buff_.end(), 0);
|
||||
}
|
||||
|
||||
bool Synchro::Open() {
|
||||
fd_ = open(port_name_.c_str(), O_RDONLY | O_NOCTTY | O_NONBLOCK);
|
||||
if (fd_ < 0) {
|
||||
printf("Open %s serials fail!\n", port_name_.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set baudrate and parity,etc. */
|
||||
Setup(baudrate_, parity_);
|
||||
printf("Set baudrate success.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Synchro::Close() {
|
||||
if (fd_ > 0) {
|
||||
/* Flush the port */
|
||||
tcflush(fd_,TCOFLUSH);
|
||||
tcflush(fd_,TCIFLUSH);
|
||||
|
||||
close(fd_);
|
||||
}
|
||||
fd_ = 0;
|
||||
}
|
||||
|
||||
/* Sets up the port parameters */
|
||||
int Synchro::Setup(enum BaudRate baud, enum Parity parity) {
|
||||
static uint32_t baud_map[19] = {
|
||||
B2400, B4800, B9600, B19200, B38400, B57600,B115200, B230400
|
||||
};
|
||||
tcflag_t baudrate;
|
||||
struct termios options;
|
||||
|
||||
/* Clear old setting completely,must add here for A3 CDC serial */
|
||||
tcgetattr(fd_, &options);
|
||||
memset(&options, 0, sizeof(options));
|
||||
tcflush(fd_, TCIOFLUSH);
|
||||
tcsetattr(fd_, TCSANOW, &options);
|
||||
// usleep(100);
|
||||
|
||||
/* Minimum number of characters to read */
|
||||
options.c_cc[VMIN] = 0;
|
||||
/* Time to wait for data */
|
||||
options.c_cc[VTIME] = 100;
|
||||
|
||||
/* Enable the receiver and set local mode... */
|
||||
options.c_cflag |= (CLOCAL | CREAD);
|
||||
|
||||
/* Set boadrate */
|
||||
baudrate = baud_map[baud];
|
||||
cfsetispeed(&options, baudrate);
|
||||
cfsetospeed(&options, baudrate);
|
||||
printf("[Baudrate]: %d %u\r\n", baud, baudrate);
|
||||
|
||||
switch (parity) {
|
||||
case P_8N1:
|
||||
/* No parity (8N1) */
|
||||
options.c_cflag &= ~PARENB;
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
options.c_cflag &= ~CSIZE;
|
||||
options.c_cflag |= CS8;
|
||||
break;
|
||||
case P_7E1:
|
||||
/* Even parity (7E1) */
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag &= ~PARODD;
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
options.c_cflag &= ~CSIZE;
|
||||
options.c_cflag |= CS7;
|
||||
break;
|
||||
case P_7O1:
|
||||
/* Odd parity (7O1) */
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag |= PARODD;
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
options.c_cflag &= ~CSIZE;
|
||||
options.c_cflag |= CS7;
|
||||
break;
|
||||
case P_7S1:
|
||||
/* Space parity is setup the same as no parity (7S1) */
|
||||
options.c_cflag &= ~PARENB;
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
options.c_cflag &= ~CSIZE;
|
||||
options.c_cflag |= CS8;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* flush the port */
|
||||
tcflush(fd_, TCIOFLUSH);
|
||||
|
||||
/* send new config to the port */
|
||||
tcsetattr(fd_, TCSANOW, &options);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t Synchro::Read(uint8_t *buffer, size_t size) {
|
||||
if (fd_ > 0) {
|
||||
auto len = read(fd_, buffer, size);
|
||||
return len < 0 ? 0 : len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2022 Livox. All rights reserved.
|
||||
//
|
||||
// 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 "livox_lidar_def.h"
|
||||
#include "livox_lidar_api.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
#include "synchro.h"
|
||||
|
||||
static void WorkModeCallback(livox_status status, uint32_t handle,LivoxLidarAsyncControlResponse *response, void *client_data) {
|
||||
if (response == nullptr) {
|
||||
return;
|
||||
}
|
||||
printf("WorkModeCallack, status:%u, handle:%u, ret_code:%u, error_key:%u",
|
||||
status, handle, response->ret_code, response->error_key);
|
||||
|
||||
}
|
||||
|
||||
static void LidarInfoChangeCallback(const uint32_t handle, const LivoxLidarInfo* info, void* client_data) {
|
||||
if (info == nullptr) {
|
||||
printf("lidar info change callback failed, the info is nullptr.\n");
|
||||
return;
|
||||
}
|
||||
printf("LidarInfoChangeCallback Lidar handle: %u SN: %s\n", handle, info->sn);
|
||||
|
||||
// set the work mode to kLivoxLidarNormal, namely start the lidar
|
||||
SetLivoxLidarWorkMode(handle, kLivoxLidarNormal, WorkModeCallback, nullptr);
|
||||
|
||||
Synchro& synchro = Synchro::GetInstance();
|
||||
#ifdef WIN32
|
||||
synchro.SetPortName("COM3");
|
||||
#else
|
||||
synchro.SetPortName("/dev/ttyACM0");
|
||||
#endif
|
||||
|
||||
/** Set Synchro's Baudrate: 9600. */
|
||||
synchro.SetBaudRate(BR9600);
|
||||
/** Set Synchro's Parity: No parity (8N1). */
|
||||
synchro.SetParity(P_8N1);
|
||||
/** SyncTimer Callback will trigger when Synchro's GPRMC/GNRMC signal is ready. */
|
||||
synchro.SetSyncTimerCallback([handle](const char* rmc, uint16_t rmc_length) {
|
||||
printf("GPRMC is:%s", rmc);
|
||||
SetLivoxLidarRmcSyncTime(handle, rmc, rmc_length, [](livox_status status, uint32_t handle, LivoxLidarRmcSyncTimeResponse* data, void* client_data){
|
||||
std::cout << "Lidar handle:" << handle << " response is: " << +data->ret << std::endl;
|
||||
}, nullptr);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(800));
|
||||
});
|
||||
if (synchro.Start()) {
|
||||
printf("Synchro start success.");
|
||||
} else {
|
||||
printf("Synchro start failed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void LivoxLidarPushMsgCallback(const uint32_t handle, const uint8_t dev_type, const char* info, void* client_data) {
|
||||
struct in_addr tmp_addr;
|
||||
tmp_addr.s_addr = handle;
|
||||
std::cout << "handle: " << handle << ", ip: " << inet_ntoa(tmp_addr) << ", push msg info: " << std::endl;
|
||||
std::cout << info << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
if (argc != 2) {
|
||||
printf("Params Invalid, must input config path.\n");
|
||||
return -1;
|
||||
}
|
||||
const std::string path = argv[1];
|
||||
|
||||
// REQUIRED, to init Livox SDK2
|
||||
if (!LivoxLidarSdkInit(path.c_str())) {
|
||||
printf("Livox Init Failed\n");
|
||||
LivoxLidarSdkUninit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetLivoxLidarInfoCallback(LivoxLidarPushMsgCallback, nullptr);
|
||||
|
||||
// REQUIRED, to get a handle to targeted lidar and set its work mode to NORMAL
|
||||
SetLivoxLidarInfoChangeCallback(LidarInfoChangeCallback, nullptr);
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(300000);
|
||||
#else
|
||||
sleep(300);
|
||||
#endif
|
||||
LivoxLidarSdkUninit();
|
||||
printf("Livox Quick Start Demo End!\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"MID360": {
|
||||
"lidar_net_info" : {
|
||||
"cmd_data_port" : 56100,
|
||||
"push_msg_port" : 56200,
|
||||
"point_data_port": 56300,
|
||||
"imu_data_port" : 56400,
|
||||
"log_data_port" : 56500
|
||||
},
|
||||
"host_net_info" : [
|
||||
{
|
||||
"host_ip" : "192.168.1.5",
|
||||
"multicast_ip" : "224.1.1.5",
|
||||
"cmd_data_port" : 56101,
|
||||
"push_msg_port" : 56201,
|
||||
"point_data_port": 56301,
|
||||
"imu_data_port" : 56401,
|
||||
"log_data_port" : 56501
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"Mid360s": {
|
||||
"lidar_net_info" : {
|
||||
"cmd_data_port" : 56100,
|
||||
"push_msg_port" : 56200,
|
||||
"point_data_port": 56300,
|
||||
"imu_data_port" : 56400,
|
||||
"log_data_port" : 56500
|
||||
},
|
||||
"host_net_info" : [
|
||||
{
|
||||
"host_ip" : "192.168.1.50",
|
||||
"multicast_ip" : "224.1.1.5",
|
||||
"cmd_data_port" : 56101,
|
||||
"push_msg_port" : 56201,
|
||||
"point_data_port": 56301,
|
||||
"imu_data_port" : 56401,
|
||||
"log_data_port" : 56501
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2022 Livox. All rights reserved.
|
||||
//
|
||||
// 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 SYNCHRO_H_
|
||||
#define SYNCHRO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
using UtcTimerCallback = std::function<void(const char* rmc, uint16_t rmc_length)>;
|
||||
|
||||
# define READ_BUF (256)
|
||||
const char * const kGPRMC{"$GPRMC"};
|
||||
const char * const kGNRMC{"$GNRMC"};
|
||||
|
||||
enum Parity {
|
||||
P_8N1, /* No parity (8N1) */
|
||||
P_7E1, /* Even parity (7E1)*/
|
||||
P_7O1, /* Odd parity (7O1) */
|
||||
P_7S1 /* Space parity is setup the same as no parity (7S1) */
|
||||
};
|
||||
|
||||
enum BaudRate {
|
||||
BR2400,
|
||||
BR4800,
|
||||
BR9600,
|
||||
BR19200,
|
||||
BR38400,
|
||||
BR57600,
|
||||
BR115200,
|
||||
BR230400,
|
||||
BR460800,
|
||||
BR500000,
|
||||
BR576000,
|
||||
BR921600,
|
||||
BR1152000,
|
||||
BR1500000,
|
||||
BR2000000,
|
||||
BR2500000,
|
||||
BR3000000,
|
||||
BR3500000,
|
||||
BR4000000,
|
||||
};
|
||||
|
||||
|
||||
class Synchro {
|
||||
|
||||
public:
|
||||
Synchro();
|
||||
~Synchro();
|
||||
|
||||
static Synchro& GetInstance() {
|
||||
static Synchro synchro;
|
||||
return synchro;
|
||||
}
|
||||
|
||||
bool Start();
|
||||
void Stop();
|
||||
void SetBaudRate(BaudRate baudrate);
|
||||
void SetPortName(std::string port_name);
|
||||
void SetParity(Parity parity);
|
||||
void SetSyncTimerCallback(UtcTimerCallback cb);
|
||||
|
||||
private:
|
||||
int Setup(enum BaudRate baud, enum Parity parity);
|
||||
void Close();
|
||||
bool Open();
|
||||
void IOLoop();
|
||||
size_t Read(uint8_t *buffer, size_t size);
|
||||
void Decode(uint8_t* buff, size_t size);
|
||||
bool ParseGps(uint8_t in_byte);
|
||||
void Clear();
|
||||
|
||||
#ifdef WIN32
|
||||
HANDLE hfile_;
|
||||
#else
|
||||
int fd_;
|
||||
#endif
|
||||
|
||||
enum BaudRate baudrate_;
|
||||
enum Parity parity_;
|
||||
std::string port_name_;
|
||||
|
||||
std::function<void(const char* rmc, uint16_t rmc_length)> sync_timer_cb_;
|
||||
|
||||
bool is_quit_;
|
||||
std::shared_ptr<std::thread> listener_;
|
||||
|
||||
std::vector<char> rmc_buff_;
|
||||
uint16_t cur_len_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,226 @@
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2022 Livox. All rights reserved.
|
||||
//
|
||||
// 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 "../synchro.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <Windows.h>
|
||||
|
||||
Synchro::Synchro() {
|
||||
hfile_ = INVALID_HANDLE_VALUE;
|
||||
is_quit_ = false;
|
||||
rmc_buff_.resize(128,0);
|
||||
}
|
||||
|
||||
Synchro::~Synchro() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void Synchro::SetBaudRate(BaudRate baudrate) {
|
||||
baudrate_ = baudrate;
|
||||
}
|
||||
|
||||
void Synchro::SetParity(Parity parity) {
|
||||
parity_ = parity;
|
||||
}
|
||||
|
||||
void Synchro::SetPortName(std::string port_name) {
|
||||
port_name_ = std::move(port_name);
|
||||
}
|
||||
|
||||
bool Synchro::Start() {
|
||||
if (!Open()) {
|
||||
return false;
|
||||
}
|
||||
is_quit_ = false;
|
||||
listener_ = std::make_shared<std::thread>(&Synchro::IOLoop, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Synchro::Stop() {
|
||||
is_quit_ = true;
|
||||
if (listener_) {
|
||||
listener_->join();
|
||||
listener_ = nullptr;
|
||||
}
|
||||
Close();
|
||||
}
|
||||
|
||||
void Synchro::IOLoop() {
|
||||
uint8_t buff[READ_BUF];
|
||||
size_t size = 0;
|
||||
while (!is_quit_) {
|
||||
if (0 < (size = Read(buff, READ_BUF))) {
|
||||
Decode(buff, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Synchro::ParseGps(uint8_t in_byte) {
|
||||
if (cur_len_ < strlen(kGPRMC)) {
|
||||
rmc_buff_[0] = rmc_buff_[1];
|
||||
rmc_buff_[1] = rmc_buff_[2];
|
||||
rmc_buff_[2] = rmc_buff_[3];
|
||||
rmc_buff_[3] = rmc_buff_[4];
|
||||
rmc_buff_[4] = rmc_buff_[5];
|
||||
rmc_buff_[5] = in_byte;
|
||||
cur_len_++;
|
||||
|
||||
if (cur_len_ == strlen(kGPRMC)) {
|
||||
if (strncmp((const char*)&rmc_buff_[0], kGPRMC, strlen(kGPRMC)) != 0 && \
|
||||
strncmp((const char*)&rmc_buff_[0], kGNRMC, strlen(kGNRMC)) != 0) {
|
||||
cur_len_--;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cur_len_ >= rmc_buff_.size()) {
|
||||
Clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
rmc_buff_[cur_len_] = in_byte;
|
||||
/** Checksum $GPRMC/$GNRMC. */
|
||||
if (rmc_buff_[cur_len_ - 2] == '*') {
|
||||
uint8_t result = 0;
|
||||
for (int i = 1; i < cur_len_ - 2; i++) {
|
||||
result ^= rmc_buff_[i];
|
||||
}
|
||||
char crc[3] = {0};
|
||||
uint32_t crc_num = 0;
|
||||
strncpy(crc, &rmc_buff_[cur_len_ - 1], 2);
|
||||
sscanf(crc, "%x", &crc_num);
|
||||
result ^= (uint8_t)crc_num;
|
||||
if (result == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
cur_len_++;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Synchro::SetSyncTimerCallback(UtcTimerCallback cb) {
|
||||
sync_timer_cb_ = cb;
|
||||
}
|
||||
|
||||
void Synchro::Decode(uint8_t * buff, size_t size) {
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (ParseGps(buff[i])) {
|
||||
if (sync_timer_cb_) {
|
||||
sync_timer_cb_(&rmc_buff_.at(0), cur_len_);
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Synchro::Clear() {
|
||||
cur_len_ = 0;
|
||||
std::fill(rmc_buff_.begin(), rmc_buff_.end(), 0);
|
||||
}
|
||||
|
||||
bool Synchro::Open() {
|
||||
hfile_ = CreateFile(port_name_.c_str(),
|
||||
GENERIC_READ,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (hfile_ == INVALID_HANDLE_VALUE) {
|
||||
printf("Open %s serials fail!\n", port_name_.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set baudrate and parity,etc. */
|
||||
Setup(baudrate_, parity_);
|
||||
printf("Set baudrate success.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Synchro::Close() {
|
||||
if (hfile_ != INVALID_HANDLE_VALUE) {
|
||||
PurgeComm(hfile_, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
|
||||
CloseHandle(hfile_);
|
||||
}
|
||||
hfile_ = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
/* Sets up the port parameters */
|
||||
int Synchro::Setup(enum BaudRate baud, enum Parity parity) {
|
||||
static uint32_t baud_map[19] = {\
|
||||
2400, 4800, 9600, 19200, 38400, 57600,115200, 230400,\
|
||||
460800, 500000, 576000,921600,1152000, 1500000, 2000000,\
|
||||
2500000, 3000000, 3500000, 4000000\
|
||||
};
|
||||
DCB dcb;
|
||||
GetCommState(hfile_, &dcb);
|
||||
dcb.BaudRate = DWORD(baud_map[baud]);
|
||||
switch (parity) {
|
||||
case P_8N1:
|
||||
/* No parity (8N1) */
|
||||
dcb.ByteSize = 8;
|
||||
dcb.Parity = NOPARITY;
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
break;
|
||||
case P_7E1:
|
||||
/* Even parity (7E1) */
|
||||
dcb.ByteSize = 7;
|
||||
dcb.Parity = EVENPARITY;
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
break;
|
||||
case P_7O1:
|
||||
/* Odd parity (7O1) */
|
||||
dcb.ByteSize = 7;
|
||||
dcb.Parity = ODDPARITY;
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
break;
|
||||
case P_7S1:
|
||||
/* Space parity is setup the same as no parity (7S1) */
|
||||
dcb.ByteSize = 7;
|
||||
dcb.Parity = SPACEPARITY;
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
SetCommState(hfile_, &dcb);
|
||||
PurgeComm(hfile_, PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t Synchro::Read(uint8_t *buffer, size_t size) {
|
||||
DWORD len = 0;
|
||||
if (hfile_ != INVALID_HANDLE_VALUE) {
|
||||
ReadFile(hfile_, buffer, size, &len, NULL);
|
||||
return len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user