#include <queue>
using namespace std;
struct SRawData
{
int start;
int end;
int pluse;
int count;
bool operator==(const SRawData& data)
{
return data.count == count && start == data.start && end == data.end && pluse == data.pluse;
}
};
struct SDataLock
{
deque<SRawData> que;
mutex mux;
};
struct SReadLock // 读取锁
{
bool bReadAll = false; // 读取完所有连续有效协议的标记
int nPackageCount = 0;
mutex mux;
condition_variable conVar;
};
class Protocol // 协议层
{
public:
enum ReadStatus { error = 0x01, failure, empty, process, vaild, finished }; // 读取结果的状态表示
public:
Protocol();
ReadStatus Analysic(BYTE ch, SRawData& rawData);
ReadStatus IsVaildData(SRawData& rawData);
bool CyclicCheck(); // crc校验
bool IsSpaceData(); // 校验空白数据
bool IsFinished(); // 校验完成标记
public:
BYTE* GetBuffer() { return m_buff; }
int GetIndex() { return m_index; }
void Release() { ZeroMemory(m_buff, sizeof(m_buff)); }
int GetLineCount() const { return m_count; }
private:
BYTE m_buff[13]; // 字符缓冲区
int m_index; // 当前字符索引
int m_count; // 切线的条数
int m_end; // 结束标记出现的次数(最多3次)
};
#include "Protocol.h"
#include "CheckCrc.h"
#include "Collector.h"
#include "Horizontal.h"
Protocol::Protocol()
: m_index(0), m_count(0), m_end(0)
{
memset(m_buff, 0, sizeof(m_buff));
}
Protocol::ReadStatus Protocol::Analysic(BYTE ch, SRawData& rawData)
{
if (m_index >= 0 && m_index < 3) // 索引在区间[0, 3) 填写协议头所在位置内存的信息
{
m_buff[m_index++] = ch; // 当m_index == 2时, 在2字节填入当前的ch值之后m_index == 3
return ReadStatus::process; // -1表示填写协议头阶段
}
if (m_index == 3) // 填满了协议头所在位置的内存
{
if (m_buff[0] == 0x01 && m_buff[1] == 0x03 && m_buff[2] == 0x08) // 找到协议头
{
m_buff[m_index++] = ch; // 将当前字节写到索引为3的内存, 在数据区填了一字节
return ReadStatus::process;
}
// 判断将来可能是协议头的情况
BOOL b1 = (m_buff[1] == 0x01); // xx 01 xx 判断下标1的字节处是后为0x01
BOOL b2 = (m_buff[2] == 0x01); // xx xx 01 判断下标2的字节处是后为0x01
BOOL b3 = (m_buff[2] == 0x03); // xx xx 03 判断下标2的字节处是后为0x03
BOOL c = (b1 && b3); // xx 01 03 上面两种情况的组合的状态
if (b2 || c)
{
m_buff[0] = 0x01; // 都会将0字节的位置置0x01
if (b2) // xx xx 01
{
m_index = 1;
}
if(c) // xx 01 03
{
m_buff[1] = 0x03;
m_index = 2;
}
m_buff[m_index++] = ch;
return ReadStatus::process;
}
m_buff[0] = m_buff[1] = m_buff[2] = 0x00; // 其他情况下未来不可能组成协议头
m_index = 0;
m_buff[m_index++] = ch;
return ReadStatus::process;
}
if (m_index > 3 && m_index < 13) // 填写数据区
m_buff[m_index++] = ch;
if (m_index < 13)
return ReadStatus::process;
m_index = 0;
ReadStatus status = IsVaildData(rawData);
Release();
return status;
}
Protocol::ReadStatus Protocol::IsVaildData(SRawData& rawData) // 0 为有效
{
/*bool& bReadAll = Data::readLock.bReadAll;
int& nPackageCount = Data::readLock.nPackageCount;*/
WORD wStart = MAKEWORD(*(m_buff + 4), *(m_buff + 3));
WORD wEnd = MAKEWORD(*(m_buff + 6), *(m_buff + 5));
WORD wCount = MAKEWORD(*(m_buff + 8), *(m_buff + 7));
WORD wPluse = MAKEWORD(*(m_buff + 10), *(m_buff + 9));
WORD wCrc = MAKEWORD(*(m_buff + 12), *(m_buff + 11));
if (!CyclicCheck()) // 校验
{
m_end = 0;
m_count = 0;
return ReadStatus::failure;
}
if (!wPluse && (wStart > 0 || wEnd > 0 || wCount > 0)) // 物体遮挡或者有灰尘
{
m_end = 0;
m_count = 0;
return ReadStatus::error;
}
if (wCrc == 0x95D7) // 空白
{
m_end = 0;
m_count = 0;
return ReadStatus::empty;
}
if ((0x95D7 != wCrc && wCrc) && wPluse && !wCount && !wEnd && !wStart) // 检测最后的3个结束协议
{
++m_end; // 记录发送的表示结束的协议条数
if (m_end == 1)
{
TRACE("一共有%d条切线\n", m_count);
m_count = 0;
Release();
}
return ReadStatus::finished;
}
rawData = move(SRawData{ wStart, wEnd, wPluse, ++m_count });
return ReadStatus::vaild;
}
bool Protocol::CyclicCheck() // CRC校验
{
if (CheckCrc::CRC16_MODBUS(m_buff, 11) != MAKEWORD(*(m_buff + 11), *(m_buff + 12))) // 校验失败
return false;
return true;
}
bool Protocol::IsSpaceData() // 空白数据
{
if (MAKEWORD(*(m_buff + 12), *(m_buff + 11)) != 0x95D7) // 不是空白
return true;
return false;
}
bool Protocol::IsFinished() // 判断结束
{
if (MAKEWORD(*(m_buff + 10), *(m_buff + 9)) && !MAKEWORD(*(m_buff + 8), *(m_buff + 7)) // 结束
&& !MAKEWORD(*(m_buff + 6), *(m_buff + 5)) && !MAKEWORD(*(m_buff + 4), *(m_buff + 3)))
return false;
return true;
}
#include "Raster.h"
#include "Protocol.h"
#include <queue>
using namespace std;
const int nMaxCount = 8;
class Horizontal : public Raster
{
public:
typedef Protocol::ReadStatus ReadStatus;
public:
void TheProc();
public:
static void Producter(Horizontal* pHorizontal);
static void Comsumer(Horizontal* pHorizontal);
public:
ReadStatus ReadCom(HANDLE hCom, BYTE ch, SRawData& rawData);
public:
static SDataLock dataLock;
static SReadLock readLock;
private:
Protocol m_protocol;
};
#include "pch.h"
#include <future>
#include "Collector.h"
#include "Horizontal.h"
#include "Serial.h"
#include "CheckCrc.h"
#define TEXT_PATH _T("./data.txt")
SDataLock Horizontal::dataLock;
SReadLock Horizontal::readLock;
void Horizontal::TheProc()
{
thread comsumer(Comsumer, this);
if (comsumer.joinable())
comsumer.detach();
thread producter(Producter, this);
if (producter.joinable())
producter.detach();
}
/*齿轮比 4 : 7 即 r / R = 4 / 7
主轴半径 25mm 再加上皮带厚度1.25mm
欧姆龙 1000HZ
一个脉冲下从轴转过的弧度为:(2 * pi) / 1000 = pi / 500
假设主轴转半圈经历了x个脉冲,从轴转半圈经历500个脉冲,从轴与主轴的连接的皮带移动了L毫米
必然有如下关系成立:L = (pi / 500) * r = (pi / x) * R
x = 500 * (R / r)
= 500 * 7 / 4
= 1750
在脉冲数为n时,皮带前进的毫米数如下:
2 * pi * (R + d) * (n / 1750)
pi 为圆周率,R为主轴半径,d为皮带的厚度,n为主轴转一周的脉冲数,注意皮带具有延展性,皮带的厚度受到安装时轴距的影响
*/
void Horizontal::Producter(Horizontal* pHorizontal)
{
BYTE ch = 0x00;
HANDLE& hCom = pHorizontal->GetComHandle();
mutex* pReadMutex = &readLock.mux;
condition_variable* pVar = &readLock.conVar;
deque<SRawData>& que = pHorizontal->dataLock.que;
SRawData rawData;
while (hCom)
{
unique_lock<mutex> readLock(*pReadMutex);
pVar->wait(readLock, [&que]() { return que.size() <= nMaxCount; });
if (ReadStatus::vaild == pHorizontal->ReadCom(hCom, ch, rawData))
{
que.emplace_back(rawData);
TRACE("Producter: start = %d, end = %d, pluse = %d, conunt = %d\n",
que.back().start, que.back().end, que.back().pluse, que.back().count);
}
pVar->notify_all();
}
}
void Horizontal::Comsumer(Horizontal* pHorizontal)
{
HANDLE& hCom = pHorizontal->GetComHandle();
mutex* pReadMutex = &readLock.mux;
condition_variable* pVar = &readLock.conVar;
deque<SRawData>& que = pHorizontal->dataLock.que;
unique_lock<mutex> readLock(*pReadMutex);
pVar->wait(readLock, [&que]() { return !que.empty(); });
TRACE("Comsumer: start = %d, end = %d, pluse = %d, conunt = %d\n",
que.front().start, que.front().end, que.front().pluse, que.front().count);
que.pop_front();
pVar->notify_all();
}
Protocol::ReadStatus Horizontal::ReadCom(HANDLE hCom, BYTE ch, SRawData& rawData)
{
Serial::ReadComm(hCom, (const LPBYTE)&ch, 1);
return m_protocol.Analysic(ch, rawData); // 对从串口总读取的数据进行分析
}