Browse Source

update

master
zhaohe 2 years ago
parent
commit
8de2a83d2a
  1. 3
      components/dwin/dwin_screen.cpp
  2. 4
      components/eq_20_asb_motor/eq20_servomotor.hpp
  3. 73
      components/zcancmder/cmd.hpp
  4. 343
      components/zcancmder/zcanreceiver.cpp
  5. 122
      components/zcancmder/zcanreceiver.hpp
  6. 67
      components/zcancmder_module/zcan_basic_order_module.cpp
  7. 46
      components/zcancmder_module/zcan_basic_order_module.hpp

3
components/dwin/dwin_screen.cpp

@ -16,7 +16,7 @@ using namespace std;
#define TAG "dwin"
DwinScreen& DwinScreen::ins() { return g_dwinScreen; }
#if 0
static void dumphex(uint8_t* data, size_t len) {
printf("(%d)", len);
for (size_t i = 0; i < len; i++) {
@ -24,6 +24,7 @@ static void dumphex(uint8_t* data, size_t len) {
}
printf("\n");
}
#endif
void DwinScreen::init(UART_HandleTypeDef* huart, map<string, DwinRamManager*>& rammanager) {
m_huart = huart;
// m_dwcfg = dwcfg;

4
components/eq_20_asb_motor/eq20_servomotor.hpp

@ -16,9 +16,9 @@ class Eq20ServoMotor {
void init(ModbusBlockHost *modbusBlockHost);
bool writereg32(int deviceid, uint32_t regadd, int value);
bool writePn(int deviceid, uint32_t pnadd, int value) { writereg32(deviceid, pnadd * 2, value); }
bool writePn(int deviceid, uint32_t pnadd, int value) { return writereg32(deviceid, pnadd * 2, value); }
private:
};
} // namespace iflytop
} // namespace iflytop

73
components/zcancmder/cmd.hpp

@ -0,0 +1,73 @@
#pragma once
#include "sdk/os/zos.hpp"
namespace iflytop {
namespace zcr {
typedef struct {
uint16_t packetindex;
uint16_t cmdid;
uint8_t subcmdid;
uint8_t packetType;
uint8_t data[];
} Cmdheader_t;
typedef enum {
kpt_cmd = 0,
kpt_ack = 1,
kpt_error_ack = 2,
kpt_status_report = 3,
} PacketType_t;
typedef enum {
kcmd_ping = 0,
kcmd_read_io = 1,
kcmd_set_io = 2,
kcmd_readadc_raw = 3,
kcmd_m211887_operation = 1000, // 维萨拉臭氧传感器
kcmd_read_presure_sensor = 1001, // 压力传感器
kcmd_triple_warning_light_ctl = 1002, // 三色警示灯控制
kcmd_high_power_electrical_ctl = 1003, // 大功率电源控制
kcmd_peristaltic_pump_ctl = 1004, // 液泵控制
kcmd_read_huacheng_pressure_sensor = 1005, // 华诚压力传感器
} CmdID_t;
} // namespace zcr
} // namespace iflytop
typedef struct {
uint8_t boardid;
} kcmd_ping_t;
typedef struct {
uint8_t boardid;
} kcmd_ping_ack_t;
typedef struct {
uint8_t ioid;
} kcmd_read_io_t;
typedef struct {
uint8_t ioid;
uint8_t val;
} kcmd_read_io_ack_t;
typedef struct {
uint8_t ioid;
uint8_t val;
} kcmd_set_io_t;
typedef struct {
uint8_t ioid;
uint8_t val;
} kcmd_set_io_ack_t;
typedef struct {
uint8_t sensorid;
} kcmd_readadc_raw_t;
typedef struct {
uint8_t sensorid;
uint8_t __p; // padding
int32_t val;
} kcmd_readadc_raw_ack_t;

343
components/zcancmder/zcanreceiver.cpp

@ -0,0 +1,343 @@
#include "zcanreceiver.hpp"
#ifdef HAL_CAN_MODULE_ENABLED
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace iflytop;
using namespace zcr;
#define TAG "ZCanCmder"
#define OVER_TIME_MS 5
uint16_t CanPacketRxBuffer::get_packetindex() {
Cmdheader_t *cmdheader = (Cmdheader_t *)rxdata;
return cmdheader->packetindex;
}
uint16_t CanPacketRxBuffer::get_cmdid() {
Cmdheader_t *cmdheader = (Cmdheader_t *)rxdata;
return cmdheader->cmdid;
}
uint8_t CanPacketRxBuffer::get_subcmdid() {
Cmdheader_t *cmdheader = (Cmdheader_t *)rxdata;
return cmdheader->subcmdid;
}
uint8_t CanPacketRxBuffer::get_packetType() {
Cmdheader_t *cmdheader = (Cmdheader_t *)rxdata;
return cmdheader->packetType;
}
uint8_t *CanPacketRxBuffer::get_data() {
Cmdheader_t *cmdheader = (Cmdheader_t *)rxdata;
return cmdheader->data;
}
uint16_t CanPacketRxBuffer::get_datalen() {
Cmdheader_t *cmdheader = (Cmdheader_t *)rxdata;
return rxdataSize - sizeof(Cmdheader_t);
}
bool CanPacketRxBuffer::iscmd(CmdID_t id, uint8_t subcmdid) {
Cmdheader_t *cmdheader = (Cmdheader_t *)rxdata;
return cmdheader->cmdid == (uint16_t)id && cmdheader->subcmdid == subcmdid;
}
Cmdheader_t* CanPacketRxBuffer::get_cmdheader() {
Cmdheader_t *cmdheader = (Cmdheader_t *)rxdata;
return cmdheader;
}
ZCanCmder::CFG *ZCanCmder::createCFG(uint8_t deviceId) {
CFG *cfg = new CFG();
ZASSERT(cfg != NULL);
cfg->deviceId = deviceId;
#ifdef STM32F103xB
cfg->canHandle = &hcan;
#else
cfg->canHandle = &hcan1;
#endif
cfg->canFilterIndex0 = 0;
cfg->maxFilterNum = 7;
cfg->rxfifoNum = CAN_RX_FIFO0;
return cfg;
}
void ZCanCmder::init(CFG *cfg) {
HAL_StatusTypeDef hal_status;
m_config = cfg;
/**
* @brief CAN
*/
/**
* @brief buf
*/
m_canPacketRxBuffer[0].dataIsReady = false;
m_canPacketRxBuffer[0].id = 1; // 只接收来自主机的消息
m_canPacketRxBuffer[0].m_canPacketNum = 0;
/**
* @brief
*/
hal_status = initializeFilter();
if (hal_status != HAL_OK) {
ZLOGE(TAG, "start can initializeFilter fail\r\n");
return;
}
/**
* @brief CAN
*/
hal_status = HAL_CAN_Start(m_config->canHandle); // 开启CAN
if (hal_status != HAL_OK) {
ZLOGE(TAG, "start can fail\r\n");
return;
}
/**
* @brief
*/
ZCanIRQDispatcher::instance().regListener(this);
HAL_StatusTypeDef status = activateRxIT();
if (status != HAL_OK) {
ZLOGE(TAG, "activateRxIT fail\r\n");
return;
}
// ZHALCORE::getInstance()->regPeriodJob([this](ZHALCORE::Context &context) { loop(); }, 0);
}
HAL_StatusTypeDef ZCanCmder::initializeFilter() {
/**
* @brief ID区帧格式
* [ 27:0 ]
* [ STDID ] [ EXTID ]
* [11 :9] [8:6] [5:0] [17:16] [15:8] [7:0]
* ID ID
*/
HAL_StatusTypeDef HAL_Status;
CAN_FilterTypeDef sFilterConfig;
uint32_t filterId;
uint32_t mask;
memset(&sFilterConfig, 0, sizeof(sFilterConfig));
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 设为MASK模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // CAN_FILTERSCALE_16BIT
sFilterConfig.FilterFIFOAssignment = m_config->rxfifoNum; // 关联过滤器到rxfifoNum
sFilterConfig.FilterActivation = ENABLE; // 激活过滤器
sFilterConfig.SlaveStartFilterBank = m_config->maxFilterNum; // slave filter start index
/*******************************************************************************
* *
*******************************************************************************/
filterId = (0); //
mask = (0); //
sFilterConfig.FilterBank = m_config->canFilterIndex0; //
sFilterConfig.FilterMaskIdLow = mask & 0xffff; //
sFilterConfig.FilterMaskIdHigh = (mask & 0xffff0000) >> 16; //
sFilterConfig.FilterIdLow = filterId & 0xffff; //
sFilterConfig.FilterIdHigh = (filterId & 0xffff0000) >> 16; //
HAL_Status = HAL_CAN_ConfigFilter(m_config->canHandle, &sFilterConfig);
if (HAL_Status != HAL_OK) {
ZLOGE(TAG, "HAL_CAN_ConfigFilter filter0 fail");
return HAL_Status;
}
ZLOGI(TAG, "HAL_CAN_ConfigFilter filterID1 %08x", filterId >> 3);
return HAL_Status;
}
void ZCanCmder::registerListener(ZCanCmderListener *listener) { m_listenerList.push_back(listener); }
void ZCanCmder::regListener(zcan_cmder_listener_t listener) { m_listenerList2.push_back(listener); }
void ZCanCmder::sendPacket(uint8_t *packet, size_t len) {
/**
* @brief
*/
int npacket = len / 8 + (len % 8 == 0 ? 0 : 1);
if (npacket > 255) {
ZLOGE(TAG, "sendPacket fail, len:%d", len);
return;
}
int finalpacketlen = len % 8 == 0 ? 8 : len % 8;
for (uint8_t i = 0; i < npacket; i++) {
bool suc = false;
if (i == npacket - 1) {
suc = sendPacketSub(npacket, i, packet + i * 8, finalpacketlen, OVER_TIME_MS);
} else {
suc = sendPacketSub(npacket, i, packet + i * 8, 8, OVER_TIME_MS);
}
if (!suc) {
ZLOGE(TAG, "sendPacket fail, packet(%d:%d)", npacket, i);
return;
}
}
}
void ZCanCmder::sendAck(Cmdheader_t *cmdheader, uint8_t *data, size_t len) {
Cmdheader_t *txheader = (Cmdheader_t *)txbuff;
memcpy(txheader, cmdheader, sizeof(Cmdheader_t));
txheader->packetType = kpt_ack;
memcpy(txheader->data, data, len);
sendPacket(txbuff, sizeof(Cmdheader_t) + len);
}
void ZCanCmder::sendErrorAck(Cmdheader_t *cmdheader, int16_t errcode) {
Cmdheader_t *txheader = (Cmdheader_t *)txbuff;
memcpy(txheader, cmdheader, sizeof(Cmdheader_t));
txheader->packetType = kpt_error_ack;
sendPacket(txbuff, sizeof(Cmdheader_t) + 2);
}
bool ZCanCmder::sendPacketSub(int npacket, int packetIndex, uint8_t *packet, size_t len, int overtimems) {
CAN_TxHeaderTypeDef pHeader;
uint8_t aData[8] /*8byte table*/;
uint32_t txMailBox = 0;
uint32_t enterticket = zos_get_tick();
memset(&pHeader, 0, sizeof(pHeader));
memset(aData, 0, sizeof(aData));
pHeader.StdId = 0x00;
pHeader.ExtId = (m_config->deviceId << 16) | (npacket << 8) | packetIndex;
pHeader.IDE = CAN_ID_EXT;
pHeader.RTR = CAN_RTR_DATA;
pHeader.DLC = len;
pHeader.TransmitGlobalTime = DISABLE;
memcpy(aData, packet, len);
m_lastTransmitStatus = HAL_CAN_AddTxMessage(m_config->canHandle, &pHeader, aData, &txMailBox);
if (m_lastTransmitStatus != HAL_OK) {
ZLOGE(TAG, "HAL_CAN_AddTxMessage fail");
return false;
}
while (HAL_CAN_IsTxMessagePending(m_config->canHandle, txMailBox)) {
if (zos_haspassedms(enterticket) > (uint32_t)overtimems) {
m_lastTransmitStatus = HAL_TIMEOUT;
HAL_CAN_AbortTxRequest(m_config->canHandle, txMailBox);
return false;
}
// m_os->sleepMS(1);
}
return true;
}
bool ZCanCmder::getRxMessage(CAN_RxHeaderTypeDef *pHeader, uint8_t aData[] /*8byte table*/) {
/**
* @brief FIFO中缓存了多少帧的数据
*/
uint32_t level = HAL_CAN_GetRxFifoFillLevel(m_config->canHandle, m_config->rxfifoNum);
if (level == 0) {
return false;
}
HAL_StatusTypeDef HAL_RetVal;
HAL_RetVal = HAL_CAN_GetRxMessage(m_config->canHandle, m_config->rxfifoNum, pHeader, aData);
if (HAL_OK == HAL_RetVal) {
// 处理接收到的can总线数据
return true;
}
return false;
}
void ZCanCmder::STM32_HAL_onCAN_RxFifo0MsgPending(CAN_HandleTypeDef *canHandle) {
/**
* @brief
*/
// ZLOG_INFO("%s\n", __FUNCTION__);
// printf("------------------%s\n", __FUNCTION__);
if (canHandle != m_config->canHandle) {
return;
}
/**
* @brief can接收到消息
*/
CAN_RxHeaderTypeDef pHeader;
uint8_t aData[8] /*8byte table*/;
while (getRxMessage(&pHeader, aData)) {
/**
* @brief
*
* [2] [3bit] [8bit] [8bit] [8bit]
* , from frameNum frameId
*/
uint8_t from = (pHeader.ExtId >> 16 & 0xFF);
uint8_t nframe = (pHeader.ExtId & 0xFF00) >> 8;
uint8_t frameId = (pHeader.ExtId & 0x00FF);
CanPacketRxBuffer *rxbuf = &m_canPacketRxBuffer[0];
if (from != rxbuf->id) {
// 目前只接收来自主机的消息
continue;
}
if (rxbuf->dataIsReady) {
// 上次接收到的消息还没有来的急处理
continue;
}
/**
* @TODO:
*/
if (frameId == 0) {
rxbuf->m_canPacketNum = 0;
}
if (rxbuf->m_canPacketNum < 255) {
rxbuf->m_canPacket[rxbuf->m_canPacketNum].pHeader = pHeader;
memcpy(rxbuf->m_canPacket[rxbuf->m_canPacketNum].aData, aData, 8);
rxbuf->m_canPacketNum++;
}
if (nframe == frameId + 1) {
rxbuf->dataIsReady = true;
}
}
// deactivateRxIT();
}
void ZCanCmder::STM32_HAL_onCAN_Error(CAN_HandleTypeDef *canHandle) {
if (canHandle != m_config->canHandle) {
return;
}
ZLOGE(TAG, "onCAN_Error\r\n");
}
void ZCanCmder::loop() {
CanPacketRxBuffer *rxbuf = &m_canPacketRxBuffer[0];
if (rxbuf->dataIsReady) {
int dataoff = 0;
for (size_t i = 0; i < rxbuf->m_canPacketNum; i++) {
memcpy(rxbuf->rxdata + dataoff, rxbuf->m_canPacket[i].aData, rxbuf->m_canPacket[i].pHeader.DLC);
dataoff += rxbuf->m_canPacket[i].pHeader.DLC;
}
rxbuf->rxdataSize = dataoff;
for (auto &var : m_listenerList) {
var->onRceivePacket(rxbuf);
}
for (auto &var : m_listenerList2) {
var(rxbuf);
}
rxbuf->dataIsReady = false;
}
}
HAL_StatusTypeDef ZCanCmder::activateRxIT() {
HAL_StatusTypeDef hal_status = HAL_ERROR;
if (m_config->rxfifoNum == CAN_RX_FIFO0) {
hal_status = HAL_CAN_ActivateNotification(m_config->canHandle, CAN_IT_RX_FIFO0_MSG_PENDING);
} else if (m_config->rxfifoNum == CAN_RX_FIFO1) {
hal_status = HAL_CAN_ActivateNotification(m_config->canHandle, CAN_IT_RX_FIFO1_MSG_PENDING);
} else {
ZLOGE(TAG, "start can HAL_CAN_ActivateNotification CAN_IT_RX_FIFO0_MSG_PENDING fail\r\n");
return hal_status;
}
return hal_status;
}
HAL_StatusTypeDef ZCanCmder::deactivateRxIT() {
HAL_StatusTypeDef hal_status = HAL_ERROR;
if (m_config->rxfifoNum == CAN_RX_FIFO0) {
hal_status = HAL_CAN_DeactivateNotification(m_config->canHandle, CAN_IT_RX_FIFO0_MSG_PENDING);
} else if (m_config->rxfifoNum == CAN_RX_FIFO1) {
hal_status = HAL_CAN_DeactivateNotification(m_config->canHandle, CAN_IT_RX_FIFO1_MSG_PENDING);
} else {
ZLOGE(TAG, "start can HAL_CAN_ActivateNotification CAN_IT_RX_FIFO0_MSG_PENDING fail\r\n");
return hal_status;
}
return hal_status;
}
#endif

