6 changed files with 65 additions and 548 deletions
-
7.project/cmake/target.cmake
-
2dep/iflytopcpp
-
49src/test/dump_can_driver_info.cpp
-
387src/test/socketcan.cpp
-
129src/test/socketcan.hpp
-
37src/test/test_can.cpp
@ -1 +1 @@ |
|||
Subproject commit 5199d0a9ee175f8254d13ec9436be0f9f67e83d5 |
|||
Subproject commit f186de7700bf4550ce2420d1cd87d43a5a1bfc39 |
@ -0,0 +1,49 @@ |
|||
#include <stdio.h>
|
|||
|
|||
#include "zlinuxcomponents/zmainhelper.hpp"
|
|||
//
|
|||
#include "iflytopcpp/core/spdlogfactory/logger.hpp"
|
|||
#include "iflytopcpp/core/thread/thread.hpp"
|
|||
#include "spdlog/spdlog.h"
|
|||
//
|
|||
|
|||
#include <linux/can.h>
|
|||
#include <linux/can/raw.h>
|
|||
#include <net/if.h>
|
|||
#include <stdio.h>
|
|||
#include <stdlib.h>
|
|||
#include <string.h>
|
|||
#include <sys/ioctl.h>
|
|||
#include <sys/socket.h>
|
|||
#include <unistd.h>
|
|||
|
|||
#include "iflytopcpp/core/driver/socketcan/socket_can.hpp"
|
|||
|
|||
using namespace iflytop; |
|||
using namespace core; |
|||
using namespace std; |
|||
using namespace clipp; |
|||
|
|||
class Main { |
|||
ENABLE_LOGGER(Main); |
|||
unique_ptr<Thread> thread; |
|||
shared_ptr<SocketCan> socketCan; |
|||
|
|||
public: |
|||
Main(/* args */) {} |
|||
~Main() {} |
|||
void run(int argc, char* argv[]) { |
|||
thread.reset(new Thread("main", [&]() { exit(main(argc, argv)); })); |
|||
while (true) sleep(1000); |
|||
} |
|||
void onSIGINT() { exit(0); } |
|||
int main(int argCount, char* argValues[]) { |
|||
if (argCount < 3) { |
|||
logger->info("Usage: {} canName canBaudrate", argValues[0]); |
|||
return 1; |
|||
} |
|||
SocketCan::dumpCanDriverInfo(argValues[1], atoi(argValues[2])); |
|||
return 0; |
|||
} |
|||
}; |
|||
MAIN_ENTRY(); |
@ -1,387 +0,0 @@ |
|||
#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 * |
|||
*******************************************************************************/ |
|||
|
|||
shared_ptr<CanFrame> CanFrame::createExtDataFrame(uint32_t id, uint8_t *data, size_t len) { |
|||
shared_ptr<CanFrame> canframe = make_shared<CanFrame>(); |
|||
if (len > 8) len = 8; |
|||
canframe->m_id = id; |
|||
canframe->m_canIdentifier = kextFrame; |
|||
canframe->m_canFrameType = kdataframe; |
|||
canframe->m_dlc = len; |
|||
memcpy(canframe->m_data, data, len); |
|||
return canframe; |
|||
} |
|||
|
|||
shared_ptr<CanFrame> CanFrame::createStdDataFrame(uint32_t id, uint8_t *data, size_t len) { |
|||
shared_ptr<CanFrame> canframe = make_shared<CanFrame>(); |
|||
if (len > 8) len = 8; |
|||
canframe->m_id = id; |
|||
canframe->m_canIdentifier = kstdFrame; |
|||
canframe->m_canFrameType = kdataframe; |
|||
canframe->m_dlc = len; |
|||
memcpy(canframe->m_data, data, len); |
|||
return canframe; |
|||
} |
|||
|
|||
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 = 0; |
|||
return canframe; |
|||
} |
|||
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 = 0; |
|||
return canframe; |
|||
} |
|||
void CanFrame::setCanIdentifier(can_identifier_t canIdentifier) { this->m_canIdentifier = canIdentifier; } |
|||
void CanFrame::setFanFrameType(can_frame_type_t fanFrameType) { this->m_canFrameType = fanFrameType; } |
|||
void CanFrame::setId(uint32_t id) { this->m_id = id; } |
|||
|
|||
uint32_t CanFrame::getId() { return m_id; } |
|||
can_identifier_t CanFrame::getCanIdentifier() { return m_canIdentifier; } |
|||
can_frame_type_t CanFrame::getFanFrameType() { return m_canFrameType; } |
|||
|
|||
/*******************************************************************************
|
|||
* SocketCan * |
|||
*******************************************************************************/ |
|||
#if 0
|
|||
int s, nbytes; |
|||
struct sockaddr_can addr; |
|||
struct ifreq ifr; |
|||
struct can_frame frame[2] = {{0}}; |
|||
s = socket(PF_CAN, SOCK_RAW, CAN_RAW); |
|||
printf("send_s = %d\n", s); |
|||
strcpy(ifr.ifr_name, "can0"); |
|||
ioctl(s, SIOCGIFINDEX, &ifr); |
|||
addr.can_family = AF_CAN; |
|||
addr.can_ifindex = ifr.ifr_ifindex; |
|||
bind(s, (struct sockaddr *)&addr, sizeof(addr)); |
|||
|
|||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); |
|||
|
|||
frame[0].can_id = 0x11; |
|||
frame[0].can_dlc = 1; |
|||
frame[0].data[0] = 'Y'; |
|||
frame[1].can_id = 0x410; |
|||
frame[1].can_dlc = 1; |
|||
frame[1].data[0] = 'N'; |
|||
|
|||
while (1) { |
|||
nbytes = write(s, &frame[0], sizeof(frame[0])); |
|||
if (nbytes != sizeof(frame[0])) { |
|||
printf("Send Error frame[0]!\n"); |
|||
break; |
|||
} |
|||
|
|||
sleep(1); |
|||
|
|||
nbytes = write(s, &frame[1], sizeof(frame[1])); |
|||
if (nbytes != sizeof(frame[1])) { |
|||
printf("Send Error frame[1]!\n"); |
|||
break; |
|||
} |
|||
|
|||
sleep(1); |
|||
} |
|||
|
|||
close(s); |
|||
#endif
|
|||
|
|||
bool SocketCan::findCan(string canName) { return access(fmt::format("/sys/class/net/{}", canName).c_str(), F_OK) == 0; } |
|||
|
|||
bool SocketCan::initialize(string canName, int bitrate, vector<can_filter_t> filters) { |
|||
m_canName = canName; |
|||
if (findCan(canName) == false) { |
|||
logger->error("can {} not found", canName); |
|||
return false; |
|||
} |
|||
|
|||
// setCanBitrate(canName, bitrate);
|
|||
|
|||
m_canfd = socket(PF_CAN, SOCK_RAW, CAN_RAW); |
|||
if (m_canfd < 0) { |
|||
logger->error("socket failed,{}", strerror(errno)); |
|||
return false; |
|||
} |
|||
|
|||
struct ifreq ifr = {0}; |
|||
strcpy(ifr.ifr_name, canName.c_str()); |
|||
ioctl(m_canfd, SIOCGIFINDEX, &ifr); |
|||
|
|||
const int bufsize = 0; |
|||
if (setsockopt(m_canfd, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)) != 0) { |
|||
logger->error("setsockopt SO_SNDBUF fail,{}", strerror(errno)); |
|||
return -1; |
|||
} |
|||
|
|||
struct sockaddr_can addr = {0}; |
|||
addr.can_family = AF_CAN; |
|||
addr.can_ifindex = ifr.ifr_ifindex; |
|||
if (bind(m_canfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { |
|||
logger->error("bind fail,{}", strerror(errno)); |
|||
return false; |
|||
} |
|||
|
|||
if (!filters.empty()) { |
|||
if (setsockopt(m_canfd, SOL_CAN_RAW, CAN_RAW_FILTER, filters.data(), filters.size() * sizeof(struct can_filter)) != 0) { |
|||
logger->error("set filters fail,{}", strerror(errno)); |
|||
return false; |
|||
}; |
|||
} else { |
|||
can_filter_t filter = {0}; |
|||
filter.can_id = 0; |
|||
filter.can_mask = 0; |
|||
if (setsockopt(m_canfd, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, sizeof(filter)) != 0) { |
|||
logger->error("set filters fail,{}", strerror(errno)); |
|||
return false; |
|||
}; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
int SocketCan::sendFrame(shared_ptr<CanFrame> frame) { |
|||
if (frame == nullptr) { |
|||
logger->error("frame is null"); |
|||
return -1; |
|||
} |
|||
if (m_canfd < 0) { |
|||
logger->error("canfd is invalid"); |
|||
return -1; |
|||
} |
|||
|
|||
canfd_frame_t canframe = frame->getCanFrame(); |
|||
|
|||
int ret = write(m_canfd, &canframe, canframe.len + 8); |
|||
if (ret != (canframe.len + 8)) { |
|||
logger->error("write fail,{}", strerror(errno)); |
|||
return -1; |
|||
} |
|||
return 0; |
|||
} |
|||
#if 0
|
|||
struct canfd_frame { |
|||
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ |
|||
__u8 len; /* frame payload length in byte */ |
|||
__u8 flags; /* additional flags for CAN FD */ |
|||
__u8 __res0; /* reserved / padding */ |
|||
__u8 __res1; /* reserved / padding */ |
|||
__u8 data[CANFD_MAX_DLEN] __attribute__((aligned(8))); |
|||
}; |
|||
#endif
|
|||
|
|||
void SocketCan::startListen() { |
|||
m_thread.reset( //
|
|||
new Thread(fmt::format("SocketCan_{}_ListenThread", m_canName), //
|
|||
[this]() { |
|||
ThisThread thisThread; |
|||
fd_set readfds, readFileDescriptors; |
|||
FD_ZERO(&readFileDescriptors); |
|||
FD_SET(m_canfd, &readFileDescriptors); |
|||
|
|||
while (!thisThread.getExitFlag()) { |
|||
canfd_frame_t canframe; |
|||
struct canfd_frame frame; |
|||
|
|||
timeval waitTime; |
|||
waitTime.tv_sec = 3; |
|||
waitTime.tv_usec = 0; |
|||
|
|||
readfds = readFileDescriptors; |
|||
|
|||
int n = select(m_canfd + 1, &readfds, 0, 0, &waitTime); |
|||
logger->info("select.... {}", n); |
|||
if (n <= 0) { |
|||
continue; |
|||
} |
|||
|
|||
memset(&canframe, 0x00, sizeof(canframe)); |
|||
int ret = read(m_canfd, &canframe, sizeof(canframe)); |
|||
// if (ret != sizeof(canframe)) {
|
|||
// logger->error("read fail,{}", strerror(errno));
|
|||
// continue;
|
|||
// }
|
|||
|
|||
logger->info("RX({}):{}", ret, StringUtils().bytesToString((uint8_t *)&canframe, ret)); |
|||
} |
|||
})); |
|||
} |
|||
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); |
|||
system(cmd.c_str()); |
|||
} |
|||
|
|||
void SocketCan::setCanBitrate(string canName, int bitrate) { |
|||
logger->info("set can:{} bitrate:{}", canName, bitrate); |
|||
dosystem(fmt::format("ip link set {} down", canName)); |
|||
dosystem(fmt::format("ip link set {} type can bitrate {}", canName, bitrate)); |
|||
dosystem(fmt::format("ip link set {} up", canName)); |
|||
} |
@ -1,129 +0,0 @@ |
|||
//
|
|||
// Created by zwsd
|
|||
//
|
|||
|
|||
#pragma once
|
|||
#include <linux/can.h>
|
|||
#include <linux/can/raw.h>
|
|||
#include <net/if.h>
|
|||
#include <stdio.h>
|
|||
#include <stdlib.h>
|
|||
#include <string.h>
|
|||
#include <sys/ioctl.h>
|
|||
#include <sys/socket.h>
|
|||
#include <unistd.h>
|
|||
|
|||
#include <fstream>
|
|||
#include <iostream>
|
|||
#include <list>
|
|||
#include <map>
|
|||
#include <memory>
|
|||
#include <set>
|
|||
#include <sstream>
|
|||
#include <string>
|
|||
#include <vector>
|
|||
|
|||
#include "iflytopcpp/core/basic/nod/nod.hpp"
|
|||
#include "iflytopcpp/core/spdlogfactory/logger.hpp"
|
|||
#include "iflytopcpp/core/thread/thread.hpp"
|
|||
|
|||
/**
|
|||
* @brief |
|||
* |
|||
* service: SocketCan |
|||
* |
|||
* 监听事件: |
|||
* 依赖状态: |
|||
* 依赖服务: |
|||
* 作用: |
|||
* |
|||
*/ |
|||
|
|||
namespace iflytop { |
|||
using namespace std; |
|||
using namespace core; |
|||
|
|||
/*******************************************************************************
|
|||
* CAN_FRAME * |
|||
*******************************************************************************/ |
|||
|
|||
typedef struct can_filter can_filter_t; |
|||
typedef struct canfd_frame canfd_frame_t; |
|||
typedef enum { |
|||
kstdFrame, |
|||
kextFrame, |
|||
} can_identifier_t; |
|||
|
|||
typedef enum { |
|||
kdataframe, |
|||
kremoteframe, |
|||
} can_frame_type_t; |
|||
|
|||
class CanFrame { |
|||
private: |
|||
uint32_t m_id = 0; |
|||
can_identifier_t m_canIdentifier = kstdFrame; |
|||
can_frame_type_t m_canFrameType = kdataframe; |
|||
uint8_t m_data[8] = {0}; |
|||
uint8_t m_dlc = 0; |
|||
|
|||
public: |
|||
static shared_ptr<CanFrame> createExtDataFrame(uint32_t id, uint8_t *data, size_t len); |
|||
static shared_ptr<CanFrame> createStdDataFrame(uint32_t id, uint8_t *data, size_t len); |
|||
static shared_ptr<CanFrame> createExtRemoteFrame(uint32_t id); |
|||
static shared_ptr<CanFrame> createStdRemoteFrame(uint32_t id); |
|||
|
|||
void setId(uint32_t id); |
|||
uint32_t getId(); |
|||
can_frame_type_t getFanFrameType(); |
|||
void setFanFrameType(can_frame_type_t fanFrameType); |
|||
can_identifier_t getCanIdentifier(); |
|||
void setCanIdentifier(can_identifier_t canIdentifier); |
|||
|
|||
canfd_frame_t getCanFrame(); |
|||
}; |
|||
|
|||
/*******************************************************************************
|
|||
* SocketCan * |
|||
*******************************************************************************/ |
|||
|
|||
class SocketCan { |
|||
ENABLE_LOGGER(SocketCan); |
|||
|
|||
string m_canName; |
|||
int m_canfd; |
|||
vector<can_filter_t> m_canfilters; |
|||
unique_ptr<Thread> m_thread; |
|||
|
|||
public: |
|||
nod::signal<void(shared_ptr<CanFrame> canframe)> signalOnFrame; |
|||
|
|||
public: |
|||
SocketCan(){}; |
|||
bool initialize(string canName, int bitrate, vector<can_filter_t> filters); |
|||
int sendFrame(shared_ptr<CanFrame> frame); |
|||
/**
|
|||
* @brief 发送can帧 |
|||
* |
|||
* @param frame |
|||
* frame="11111111#1122334455667788" ID=0x11111111,帧类型=数据帧,帧格式=扩展帧,数据长度=8,数据=1122334455667788 |
|||
* frame="111#1122334455667788" ID=0x111, 帧类型=数据帧,帧格式=标准帧,数据长度=8,数据=1122334455667788 |
|||
* frame="111#R" ID=0x111, 帧类型=远程帧,帧格式=标准帧,数据长度=0 |
|||
* frame="11111111#R" ID=0x11111111,帧类型=远程帧,帧格式=扩展帧,数据长度=0 |
|||
* @return int |
|||
*/ |
|||
int sendFrame(string frame); |
|||
void startListen(); |
|||
~SocketCan() { |
|||
if (m_canfd > 0) { |
|||
close(m_canfd); |
|||
} |
|||
} |
|||
|
|||
private: |
|||
void dosystem(string cmd); |
|||
void setCanBitrate(string canName, int bitrate); |
|||
bool findCan(string canName); |
|||
int parse_canframe(char *cs, struct canfd_frame *cf); |
|||
}; |
|||
} // namespace iflytop
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue