|
|
@ -1,8 +1,23 @@ |
|
|
|
#include "socketcan.hpp"
|
|
|
|
|
|
|
|
#include <linux/can.h>
|
|
|
|
#include <linux/can/raw.h>
|
|
|
|
|
|
|
|
#include "iflytopcpp/core/components/stringutils.hpp"
|
|
|
|
//
|
|
|
|
using namespace iflytop; |
|
|
|
#define CANID_DELIM '#'
|
|
|
|
#define CC_DLC_DELIM '_'
|
|
|
|
#define DATA_SEPERATOR '.'
|
|
|
|
#define CAN_MAX_DLC 8
|
|
|
|
#define CAN_MAX_RAW_DLC 15
|
|
|
|
#define CAN_MAX_DLEN 8
|
|
|
|
unsigned char asc2nibble(char c) { |
|
|
|
if ((c >= '0') && (c <= '9')) return c - '0'; |
|
|
|
if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10; |
|
|
|
if ((c >= 'a') && (c <= 'f')) return c - 'a' + 10; |
|
|
|
return 16; /* error */ |
|
|
|
} |
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* can_frame_t * |
|
|
@ -30,20 +45,20 @@ shared_ptr<CanFrame> CanFrame::createStdDataFrame(uint32_t id, uint8_t *data, si |
|
|
|
return canframe; |
|
|
|
} |
|
|
|
|
|
|
|
shared_ptr<CanFrame> CanFrame::createExtRemoteFrame(uint32_t id, uint8_t dlc) { |
|
|
|
shared_ptr<CanFrame> CanFrame::createExtRemoteFrame(uint32_t id) { |
|
|
|
shared_ptr<CanFrame> canframe = make_shared<CanFrame>(); |
|
|
|
canframe->m_id = id; |
|
|
|
canframe->m_canIdentifier = kextFrame; |
|
|
|
canframe->m_canFrameType = kremoteframe; |
|
|
|
canframe->m_dlc = dlc; |
|
|
|
canframe->m_dlc = 0; |
|
|
|
return canframe; |
|
|
|
} |
|
|
|
shared_ptr<CanFrame> CanFrame::createStdRemoteFrame(uint32_t id, uint8_t dlc) { |
|
|
|
shared_ptr<CanFrame> CanFrame::createStdRemoteFrame(uint32_t id) { |
|
|
|
shared_ptr<CanFrame> canframe = make_shared<CanFrame>(); |
|
|
|
canframe->m_id = id; |
|
|
|
canframe->m_canIdentifier = kstdFrame; |
|
|
|
canframe->m_canFrameType = kremoteframe; |
|
|
|
canframe->m_dlc = dlc; |
|
|
|
canframe->m_dlc = 0; |
|
|
|
return canframe; |
|
|
|
} |
|
|
|
void CanFrame::setCanIdentifier(can_identifier_t canIdentifier) { this->m_canIdentifier = canIdentifier; } |
|
|
@ -54,26 +69,6 @@ uint32_t CanFrame::getId() { return m_id; } |
|
|
|
can_identifier_t CanFrame::getCanIdentifier() { return m_canIdentifier; } |
|
|
|
can_frame_type_t CanFrame::getFanFrameType() { return m_canFrameType; } |
|
|
|
|
|
|
|
can_frame_t CanFrame::getCanFrame() { |
|
|
|
can_frame_t frame; |
|
|
|
memset(&frame, 0, sizeof(frame)); |
|
|
|
|
|
|
|
if (m_canIdentifier == kstdFrame) { |
|
|
|
frame.can_id = (m_id & CAN_SFF_MASK); |
|
|
|
} else { |
|
|
|
frame.can_id = (m_id & CAN_EFF_MASK) | CAN_EFF_FLAG; |
|
|
|
} |
|
|
|
|
|
|
|
if (m_canFrameType == kremoteframe) { |
|
|
|
frame.can_id |= CAN_RTR_FLAG; |
|
|
|
frame.can_dlc = m_dlc; |
|
|
|
} else { |
|
|
|
frame.can_dlc = m_dlc; |
|
|
|
memcpy(frame.data, m_data, m_dlc); |
|
|
|
} |
|
|
|
return frame; |
|
|
|
} |
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* SocketCan * |
|
|
|
*******************************************************************************/ |
|
|
@ -177,10 +172,10 @@ int SocketCan::sendFrame(shared_ptr<CanFrame> frame) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
can_frame_t canframe = frame->getCanFrame(); |
|
|
|
canfd_frame_t canframe = frame->getCanFrame(); |
|
|
|
|
|
|
|
int ret = write(m_canfd, &canframe, sizeof(canframe)); |
|
|
|
if (ret != sizeof(canframe)) { |
|
|
|
int ret = write(m_canfd, &canframe, canframe.len + 8); |
|
|
|
if (ret != (canframe.len + 8)) { |
|
|
|
logger->error("write fail,{}", strerror(errno)); |
|
|
|
return -1; |
|
|
|
} |
|
|
@ -201,7 +196,7 @@ void SocketCan::startListen() { |
|
|
|
FD_SET(m_canfd, &readFileDescriptors); |
|
|
|
|
|
|
|
while (!thisThread.getExitFlag()) { |
|
|
|
can_frame_t canframe; |
|
|
|
canfd_frame_t canframe; |
|
|
|
|
|
|
|
logger->info("select...."); |
|
|
|
size_t n = select(m_canfd + 1, &readFileDescriptors, 0, 0, &waitTime); |
|
|
@ -220,6 +215,145 @@ void SocketCan::startListen() { |
|
|
|
} |
|
|
|
})); |
|
|
|
} |
|
|
|
canfd_frame_t CanFrame::getCanFrame() { |
|
|
|
canfd_frame_t frame; |
|
|
|
#if 1
|
|
|
|
memset(&frame, 0, sizeof(frame)); |
|
|
|
|
|
|
|
if (m_canIdentifier == kstdFrame) { |
|
|
|
frame.can_id = (m_id & CAN_SFF_MASK); |
|
|
|
} else { |
|
|
|
frame.can_id = (m_id & CAN_EFF_MASK) | CAN_EFF_FLAG; |
|
|
|
} |
|
|
|
|
|
|
|
if (m_canFrameType == kremoteframe) { |
|
|
|
frame.can_id |= CAN_RTR_FLAG; |
|
|
|
frame.len = m_dlc; |
|
|
|
} else { |
|
|
|
frame.len = m_dlc; |
|
|
|
memcpy(frame.data, m_data, m_dlc); |
|
|
|
} |
|
|
|
#endif
|
|
|
|
return frame; |
|
|
|
} |
|
|
|
|
|
|
|
int SocketCan::parse_canframe(char *cs, struct canfd_frame *cf) { |
|
|
|
/* documentation see lib.h */ |
|
|
|
|
|
|
|
int i, idx, dlen, len; |
|
|
|
int maxdlen = CAN_MAX_DLEN; |
|
|
|
int ret = CAN_MTU; |
|
|
|
canid_t tmp; |
|
|
|
|
|
|
|
len = strlen(cs); |
|
|
|
// printf("'%s' len %d\n", cs, len);
|
|
|
|
|
|
|
|
memset(cf, 0, sizeof(*cf)); /* init CAN FD frame, e.g. LEN = 0 */ |
|
|
|
|
|
|
|
if (len < 4) return 0; |
|
|
|
|
|
|
|
if (cs[3] == CANID_DELIM) { /* 3 digits */ |
|
|
|
|
|
|
|
idx = 4; |
|
|
|
for (i = 0; i < 3; i++) { |
|
|
|
if ((tmp = asc2nibble(cs[i])) > 0x0F) return 0; |
|
|
|
cf->can_id |= (tmp << (2 - i) * 4); |
|
|
|
} |
|
|
|
|
|
|
|
} else if (cs[8] == CANID_DELIM) { /* 8 digits */ |
|
|
|
|
|
|
|
idx = 9; |
|
|
|
for (i = 0; i < 8; i++) { |
|
|
|
if ((tmp = asc2nibble(cs[i])) > 0x0F) return 0; |
|
|
|
cf->can_id |= (tmp << (7 - i) * 4); |
|
|
|
} |
|
|
|
if (!(cf->can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe? */ |
|
|
|
cf->can_id |= CAN_EFF_FLAG; /* then it is an extended frame */ |
|
|
|
|
|
|
|
} else |
|
|
|
return 0; |
|
|
|
|
|
|
|
if ((cs[idx] == 'R') || (cs[idx] == 'r')) { /* RTR frame */ |
|
|
|
cf->can_id |= CAN_RTR_FLAG; |
|
|
|
|
|
|
|
/* check for optional DLC value for CAN 2.0B frames */ |
|
|
|
if (cs[++idx] && (tmp = asc2nibble(cs[idx++])) <= CAN_MAX_DLEN) { |
|
|
|
cf->len = tmp; |
|
|
|
|
|
|
|
/* check for optional raw DLC value for CAN 2.0B frames */ |
|
|
|
if ((tmp == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) { |
|
|
|
tmp = asc2nibble(cs[idx]); |
|
|
|
if ((tmp > CAN_MAX_DLEN) && (tmp <= CAN_MAX_RAW_DLC)) { |
|
|
|
struct can_frame *ccf = (struct can_frame *)cf; |
|
|
|
|
|
|
|
ccf->__res1 = tmp; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
if (cs[idx] == CANID_DELIM) { /* CAN FD frame escape char '##' */ |
|
|
|
|
|
|
|
maxdlen = CANFD_MAX_DLEN; |
|
|
|
ret = CANFD_MTU; |
|
|
|
|
|
|
|
/* CAN FD frame <canid>##<flags><data>* */ |
|
|
|
if ((tmp = asc2nibble(cs[idx + 1])) > 0x0F) return 0; |
|
|
|
|
|
|
|
cf->flags = tmp; |
|
|
|
idx += 2; |
|
|
|
} |
|
|
|
|
|
|
|
for (i = 0, dlen = 0; i < maxdlen; i++) { |
|
|
|
if (cs[idx] == DATA_SEPERATOR) /* skip (optional) separator */ |
|
|
|
idx++; |
|
|
|
|
|
|
|
if (idx >= len) /* end of string => end of data */ |
|
|
|
break; |
|
|
|
|
|
|
|
if ((tmp = asc2nibble(cs[idx++])) > 0x0F) return 0; |
|
|
|
cf->data[i] = (tmp << 4); |
|
|
|
if ((tmp = asc2nibble(cs[idx++])) > 0x0F) return 0; |
|
|
|
cf->data[i] |= tmp; |
|
|
|
dlen++; |
|
|
|
} |
|
|
|
cf->len = dlen; |
|
|
|
|
|
|
|
/* check for extra DLC when having a Classic CAN with 8 bytes payload */ |
|
|
|
if ((maxdlen == CAN_MAX_DLEN) && (dlen == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) { |
|
|
|
unsigned char dlc = asc2nibble(cs[idx]); |
|
|
|
|
|
|
|
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) { |
|
|
|
struct can_frame *ccf = (struct can_frame *)cf; |
|
|
|
|
|
|
|
ccf->__res1 = dlc; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
int SocketCan::sendFrame(string framestr) { |
|
|
|
struct canfd_frame frame; |
|
|
|
int required_mtu; |
|
|
|
required_mtu = parse_canframe((char *)framestr.c_str(), &frame); |
|
|
|
if (!required_mtu) { |
|
|
|
logger->error("Wrong CAN-frame format!"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
if (required_mtu > (int)CAN_MTU) { |
|
|
|
logger->error("CAN-FD frames not supported!"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
logger->info("send frame:{} {} {} {} {} {}", required_mtu, frame.can_id, frame.len, frame.flags, frame.__res0, frame.__res1); |
|
|
|
if (write(m_canfd, &frame, required_mtu) != required_mtu) { |
|
|
|
logger->error("CAN-FD frames not supported!"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
void SocketCan::dosystem(string cmd) { |
|
|
|
logger->info("do cmd:{}", cmd); |
|
|
|