122
components/zcancmder/zcanreceiver.hpp

@ -0,0 +1,122 @@
//
// Created by zwsd
//
#pragma once
#include "cmd.hpp"
#include "sdk/os/zos.hpp"
namespace iflytop {
namespace zcr {
typedef enum {
kpacketHeader = 0,
kpacketData = 1,
kpacketTail = 2,
} packet_type_t;
class CANPacket {
public:
CAN_RxHeaderTypeDef pHeader;
uint8_t aData[8]; /*8byte table*/
};
}; // namespace zcr
using namespace zcr;
class CanPacketRxBuffer {
public:
uint16_t id = 0;
CANPacket m_canPacket[256] = {0}; // 用于接收can消息
uint8_t m_canPacketNum = 0;
bool dataIsReady = false;
uint8_t rxdata[2000] = {0};
int rxdataSize = 0;
public:
uint16_t get_packetindex();
uint16_t get_cmdid();
uint8_t get_subcmdid();
uint8_t get_packetType();
uint8_t *get_data();
uint16_t get_datalen();
Cmdheader_t* get_cmdheader();
bool iscmd(CmdID_t id, uint8_t subcmdid);
template <typename T>
T *get_data_as() {
return (T *)get_data();
}
};
class ZCanCmderListener {
public:
virtual void onRceivePacket(CanPacketRxBuffer *rxcmd) = 0;
};
typedef function<void(CanPacketRxBuffer *rxcmd)> zcan_cmder_listener_t;
class ZCanCmder : public ZCanIRQListener {
public:
class CFG {
public:
uint8_t deviceId; //
/*******************************************************************************
* CANConfig *
*******************************************************************************/
CAN_HandleTypeDef *canHandle; // 默认使用CAN1
int canFilterIndex0; // 过滤器0 接收,发给自身的消息
int maxFilterNum; // 使用的过滤器数量,最大值14,默认为7
int rxfifoNum; // 使用的FIFO,默认使用FIFO0
int packetRxOvertime_ms; //
};
uint8_t txbuff[1000];
public:
class LoopJobContext {
public:
bool hasDoneSomething;
};
private:
CFG *m_config = NULL; // 配置
bool m_canOnRxDataFlag = false; // 是否有数据接收,用于从中断上下文转移到MainLoop上下文
uint32_t m_lastPacketTicket = 0; // 上一次接收到消息的时间,用于判断与主机是否断开连接
HAL_StatusTypeDef m_lastTransmitStatus; // 上次调用can发送方法的返回值
list<ZCanCmderListener *> m_listenerList;
list<zcan_cmder_listener_t> m_listenerList2;
CanPacketRxBuffer m_canPacketRxBuffer[1];
public:
ZCanCmder() {}
CFG *createCFG(uint8_t deviceId);
void init(CFG *cfg);
void registerListener(ZCanCmderListener *listener);
void regListener(zcan_cmder_listener_t listener);
void sendPacket(uint8_t *packet, size_t len);
void sendAck(Cmdheader_t *rxcmdheader, uint8_t *data, size_t len);
void sendErrorAck(Cmdheader_t *rxcmdheader, int16_t errcode);
bool sendPacketSub(int npacket, int packetIndex, uint8_t *packet, size_t len, int overtimems);
uint8_t getDeviceId() { return m_config->deviceId; }
void loop();
public:
virtual void STM32_HAL_onCAN_RxFifo0MsgPending(CAN_HandleTypeDef *can);
virtual void STM32_HAL_onCAN_Error(CAN_HandleTypeDef *can);
private:
HAL_StatusTypeDef initializeFilter();
HAL_StatusTypeDef activateRxIT();
HAL_StatusTypeDef deactivateRxIT();
bool getRxMessage(CAN_RxHeaderTypeDef *pHeader, uint8_t aData[] /*8byte table*/);
};
} // namespace iflytop

