对上交代码进行修改,主要将能量机关去掉,添加了同济的PnP位姿解算,但是同济有个四元数,获取IMU部分没有启用,可能导致精度不够。当前还存在反陀螺功能,修改为逻辑和弹道预测相结合,主要在时间关系上进行调整。
This commit is contained in:
120
others/src/additions.cpp
Normal file
120
others/src/additions.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
//
|
||||
// Created by sjturm on 19-5-17.
|
||||
//
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include <opencv2/videoio/videoio_c.h>
|
||||
#include <additions.h>
|
||||
#include <camera/camera_wrapper.h>
|
||||
#include <armor_finder/armor_finder.h>
|
||||
#include <log.h>
|
||||
|
||||
#define RECEIVE_LOG_LEVEL LOG_MSG
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
extern WrapperHead *video;
|
||||
|
||||
extern Serial serial;
|
||||
extern uint8_t last_state;
|
||||
|
||||
extern ArmorFinder armor_finder;
|
||||
|
||||
void uartReceive(Serial *pSerial) {
|
||||
char buffer[40];
|
||||
LOGM(STR_CTR(WORD_LIGHT_WHITE, "data receive start!"));
|
||||
while (true) {
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
pSerial->ReadData((uint8_t *) buffer, sizeof(mcu_data)+1);
|
||||
if (buffer[sizeof(mcu_data)] == '\n') {
|
||||
memcpy(&mcu_data, buffer, sizeof(mcu_data));
|
||||
LOGM("Get, state:%c, mark:%d!", mcu_data.state, (int) mcu_data.mark);
|
||||
LOGM("Get yaw: %f, pitch: %f!", mcu_data.curr_yaw, mcu_data.curr_pitch);
|
||||
// static int t = time(nullptr);
|
||||
// static int cnt = 0;
|
||||
// if(time(nullptr) > t){
|
||||
// t = time(nullptr);
|
||||
// LOGM("fps:%d", cnt);
|
||||
// cnt = 0;
|
||||
// }else{
|
||||
// cnt++;
|
||||
// }
|
||||
}else{
|
||||
// LOGW("corrupt data!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cv::VideoWriter initVideoWriter(const std::string &filename_prefix) {
|
||||
cv::VideoWriter video;
|
||||
std::ifstream in(filename_prefix + "cnt.txt");
|
||||
int cnt = 0;
|
||||
if (in.is_open()) {
|
||||
in >> cnt;
|
||||
in.close();
|
||||
}
|
||||
std::string file_name = filename_prefix + std::to_string(cnt) + ".avi";
|
||||
cnt++;
|
||||
std::ofstream out(filename_prefix + "cnt.txt");
|
||||
if (out.is_open()) {
|
||||
out << cnt << std::endl;
|
||||
out.close();
|
||||
}
|
||||
video.open(file_name, CV_FOURCC('P', 'I', 'M', '1'), 90, cv::Size(640, 480), true);
|
||||
return video;
|
||||
}
|
||||
|
||||
bool checkReconnect(bool is_camera_connect) {
|
||||
if (!is_camera_connect) {
|
||||
int curr_gain = ((CameraWrapper* )video)->gain;
|
||||
int curr_exposure = ((CameraWrapper* )video)->exposure;
|
||||
int curr_mode = ((CameraWrapper* )video)->mode; // 获取原始模式
|
||||
|
||||
delete video;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 等待硬件释放
|
||||
video = new CameraWrapper(curr_exposure, curr_gain, curr_mode/*, "armor"*/);
|
||||
//video = new CameraWrapper(curr_exposure, curr_gain, 0/*, "armor"*/);
|
||||
is_camera_connect = video->init();
|
||||
}
|
||||
return is_camera_connect;
|
||||
}
|
||||
|
||||
auto video_writer = initVideoWriter(PROJECT_DIR"/video/");
|
||||
|
||||
void saveVideos(const cv::Mat &gimbal_src) {
|
||||
if (!gimbal_src.empty()) {
|
||||
video_writer.write(gimbal_src);
|
||||
} else return;
|
||||
}
|
||||
|
||||
void showOrigin(const cv::Mat &src) {
|
||||
if (!src.empty()) {
|
||||
imshow("origin", src);
|
||||
cv::waitKey(1);
|
||||
} else return;
|
||||
}
|
||||
|
||||
void extract(cv::Mat &src) {//图像预处理,将视频切成640×480的大小
|
||||
if (src.empty()) return;
|
||||
float length = static_cast<float>(src.cols);
|
||||
float width = static_cast<float>(src.rows);
|
||||
if (length / width > 1280.0 / 1024.0) {
|
||||
length *= 1024 / width;
|
||||
resize(src, src, cv::Size(length, 1024));
|
||||
src = src(Rect((length - 1280) / 2, 0, 1280, 1024));
|
||||
} else {
|
||||
width *= 1280.0 / length;
|
||||
resize(src, src, cv::Size(1280, width));
|
||||
src = src(Rect(0, (width - 1024) / 2, 1280, 1024));
|
||||
}
|
||||
}
|
||||
|
||||
double getPointLength(const cv::Point2f &p) {
|
||||
return sqrt(p.x * p.x + p.y * p.y);
|
||||
}
|
||||
189
others/src/camera/camera_wrapper.cpp
Normal file
189
others/src/camera/camera_wrapper.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
//
|
||||
// Created by zhikun on 18-11-7.
|
||||
//
|
||||
#include <iostream>
|
||||
#include <camera/camera_wrapper.h>
|
||||
#include <log.h>
|
||||
#include <additions.h>
|
||||
#include <options.h>
|
||||
#include <config/setconfig.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
CameraWrapper::CameraWrapper(int exposure, int gain, int camera_mode, const std::string &n) :
|
||||
name(n),
|
||||
init_done(false),
|
||||
mode(camera_mode),
|
||||
camera_cnts(2),
|
||||
camera_status(-1),
|
||||
rgb_buffer(nullptr),
|
||||
channel(3),
|
||||
gain(gain),
|
||||
exposure(exposure){
|
||||
}
|
||||
|
||||
void cameraCallback(CameraHandle hCamera, BYTE *pFrameBuffer, tSdkFrameHead* pFrameHead,PVOID pContext){
|
||||
CameraWrapper *c = (CameraWrapper*)pContext;
|
||||
CameraImageProcess(hCamera, pFrameBuffer, c->rgb_buffer, pFrameHead);
|
||||
// 使用 cv::Mat 替代 IplImage
|
||||
cv::Mat img(pFrameHead->iHeight, pFrameHead->iWidth,
|
||||
c->channel == 3 ? CV_8UC3 : CV_8UC1,
|
||||
c->rgb_buffer, pFrameHead->iWidth * c->channel);
|
||||
c->src_queue.push(img.clone());
|
||||
}
|
||||
|
||||
bool CameraWrapper::init() {
|
||||
CameraSdkInit(1);
|
||||
int camera_enumerate_device_status = CameraEnumerateDevice(camera_enum_list, &camera_cnts);
|
||||
if (camera_enumerate_device_status != CAMERA_STATUS_SUCCESS) {
|
||||
LOGE("CameraEnumerateDevice fail with %d!", camera_enumerate_device_status);
|
||||
return false;
|
||||
}
|
||||
if (camera_cnts == 0) {
|
||||
LOGE("No camera device detected!");
|
||||
return false;
|
||||
} else if (camera_cnts >= 1) {
|
||||
LOGM("%d camera device detected!", camera_cnts);
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < camera_cnts; i++) {
|
||||
camera_status = CameraInit(&camera_enum_list[i], -1, -1, &h_camera);
|
||||
if (camera_status != CAMERA_STATUS_SUCCESS) {
|
||||
CameraUnInit(h_camera);
|
||||
continue;
|
||||
}
|
||||
CameraGetFriendlyName(h_camera, camera_name);
|
||||
if (name == "NULL" || strcmp(name.data(), camera_name) == 0) {
|
||||
break;
|
||||
}
|
||||
CameraUnInit(h_camera);
|
||||
}
|
||||
if (i >= camera_cnts) {
|
||||
LOGE("No device name %s or device open error!!", name.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto status = CameraGetCapability(h_camera, &tCapability);
|
||||
if (status != CAMERA_STATUS_SUCCESS) {
|
||||
cout << "CameraGetCapability return error code " << status << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
rgb_buffer = (unsigned char *) malloc(tCapability.sResolutionRange.iHeightMax *
|
||||
tCapability.sResolutionRange.iWidthMax * 3);
|
||||
#ifdef Windows
|
||||
char filepath[200];
|
||||
sprintf(filepath, PROJECT_DIR"/others/%s.Config", name.data());
|
||||
if (CameraReadParameterFromFile(h_camera, filepath) != CAMERA_STATUS_SUCCESS) {
|
||||
LOGE("Load parameter %s from file fail!", filepath);
|
||||
return false;
|
||||
}
|
||||
if (CameraLoadParameter(h_camera, PARAMETER_TEAM_A) != CAMERA_STATUS_SUCCESS) {
|
||||
LOGE("CameraLoadParameter %s fail!", filepath);
|
||||
return false;
|
||||
}
|
||||
LOGM("successfully loaded %s!", filepath);
|
||||
#elif defined(Linux)
|
||||
CameraReadParameterFromFile(h_camera, PROJECT_DIR"/others/MV-UB31-Group0.config");
|
||||
CameraLoadParameter(h_camera, PARAMETER_TEAM_A);
|
||||
CameraSetAeState(h_camera, false);
|
||||
CameraSetExposureTime(h_camera, exposure * 1000);
|
||||
CameraSetAnalogGain(h_camera, gain);
|
||||
#endif
|
||||
double t;
|
||||
int g;
|
||||
CameraGetExposureTime(h_camera, &t);
|
||||
CameraGetAnalogGain(h_camera, &g);
|
||||
LOGM("Exposure time: %lfms, gain:%d", t / 1000.0, g);
|
||||
/*让SDK进入工作模式,开始接收来自相机发送的图像
|
||||
数据。如果当前相机是触发模式,则需要接收到
|
||||
触发帧以后才会更新图像。 */
|
||||
CameraPlay(h_camera);
|
||||
|
||||
/*其他的相机参数设置
|
||||
例如 CameraSetExposureTime CameraGetExposureTime 设置/读取曝光时间
|
||||
CameraSetImageResolution CameraGetImageResolution 设置/读取分辨率
|
||||
CameraSetGamma、CameraSetContrast、CameraSetGain等设置图像伽马、对比度、RGB数字增益等等。
|
||||
CameraGetFriendlyName CameraSetFriendlyName 获取/设置相机名称(该名称可写入相机硬件)
|
||||
*/
|
||||
cout << tCapability.sIspCapacity.bMonoSensor << endl;
|
||||
if (tCapability.sIspCapacity.bMonoSensor) {
|
||||
channel = 1;
|
||||
CameraSetIspOutFormat(h_camera, CAMERA_MEDIA_TYPE_MONO8);
|
||||
LOGM("camera %s mono ", camera_name);
|
||||
} else {
|
||||
channel = 3;
|
||||
CameraSetIspOutFormat(h_camera, CAMERA_MEDIA_TYPE_BGR8);
|
||||
LOGM("camera %s color ", camera_name);
|
||||
}
|
||||
if(mode == 2){
|
||||
CameraSetCallbackFunction(h_camera, cameraCallback, this, nullptr);
|
||||
}
|
||||
init_done = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CameraWrapper::read(cv::Mat &src) {
|
||||
if(init_done) {
|
||||
if (mode == 0)return readProcessed(src);
|
||||
if (mode == 1)return readRaw(src);
|
||||
if (mode == 2)return readCallback(src);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CameraWrapper::readRaw(cv::Mat &src) {
|
||||
if (CameraGetImageBuffer(h_camera, &frame_info, &pby_buffer, 500) == CAMERA_STATUS_SUCCESS) {
|
||||
// 使用 cv::Mat 替代 IplImage
|
||||
cv::Mat img(frame_info.iHeight, frame_info.iWidth, CV_8UC1, pby_buffer, frame_info.iWidth);
|
||||
src = img.clone();
|
||||
|
||||
//在成功调用CameraGetImageBuffer后,必须调用CameraReleaseImageBuffer来释放获得的buffer。
|
||||
//否则再次调用CameraGetImageBuffer时,程序将被挂起一直阻塞,直到其他线程中调用CameraReleaseImageBuffer来释放了buffer
|
||||
CameraReleaseImageBuffer(h_camera, pby_buffer);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
src = cv::Mat();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CameraWrapper::readProcessed(cv::Mat &src) {
|
||||
if (CameraGetImageBuffer(h_camera, &frame_info, &pby_buffer, 500) == CAMERA_STATUS_SUCCESS) {
|
||||
CameraImageProcess(h_camera, pby_buffer, rgb_buffer,
|
||||
&frame_info); // this function is super slow, better not to use it.
|
||||
// 使用 cv::Mat 替代 IplImage
|
||||
int mat_type = (channel == 3) ? CV_8UC3 : CV_8UC1;
|
||||
cv::Mat img(frame_info.iHeight, frame_info.iWidth, mat_type, rgb_buffer, frame_info.iWidth * channel);
|
||||
src = img.clone();
|
||||
//在成功调用CameraGetImageBuffer后,必须调用CameraReleaseImageBuffer来释放获得的buffer。
|
||||
//否则再次调用CameraGetImageBuffer时,程序将被挂起一直阻塞,直到其他线程中调用CameraReleaseImageBuffer来释放了buffer
|
||||
CameraReleaseImageBuffer(h_camera, pby_buffer);
|
||||
return true;
|
||||
} else {
|
||||
src = cv::Mat();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CameraWrapper::readCallback(cv::Mat &src) {
|
||||
systime ts, te;
|
||||
getsystime(ts);
|
||||
while(src_queue.empty()){
|
||||
getsystime(te);
|
||||
if(getTimeIntervalms(te, ts) > 500){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return src_queue.pop(src);
|
||||
}
|
||||
|
||||
CameraWrapper::~CameraWrapper() {
|
||||
CameraUnInit(h_camera);
|
||||
//注意,先反初始化后再free
|
||||
if (rgb_buffer != nullptr)
|
||||
free(rgb_buffer);
|
||||
}
|
||||
21
others/src/camera/video_wrapper.cpp
Normal file
21
others/src/camera/video_wrapper.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Created by xixiliadorabarry on 1/24/19.
|
||||
//
|
||||
|
||||
#include "camera/video_wrapper.h"
|
||||
|
||||
|
||||
VideoWrapper::VideoWrapper(const std::string &filename) {
|
||||
video.open(filename);
|
||||
}
|
||||
|
||||
VideoWrapper::~VideoWrapper() = default;
|
||||
|
||||
|
||||
bool VideoWrapper::init() {
|
||||
return video.isOpened();
|
||||
}
|
||||
|
||||
bool VideoWrapper::read(cv::Mat &src) {
|
||||
return video.read(src);
|
||||
}
|
||||
135
others/src/options.cpp
Normal file
135
others/src/options.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
//
|
||||
// Created by xinyang on 19-3-27.
|
||||
//
|
||||
|
||||
#include <options.h>
|
||||
#include <log.h>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
bool show_armor_box = true;
|
||||
bool show_armor_boxes = false;
|
||||
bool show_light_blobs = false;
|
||||
bool show_origin = false;
|
||||
bool run_with_camera = true;
|
||||
bool save_video = false;
|
||||
bool wait_uart = false;
|
||||
bool save_labelled_boxes = false;
|
||||
bool show_process = false;
|
||||
bool save_mark = false;
|
||||
|
||||
bool show_info = true;
|
||||
bool run_by_frame = false;
|
||||
|
||||
// 使用map保存所有选项及其描述和操作,加快查找速度。
|
||||
std::map<std::string, std::pair<std::string, void(*)(void)>> options = {
|
||||
{"--help",{
|
||||
"show the help information.", [](){
|
||||
LOG(LOG_MSG, "<HELP>: " STR_CTR(WORD_BLUE, "All options below are for debug use."));
|
||||
for(const auto &option : options){
|
||||
LOG(LOG_MSG, "<HELP>: " STR_CTR(WORD_GREEN, "%s: %s"), option.first.data(), option.second.first.data());
|
||||
}
|
||||
}
|
||||
}},
|
||||
{"--show-armor-box", {
|
||||
"show the aim box.", []() {
|
||||
show_armor_box = true;
|
||||
LOGM("Enable show armor box");
|
||||
}
|
||||
}},
|
||||
{"--show-armor-boxes",{
|
||||
"show the candidate aim boxes.", [](){
|
||||
show_armor_boxes = true;
|
||||
LOGM("Enable show armor boxes");
|
||||
}
|
||||
}},
|
||||
{"--show-light-blobs",{
|
||||
"show the candidate light blobs.", [](){
|
||||
show_light_blobs = true;
|
||||
LOGM("Enable show light blobs");
|
||||
}
|
||||
}},
|
||||
{"--show-origin", {
|
||||
"show the origin image.", [](){
|
||||
show_origin = true;
|
||||
LOGM("Enable show origin");
|
||||
}
|
||||
}},
|
||||
{"--run-with-camera", {
|
||||
"start the program with camera directly without asking.", []() {
|
||||
run_with_camera = true;
|
||||
LOGM("Run with camera!");
|
||||
}
|
||||
}},
|
||||
{"--save-video", {
|
||||
"save the video.", [](){
|
||||
save_video = true;
|
||||
LOGM("Enable save video!");
|
||||
}
|
||||
}},
|
||||
{"--save-labelled-boxes",{
|
||||
"save the candidate boxes with their id labels.", [](){
|
||||
save_labelled_boxes = true;
|
||||
LOGM("labelled armor boxes will be saved!");
|
||||
}
|
||||
}},
|
||||
{"--wait-uart", {
|
||||
"wait uart until ready before running.", [](){
|
||||
wait_uart = true;
|
||||
LOGM("Enable wait uart!");
|
||||
}
|
||||
}},
|
||||
{"--run-by-frame",{
|
||||
"run the code frame by frame.(normally used when run video)", [](){
|
||||
run_by_frame = true;
|
||||
LOGM("Enable run frame by frame");
|
||||
}
|
||||
}},
|
||||
{"--show-process", {
|
||||
"", [](){
|
||||
show_process = true;
|
||||
LOGM("Enable show processed image!");
|
||||
}
|
||||
}},
|
||||
|
||||
{"--save-mark", {
|
||||
"", [](){
|
||||
save_mark = true;
|
||||
LOGM("Write down mark");
|
||||
}
|
||||
}},
|
||||
{"--show-info", {
|
||||
"", [](){
|
||||
show_info = true;
|
||||
LOGM("Show information!");
|
||||
}
|
||||
}},
|
||||
{"--show-all", {
|
||||
"show all image windows.", [](){
|
||||
show_armor_box = true;
|
||||
LOGM("Enable show armor box");
|
||||
show_armor_boxes = true;
|
||||
LOGM("Enable show armor boxes");
|
||||
show_light_blobs = true;
|
||||
LOGM("Enable show light blobs");
|
||||
show_origin = true;
|
||||
LOGM("Enable show origin");
|
||||
show_process = true;
|
||||
LOGM("Enable show processed image");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void processOptions(int argc, char **argv) {
|
||||
if (argc >= 2) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
auto key = options.find(std::string(argv[i])); // 寻找对应选项。
|
||||
if(key != options.end()){
|
||||
key->second.second();
|
||||
}else{
|
||||
LOGW("Unknown option: %s. Use --help to see options.", argv[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
342
others/src/serial.cpp
Normal file
342
others/src/serial.cpp
Normal file
@@ -0,0 +1,342 @@
|
||||
#include <serial.h>
|
||||
#include <options.h>
|
||||
#include <iostream>
|
||||
|
||||
//#define LOG_LEVEL LOG_NONE
|
||||
#include <log.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef Windows
|
||||
|
||||
Serial::Serial(UINT baud, char parity, UINT databits, UINT stopsbits, DWORD dwCommEvents) :
|
||||
hComm(INVALID_HANDLE_VALUE),
|
||||
portNo(3),
|
||||
parity(parity),
|
||||
databits(databits),
|
||||
stopsbits(stopsbits),
|
||||
dwCommEvents(dwCommEvents){
|
||||
if (wait_uart) {
|
||||
LOGM("Waiting for serial COM%d", portNo);
|
||||
while (InitPort(portNo, baud, parity, databits, stopsbits, dwCommEvents) == false);
|
||||
LOGM("Port COM%d open success!", portNo);
|
||||
} else {
|
||||
if (InitPort(portNo, baud, parity, databits, stopsbits, dwCommEvents)) {
|
||||
LOGM("Port COM%d open success!", portNo);
|
||||
} else {
|
||||
LOGE("Port COM%d open fail!", portNo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Serial::~Serial() {
|
||||
ClosePort();
|
||||
}
|
||||
|
||||
void Serial::ErrorHandler() {
|
||||
if (wait_uart) {
|
||||
LOGE("Serial COM%d offline, waiting for serial COM%d", portNo, portNo);
|
||||
while (InitPort(portNo, baud, parity, databits, stopsbits, dwCommEvents) == false);
|
||||
LOGM("Port COM%d reopen success!", portNo);
|
||||
}
|
||||
}
|
||||
|
||||
bool Serial::openPort(UINT portNo) {
|
||||
char szPort[50];
|
||||
sprintf_s(szPort, "COM%d", portNo);
|
||||
|
||||
/** 打开指定的串口 */
|
||||
hComm = CreateFileA(szPort, /** 设备名,COM1,COM2等 */
|
||||
GENERIC_READ | GENERIC_WRITE, /** 访问模式,可同时读写 */
|
||||
0, /** 共享模式,0表示不共享 */
|
||||
NULL, /** 安全性设置,一般使用NULL */
|
||||
OPEN_EXISTING, /** 该参数表示设备必须存在,否则创建失败 */
|
||||
0,
|
||||
0);
|
||||
|
||||
return hComm != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
void Serial::ClosePort() {
|
||||
/** 如果有串口被打开,关闭它 */
|
||||
if (hComm != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(hComm);
|
||||
hComm = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
bool Serial::InitPort(UINT portNo, UINT baud, char parity, UINT databits, UINT stopsbits, DWORD dwCommEvents) {
|
||||
/** 临时变量,将制定参数转化为字符串形式,以构造DCB结构 */
|
||||
char szDCBparam[50];
|
||||
sprintf_s(szDCBparam, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopsbits);
|
||||
|
||||
if (!openPort(portNo)){
|
||||
cout << "open error!" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOL bIsSuccess = TRUE;
|
||||
COMMTIMEOUTS CommTimeouts;
|
||||
CommTimeouts.ReadIntervalTimeout = 0;
|
||||
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
|
||||
CommTimeouts.ReadTotalTimeoutConstant = 0;
|
||||
CommTimeouts.WriteTotalTimeoutMultiplier = 0;
|
||||
CommTimeouts.WriteTotalTimeoutConstant = 0;
|
||||
if (bIsSuccess) {
|
||||
bIsSuccess = SetCommTimeouts(hComm, &CommTimeouts);
|
||||
} else {
|
||||
cout << "SetCommTimeouts error!" << endl;
|
||||
}
|
||||
|
||||
DCB dcb;
|
||||
if (bIsSuccess) {
|
||||
/** 获取当前串口配置参数,并且构造串口DCB参数 */
|
||||
bIsSuccess = GetCommState(hComm, &dcb);
|
||||
bIsSuccess = BuildCommDCB(szDCBparam, &dcb);
|
||||
if (!bIsSuccess) {
|
||||
|
||||
cout << "Create dcb fail with "<< GetLastError() << endl;
|
||||
}
|
||||
/** 开启RTS flow控制 */
|
||||
dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
||||
}
|
||||
|
||||
if (bIsSuccess) {
|
||||
/** 使用DCB参数配置串口状态 */
|
||||
bIsSuccess = SetCommState(hComm, &dcb);
|
||||
if (!bIsSuccess) {
|
||||
cout << "SetCommState error!" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/** 清空串口缓冲区 */
|
||||
PurgeComm(hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
|
||||
|
||||
return bIsSuccess;
|
||||
}
|
||||
|
||||
UINT Serial::GetBytesInCOM() const {
|
||||
DWORD dwError = 0; /** 错误码 */
|
||||
COMSTAT comstat; /** COMSTAT结构体,记录通信设备的状态信息 */
|
||||
memset(&comstat, 0, sizeof(COMSTAT));
|
||||
|
||||
UINT BytesInQue = 0;
|
||||
/** 在调用ReadFile和WriteFile之前,通过本函数清除以前遗留的错误标志 */
|
||||
if (ClearCommError(hComm, &dwError, &comstat)) {
|
||||
BytesInQue = comstat.cbInQue; /** 获取在输入缓冲区中的字节数 */
|
||||
}
|
||||
|
||||
return BytesInQue;
|
||||
}
|
||||
|
||||
bool Serial::WriteData(const unsigned char* pData, unsigned int length) {
|
||||
if (hComm == INVALID_HANDLE_VALUE) {
|
||||
ErrorHandler();
|
||||
return false;
|
||||
}
|
||||
|
||||
/** 向缓冲区写入指定量的数据 */
|
||||
BOOL bResult = TRUE;
|
||||
DWORD BytesToSend = 0;
|
||||
bResult = WriteFile(hComm, pData, length, &BytesToSend, NULL);
|
||||
if (!bResult) {
|
||||
DWORD dwError = GetLastError();
|
||||
/** 清空串口缓冲区 */
|
||||
PurgeComm(hComm, PURGE_RXCLEAR | PURGE_RXABORT);
|
||||
ErrorHandler();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serial::ReadData(unsigned char *buffer, unsigned int length) {
|
||||
if (hComm == INVALID_HANDLE_VALUE) {
|
||||
ErrorHandler();
|
||||
return false;
|
||||
}
|
||||
|
||||
/** 从缓冲区读取length字节的数据 */
|
||||
BOOL bResult = TRUE;
|
||||
DWORD totalRead = 0, onceRead = 0;
|
||||
while (totalRead < length) {
|
||||
bResult = ReadFile(hComm, buffer, length-totalRead, &onceRead, NULL);
|
||||
totalRead += onceRead;
|
||||
if ((!bResult)) {
|
||||
/** 获取错误码,可以根据该错误码查出错误原因 */
|
||||
DWORD dwError = GetLastError();
|
||||
|
||||
/** 清空串口缓冲区 */
|
||||
PurgeComm(hComm, PURGE_RXCLEAR | PURGE_RXABORT);
|
||||
ErrorHandler();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return bResult;
|
||||
}
|
||||
|
||||
#elif defined(Linux) || defined(Darwin)
|
||||
|
||||
#include <string.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
string get_uart_dev_name() {
|
||||
FILE *ls = popen("ls /dev/ttyCH341USB* --color=never", "r");
|
||||
char name[20] = {0};
|
||||
fscanf(ls, "%s", name);
|
||||
return name;
|
||||
}
|
||||
|
||||
Serial::Serial(int nSpeed, char nEvent, int nBits, int nStop) :
|
||||
nSpeed(nSpeed), nEvent(nEvent), nBits(nBits), nStop(nStop) {
|
||||
if (wait_uart) {
|
||||
LOGM("Wait for serial be ready!");
|
||||
while (!InitPort(nSpeed, nEvent, nBits, nStop));
|
||||
LOGM("Port set successfully!");
|
||||
} else {
|
||||
if (InitPort(nSpeed, nEvent, nBits, nStop)) {
|
||||
LOGM("Port set successfully!");
|
||||
} else {
|
||||
LOGE("Port set fail!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Serial::~Serial() {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
bool Serial::InitPort(int nSpeed, char nEvent, int nBits, int nStop) {
|
||||
string name = get_uart_dev_name();
|
||||
if (name == "") {
|
||||
return false;
|
||||
}
|
||||
if ((fd = open(name.data(), O_RDWR)) < 0) {
|
||||
return false;
|
||||
}
|
||||
if (set_opt(fd, nSpeed, nEvent, nBits, nStop) < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//int GetBytesInCOM() const {
|
||||
//
|
||||
//}
|
||||
|
||||
bool Serial::WriteData(const unsigned char *pData, unsigned int length) {
|
||||
int cnt = 0, curr = 0;
|
||||
if (fd <= 0){
|
||||
if(wait_uart){
|
||||
InitPort(nSpeed, nEvent, nBits, nStop);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
while ((curr = write(fd, pData + cnt, length - cnt)) > 0 && (cnt += curr) < length);
|
||||
if (curr < 0) {
|
||||
LOGE("Serial offline!");
|
||||
close(fd);
|
||||
if (wait_uart) {
|
||||
InitPort(nSpeed, nEvent, nBits, nStop);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serial::ReadData(unsigned char *buffer, unsigned int length) {
|
||||
int cnt = 0, curr = 0;
|
||||
while ((curr = read(fd, buffer + cnt, length - cnt)) > 0 && (cnt += curr) < length);
|
||||
if (curr < 0) {
|
||||
LOGE("Serial offline!");
|
||||
close(fd);
|
||||
if (wait_uart) {
|
||||
InitPort(nSpeed, nEvent, nBits, nStop);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int Serial::set_opt(int fd, int nSpeed, char nEvent, int nBits, int nStop) {
|
||||
termios newtio{}, oldtio{};
|
||||
if (tcgetattr(fd, &oldtio) != 0) {
|
||||
perror("SetupSerial 1");
|
||||
return -1;
|
||||
}
|
||||
bzero(&newtio, sizeof(newtio));
|
||||
newtio.c_cflag |= CLOCAL | CREAD;
|
||||
newtio.c_cflag &= ~CSIZE;
|
||||
|
||||
switch (nBits) {
|
||||
case 7:
|
||||
newtio.c_cflag |= CS7;
|
||||
break;
|
||||
case 8:
|
||||
newtio.c_cflag |= CS8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (nEvent) {
|
||||
case 'O': //奇校验
|
||||
newtio.c_cflag |= PARENB;
|
||||
newtio.c_cflag |= PARODD;
|
||||
newtio.c_iflag |= (INPCK | ISTRIP);
|
||||
break;
|
||||
case 'E': //偶校验
|
||||
newtio.c_iflag |= (INPCK | ISTRIP);
|
||||
newtio.c_cflag |= PARENB;
|
||||
newtio.c_cflag &= ~PARODD;
|
||||
break;
|
||||
case 'N': //无校验
|
||||
newtio.c_cflag &= ~PARENB;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (nSpeed) {
|
||||
case 2400:
|
||||
cfsetispeed(&newtio, B2400);
|
||||
cfsetospeed(&newtio, B2400);
|
||||
break;
|
||||
case 4800:
|
||||
cfsetispeed(&newtio, B4800);
|
||||
cfsetospeed(&newtio, B4800);
|
||||
break;
|
||||
case 9600:
|
||||
cfsetispeed(&newtio, B9600);
|
||||
cfsetospeed(&newtio, B9600);
|
||||
break;
|
||||
case 115200:
|
||||
cfsetispeed(&newtio, B115200);
|
||||
cfsetospeed(&newtio, B115200);
|
||||
break;
|
||||
default:
|
||||
cfsetispeed(&newtio, B9600);
|
||||
cfsetospeed(&newtio, B9600);
|
||||
break;
|
||||
}
|
||||
|
||||
if (nStop == 1) {
|
||||
newtio.c_cflag &= ~CSTOPB;
|
||||
} else if (nStop == 2) {
|
||||
newtio.c_cflag |= CSTOPB;
|
||||
}
|
||||
|
||||
newtio.c_cc[VTIME] = 0;
|
||||
newtio.c_cc[VMIN] = 0;
|
||||
tcflush(fd, TCIFLUSH);
|
||||
if ((tcsetattr(fd, TCSANOW, &newtio)) != 0) {
|
||||
perror("com set error");
|
||||
return -1;
|
||||
}
|
||||
printf("set done!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* switch os */
|
||||
36
others/src/systime.cpp
Normal file
36
others/src/systime.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// Created by xinyang on 19-7-31.
|
||||
//
|
||||
#include <systime.h>
|
||||
|
||||
#if defined(Linux) || defined(Darwin)
|
||||
|
||||
static systime getsystime(){
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
return tv.tv_usec / 1000.0 + tv.tv_sec * 1000.0;
|
||||
}
|
||||
|
||||
void getsystime(systime &t) {
|
||||
static systime time_base = getsystime();
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
t = tv.tv_usec / 1000.0 + tv.tv_sec * 1000.0 - time_base;
|
||||
}
|
||||
|
||||
#elif defined(Windows)
|
||||
|
||||
void getsystime(systime &t){
|
||||
SYSTEMTIME tv;
|
||||
GetLocalTime(&tv);
|
||||
t = tv.wMilliseconds + tv.wSecond * 1000.0;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "nonsupport platform."
|
||||
#endif
|
||||
|
||||
|
||||
double getTimeIntervalms(const systime &now, const systime &last) {
|
||||
return now - last;
|
||||
}
|
||||
Reference in New Issue
Block a user