Files
Chm30Utility/CanDriver/driver/CandleApiDriver/CandleApiInterface.cpp
2025-03-17 19:12:22 +09:00

392 lines
12 KiB
C++

#include "CandleApiDriver.h"
#include "CandleApiInterface.h"
CandleApiInterface::CandleApiInterface(CandleApiDriver *driver, candle_handle handle)
: CanInterface(driver),
_hostOffsetStart(0),
_deviceTicksStart(0),
_handle(handle),
_backend(driver->backend()),
_numRx(0),
_numTx(0),
_numTxErr(0)
{
_settings.setBitrate(500000);
_settings.setSamplePoint(875);
// Timings for 170MHz processors (CANable 2.0)
// Tseg1: 2..256 Tseg2: 2..128 sjw: 1..128 brp: 1..512
// Note: as expressed below, Tseg1 does not include 1 count for prop phase
_timings
<< CandleApiTiming(170000000, 10000, 875, 68, 217, 31)
<< CandleApiTiming(170000000, 20000, 875, 34, 217, 31)
<< CandleApiTiming(170000000, 50000, 875, 17, 173, 25)
<< CandleApiTiming(170000000, 83333, 875, 8, 221, 32)
<< CandleApiTiming(170000000, 100000, 875, 10, 147, 21)
<< CandleApiTiming(170000000, 125000, 875, 8, 147, 21)
<< CandleApiTiming(170000000, 250000, 875, 4, 147, 21)
<< CandleApiTiming(170000000, 500000, 875, 2, 147, 21)
<< CandleApiTiming(170000000, 1000000, 875, 1, 147, 21);
// Timings for 48MHz processors (CANable 0.X)
_timings
// sample point: 50.0%
<< CandleApiTiming(48000000, 10000, 500, 300, 6, 8)
<< CandleApiTiming(48000000, 20000, 500, 150, 6, 8)
<< CandleApiTiming(48000000, 50000, 500, 60, 6, 8)
<< CandleApiTiming(48000000, 83333, 500, 36, 6, 8)
<< CandleApiTiming(48000000, 100000, 500, 30, 6, 8)
<< CandleApiTiming(48000000, 125000, 500, 24, 6, 8)
<< CandleApiTiming(48000000, 250000, 500, 12, 6, 8)
<< CandleApiTiming(48000000, 500000, 500, 6, 6, 8)
<< CandleApiTiming(48000000, 800000, 500, 3, 8, 9)
<< CandleApiTiming(48000000, 1000000, 500, 3, 6, 8)
// sample point: 62.5%
<< CandleApiTiming(48000000, 10000, 625, 300, 8, 6)
<< CandleApiTiming(48000000, 20000, 625, 150, 8, 6)
<< CandleApiTiming(48000000, 50000, 625, 60, 8, 6)
<< CandleApiTiming(48000000, 83333, 625, 36, 8, 6)
<< CandleApiTiming(48000000, 100000, 625, 30, 8, 6)
<< CandleApiTiming(48000000, 125000, 625, 24, 8, 6)
<< CandleApiTiming(48000000, 250000, 625, 12, 8, 6)
<< CandleApiTiming(48000000, 500000, 625, 6, 8, 6)
<< CandleApiTiming(48000000, 800000, 600, 4, 7, 6)
<< CandleApiTiming(48000000, 1000000, 625, 3, 8, 6)
// sample point: 75.0%
<< CandleApiTiming(48000000, 10000, 750, 300, 10, 4)
<< CandleApiTiming(48000000, 20000, 750, 150, 10, 4)
<< CandleApiTiming(48000000, 50000, 750, 60, 10, 4)
<< CandleApiTiming(48000000, 83333, 750, 36, 10, 4)
<< CandleApiTiming(48000000, 100000, 750, 30, 10, 4)
<< CandleApiTiming(48000000, 125000, 750, 24, 10, 4)
<< CandleApiTiming(48000000, 250000, 750, 12, 10, 4)
<< CandleApiTiming(48000000, 500000, 750, 6, 10, 4)
<< CandleApiTiming(48000000, 800000, 750, 3, 13, 5)
<< CandleApiTiming(48000000, 1000000, 750, 3, 10, 4)
// sample point: 87.5%
<< CandleApiTiming(48000000, 10000, 875, 300, 12, 2)
<< CandleApiTiming(48000000, 20000, 875, 150, 12, 2)
<< CandleApiTiming(48000000, 50000, 875, 60, 12, 2)
<< CandleApiTiming(48000000, 83333, 875, 36, 12, 2)
<< CandleApiTiming(48000000, 100000, 875, 30, 12, 2)
<< CandleApiTiming(48000000, 125000, 875, 24, 12, 2)
<< CandleApiTiming(48000000, 250000, 875, 12, 12, 2)
<< CandleApiTiming(48000000, 500000, 875, 6, 12, 2)
<< CandleApiTiming(48000000, 800000, 867, 4, 11, 2)
<< CandleApiTiming(48000000, 1000000, 875, 3, 12, 2);
_timings
// sample point: 50.0%
<< CandleApiTiming(16000000, 10000, 520, 64, 11, 12)
<< CandleApiTiming(16000000, 20000, 500, 50, 6, 8)
<< CandleApiTiming(16000000, 50000, 500, 20, 6, 8)
<< CandleApiTiming(16000000, 83333, 500, 12, 6, 8)
<< CandleApiTiming(16000000, 100000, 500, 10, 6, 8)
<< CandleApiTiming(16000000, 125000, 500, 8, 6, 8)
<< CandleApiTiming(16000000, 250000, 500, 4, 6, 8)
<< CandleApiTiming(16000000, 500000, 500, 2, 6, 8)
<< CandleApiTiming(16000000, 800000, 500, 1, 8, 10)
<< CandleApiTiming(16000000, 1000000, 500, 1, 6, 8)
// sample point: 62.5%
<< CandleApiTiming(16000000, 10000, 625, 64, 14, 9)
<< CandleApiTiming(16000000, 20000, 625, 50, 8, 6)
<< CandleApiTiming(16000000, 50000, 625, 20, 8, 6)
<< CandleApiTiming(16000000, 83333, 625, 12, 8, 6)
<< CandleApiTiming(16000000, 100000, 625, 10, 8, 6)
<< CandleApiTiming(16000000, 125000, 625, 8, 8, 6)
<< CandleApiTiming(16000000, 250000, 625, 4, 8, 6)
<< CandleApiTiming(16000000, 500000, 625, 2, 8, 6)
<< CandleApiTiming(16000000, 800000, 625, 1, 11, 7)
<< CandleApiTiming(16000000, 1000000, 625, 1, 8, 6)
// sample point: 75.0%
<< CandleApiTiming(16000000, 20000, 750, 50, 10, 4)
<< CandleApiTiming(16000000, 50000, 750, 20, 10, 4)
<< CandleApiTiming(16000000, 83333, 750, 12, 10, 4)
<< CandleApiTiming(16000000, 100000, 750, 10, 10, 4)
<< CandleApiTiming(16000000, 125000, 750, 8, 10, 4)
<< CandleApiTiming(16000000, 250000, 750, 4, 10, 4)
<< CandleApiTiming(16000000, 500000, 750, 2, 10, 4)
<< CandleApiTiming(16000000, 800000, 750, 1, 13, 5)
<< CandleApiTiming(16000000, 1000000, 750, 1, 10, 4)
// sample point: 87.5%
<< CandleApiTiming(16000000, 20000, 875, 50, 12, 2)
<< CandleApiTiming(16000000, 50000, 875, 20, 12, 2)
<< CandleApiTiming(16000000, 83333, 875, 12, 12, 2)
<< CandleApiTiming(16000000, 100000, 875, 10, 12, 2)
<< CandleApiTiming(16000000, 125000, 875, 8, 12, 2)
<< CandleApiTiming(16000000, 250000, 875, 4, 12, 2)
<< CandleApiTiming(16000000, 500000, 875, 2, 12, 2)
<< CandleApiTiming(16000000, 800000, 900, 2, 7, 1)
<< CandleApiTiming(16000000, 1000000, 875, 1, 12, 2);
}
CandleApiInterface::~CandleApiInterface()
{
}
QString CandleApiInterface::getName() const
{
return "candle" + QString::number(getId() & 0xFF);
}
QString CandleApiInterface::getDetailsStr() const
{
return QString::fromStdWString(getPath());
}
void CandleApiInterface::applyConfig(const MeasurementInterface &mi)
{
_settings = mi;
}
unsigned CandleApiInterface::getBitrate()
{
return _settings.bitrate();
}
uint32_t CandleApiInterface::getCapabilities()
{
candle_capability_t caps;
if (candle_channel_get_capabilities(_handle, 0, &caps)) {
uint32_t retval = 0;
if (caps.feature & CANDLE_MODE_LISTEN_ONLY) {
retval |= CanInterface::capability_listen_only;
}
if (caps.feature & CANDLE_MODE_ONE_SHOT) {
retval |= CanInterface::capability_one_shot;
}
if (caps.feature & CANDLE_MODE_TRIPLE_SAMPLE) {
retval |= CanInterface::capability_triple_sampling;
}
return retval;
} else {
return 0;
}
}
QList<CanTiming> CandleApiInterface::getAvailableBitrates()
{
QList<CanTiming> retval;
candle_capability_t caps;
if (candle_channel_get_capabilities(_handle, 0, &caps)) {
int i = 0;
foreach (const CandleApiTiming t, _timings) {
if (t.getBaseClk() == caps.fclk_can) {
retval << CanTiming(i++, t.getBitrate(), 0, t.getSamplePoint());
}
}
}
return retval;
}
bool CandleApiInterface::setBitTiming(uint32_t bitrate, uint32_t samplePoint)
{
candle_capability_t caps;
if (!candle_channel_get_capabilities(_handle, 0, &caps)) {
return false;
}
foreach (const CandleApiTiming t, _timings) {
if ( (t.getBaseClk() == caps.fclk_can)
&& (t.getBitrate()==bitrate)
&& (t.getSamplePoint()==samplePoint) )
{
candle_bittiming_t timing = t.getTiming();
return candle_channel_set_timing(_handle, 0, &timing);
}
}
// no valid timing found
return false;
}
void CandleApiInterface::open()
{
if (!candle_dev_open(_handle)) {
// TODO what?
_isOpen = false;
return;
}
if (!setBitTiming(_settings.bitrate(), _settings.samplePoint())) {
// TODO what?
_isOpen = false;
return;
}
uint32_t flags = 0;
if (_settings.isListenOnlyMode()) {
flags |= CANDLE_MODE_LISTEN_ONLY;
}
if (_settings.isOneShotMode()) {
flags |= CANDLE_MODE_ONE_SHOT;
}
if (_settings.isTripleSampling()) {
flags |= CANDLE_MODE_TRIPLE_SAMPLE;
}
_numRx = 0;
_numTx = 0;
_numTxErr = 0;
uint32_t t_dev;
if (candle_dev_get_timestamp_us(_handle, &t_dev)) {
_hostOffsetStart =
_backend.getUsecsAtMeasurementStart() +
_backend.getUsecsSinceMeasurementStart();
_deviceTicksStart = t_dev;
}
candle_channel_start(_handle, 0, flags);
_isOpen = true;
}
bool CandleApiInterface::isOpen()
{
return _isOpen;
}
void CandleApiInterface::close()
{
candle_channel_stop(_handle, 0);
candle_dev_close(_handle);
_isOpen = false;
}
void CandleApiInterface::sendMessage(const CanMessage &msg)
{
candle_frame_t frame;
frame.can_id = msg.getId();
if (msg.isExtended()) {
frame.can_id |= CANDLE_ID_EXTENDED;
}
if (msg.isRTR()) {
frame.can_id |= CANDLE_ID_RTR;
}
frame.can_dlc = msg.getLength();
for (int i=0; i<8; i++) {
frame.data[i] = msg.getByte(i);
}
if (candle_frame_send(_handle, 0, &frame)) {
_numTx++;
} else {
_numTxErr++;
}
}
bool CandleApiInterface::readMessage(QList<CanMessage> &msglist, unsigned int timeout_ms)
{
candle_frame_t frame;
CanMessage msg;
if (candle_frame_read(_handle, &frame, timeout_ms)) {
if (candle_frame_type(&frame)==CANDLE_FRAMETYPE_RECEIVE) {
_numRx++;
msg.setInterfaceId(getId());
msg.setErrorFrame(false);
msg.setId(candle_frame_id(&frame));
msg.setExtended(candle_frame_is_extended_id(&frame));
msg.setRTR(candle_frame_is_rtr(&frame));
uint8_t dlc = candle_frame_dlc(&frame);
uint8_t *data = candle_frame_data(&frame);
msg.setLength(dlc);
for (int i=0; i<dlc; i++) {
msg.setByte(i, data[i]);
}
uint32_t dev_ts = candle_frame_timestamp_us(&frame) - _deviceTicksStart;
uint64_t ts_us = _hostOffsetStart + dev_ts;
uint64_t us_since_start = _backend.getUsecsSinceMeasurementStart();
if (us_since_start > 0x180000000) { // device timestamp overflow must have happend at least once
ts_us += us_since_start & 0xFFFFFFFF00000000;
}
msg.setTimestamp(ts_us/1000000, ts_us % 1000000);
msglist.append(msg);
return true;
}
}
return false;
}
bool CandleApiInterface::updateStatistics()
{
return true;
}
uint32_t CandleApiInterface::getState()
{
return CanInterface::state_ok;
}
int CandleApiInterface::getNumRxFrames()
{
return _numRx;
}
int CandleApiInterface::getNumRxErrors()
{
return 0;
}
int CandleApiInterface::getNumTxFrames()
{
return _numTx;
}
int CandleApiInterface::getNumTxErrors()
{
return _numTxErr;
}
int CandleApiInterface::getNumRxOverruns()
{
return 0;
}
int CandleApiInterface::getNumTxDropped()
{
return 0;
}
wstring CandleApiInterface::getPath() const
{
return wstring(candle_dev_get_path(_handle));
}
void CandleApiInterface::update(candle_handle dev)
{
candle_dev_free(_handle);
_handle = dev;
}