67
components/zcancmder_module/zcan_basic_order_module.cpp

@ -0,0 +1,67 @@
#include "zcan_basic_order_module.hpp"
#include <stdio.h>
#include <string.h>
#ifdef HAL_CAN_MODULE_ENABLED
using namespace iflytop;
using namespace zcr;
void ZCanBasicOrderModule::initialize(ZCanCmder* zcanReceiver) {
zcanReceiver->registerListener(this);
m_zcanReceiver = zcanReceiver;
}
void ZCanBasicOrderModule::regInputCtl(readfn_t fn) { m_readfn = fn; }
void ZCanBasicOrderModule::regOutCtl(writefn_t fn) { m_writefn = fn; }
void ZCanBasicOrderModule::regReadAdcVal(readadcval_t fn) { m_readadcval = fn; }
void ZCanBasicOrderModule::onRceivePacket(CanPacketRxBuffer* rxbuf) {
if (rxbuf->iscmd(kcmd_ping, 0)) {
kcmd_ping_t* pingcmd = rxbuf->get_data_as<kcmd_ping_t>();
kcmd_ping_ack_t* ack = (kcmd_ping_ack_t*)txbuff;
if (pingcmd->boardid == m_zcanReceiver->getDeviceId()) {
ack->boardid = pingcmd->boardid;
m_zcanReceiver->sendAck(rxbuf->get_cmdheader(), txbuff, sizeof(kcmd_ping_ack_t));
return;
}
} else if (rxbuf->iscmd(kcmd_read_io, 0)) {
kcmd_read_io_t* cmd = rxbuf->get_data_as<kcmd_read_io_t>();
kcmd_read_io_ack_t* ack = (kcmd_read_io_ack_t*)txbuff;
bool val = false;
if (m_readfn && m_readfn(cmd->ioid, val)) {
ack->ioid = cmd->ioid;
ack->val = val;
m_zcanReceiver->sendAck(rxbuf->get_cmdheader(), txbuff, sizeof(kcmd_read_io_ack_t));
return;
}
} else if (rxbuf->iscmd(kcmd_set_io, 0)) {
kcmd_set_io_t* cmd = rxbuf->get_data_as<kcmd_set_io_t>();
kcmd_set_io_ack_t ack;
bool val = cmd->val;
if (m_writefn && m_writefn(cmd->ioid, val)) {
ack.ioid = cmd->ioid;
ack.val = val;
m_zcanReceiver->sendAck(rxbuf->get_cmdheader(), (uint8_t*)&ack, sizeof(ack));
return;
}
} else if (rxbuf->iscmd(kcmd_readadc_raw, 0)) {
kcmd_readadc_raw_t* cmd = rxbuf->get_data_as<kcmd_readadc_raw_t>();
kcmd_readadc_raw_ack_t ack;
int32_t val = 0;
if (m_readadcval && m_readadcval(cmd->sensorid, val)) {
ack.sensorid = cmd->sensorid;
ack.val = val;
m_zcanReceiver->sendAck(rxbuf->get_cmdheader(), (uint8_t*)&ack, sizeof(ack));
return;
}
}
}
void ZCanBasicOrderModule::loop() {}
#endif

46
components/zcancmder_module/zcan_basic_order_module.hpp

@ -0,0 +1,46 @@
//
// Created by zwsd
//
#pragma once
//
#include "sdk/os/zos.hpp"
#include "sdk\components\zcancmder\zcanreceiver.hpp"
#ifdef HAL_CAN_MODULE_ENABLED
namespace iflytop {
class ZCanBasicOrderModule : public ZCanCmderListener {
public:
private:
ZCanCmder* m_zcanReceiver;
typedef function<bool(uint8_t id, bool& val)> readfn_t;
typedef function<bool(uint8_t id, bool val)> writefn_t;
typedef function<bool(uint8_t id, int32_t& val)> readadcval_t;
readfn_t m_readfn;
writefn_t m_writefn;
readadcval_t m_readadcval;
uint8_t txbuff[32];
public:
ZCanBasicOrderModule(/* args */) {}
~ZCanBasicOrderModule() {}
public:
void initialize(ZCanCmder* zcanReceiver);
void regInputCtl(readfn_t fn);
void regOutCtl(writefn_t fn);
void regReadAdcVal(readadcval_t fn);
public:
virtual void onRceivePacket(CanPacketRxBuffer* rxbuf);
private:
void loop();
};
} // namespace iflytop
#endif
Loading…
Cancel
Save