Small project to display some OBD values from the Toyota GT86/ Subaru BRZ/ Scion FRS on an OLED display.
Dependencies: Adafruit_GFX MODSERIAL mbed-rtos mbed
IsoTpHandler.cpp
- Committer:
- chrta
- Date:
- 2014-05-11
- Revision:
- 7:a19b63c0a0fa
- Parent:
- 4:0e2d6cc31afb
File content as of revision 7:a19b63c0a0fa:
#include "IsoTpHandler.h"
#include "PidDecoder.h"
#include "MODSERIAL.h"
extern MODSERIAL pc;
#ifdef ACTIVATE_DEBUG_OUTPUT
#define DEBUG_PRINT(format, ...) pc.printf(format, ##__VA_ARGS__)
#else
#define DEBUG_PRINT(format, ...)
#endif
static PidDecoder pidDecoder;
enum IsoTpMessageType
{
SINGLE_FRAME = 0, ///< The single frame transferred contains the complete payload of up to 7 bytes (normal addressing) or 6 bytes (extended addressing)
FIRST_FRAME = 1, ///< The first frame of a longer multi-frame message packet, used when more than 6/7 bytes of data segmented must be communicated. The first frame contains the length of the full packet, along with the initial data.
CONSECUTIVE_FRAME = 2, ///< A frame containing subsequent data for a multi-frame packet
FLOW_CONTOL_FRAME = 3, ///< The response from the receiver, acknowledging a First-frame segment. It lays down the parameters for the transmission of further consecutive frames.
};
enum IsoTpFlowType
{
CLEAR_TO_SEND = 0,
WAIT = 1,
OVERFLOW_ABORT = 2,
};
const IsoTpHandler::IdleState IsoTpHandler::idleState;
const IsoTpHandler::ConsequtiveTransferState IsoTpHandler::consequtiveTransferState;
IsoTpHandler::IdleState::IdleState()
{
}
void IsoTpHandler::IdleState::processInput(const CANMessage* message, IsoTpHandler* context) const
{
if (!IsoTpHandler::isValidIsoTpPacket(message))
{
return;
}
uint8_t messageType = message->data[0] >> 4;
if (messageType == SINGLE_FRAME)
{
uint8_t messageSize = message->data[0] & 0x0F;
if (messageSize > message->len - 1)
{
DEBUG_PRINT("Iso tp message is too short: iso len %d vs can len %d\r\n", messageSize, message->len);
return;
}
context->handle_decoded_packet(&message->data[1], messageSize);
return;
}
if (messageType == FIRST_FRAME)
{
if (message->len != 8)
{
DEBUG_PRINT("Invalid iso tp message length for FIRST_FRAME, length is %d\r\n", message->len);
return;
}
uint16_t messageSize = ((message->data[0] & 0x0F) << 8) | (message->data[1]);
context->init_consequtive_reading(messageSize, &message->data[2]);
context->setState(&consequtiveTransferState);
return;
}
if (messageType == CONSECUTIVE_FRAME)
{
DEBUG_PRINT("Invalid iso tp message in idle state, because unexpected CONSECUTIVE_FRAME received\r\n");
return;
}
if (messageType == FLOW_CONTOL_FRAME)
{
DEBUG_PRINT("Invalid iso tp message, because unexpected FLOW_CONTOL_FRAME received\r\n");
return;
}
DEBUG_PRINT("Invalid iso tp message ?!\r\n");
}
void IsoTpHandler::IdleState::onEnter(IsoTpHandler* context) const
{
}
void IsoTpHandler::IdleState::onLeave(IsoTpHandler* context) const
{
}
IsoTpHandler::ConsequtiveTransferState::ConsequtiveTransferState()
{
}
void IsoTpHandler::ConsequtiveTransferState::processInput(const CANMessage* message, IsoTpHandler* context) const
{
if (!IsoTpHandler::isValidIsoTpPacket(message))
{
return;
}
uint8_t messageType = message->data[0] >> 4;
if (messageType == SINGLE_FRAME)
{
DEBUG_PRINT("Received SINGLE_FRAME, expected consequitve frame\r\n");
return;
}
if (messageType == FIRST_FRAME)
{
DEBUG_PRINT("Received FIRST_FRAME, expected consequitve frame\r\n");
return;
}
if (messageType == CONSECUTIVE_FRAME)
{
uint8_t index = message->data[0] & 0x0F;
if (index != context->getExpectedIndex())
{
DEBUG_PRINT("In consequiive frame, received index %d, expected %d\r\n", index, context->getExpectedIndex());
context->setState(&IsoTpHandler::idleState);
return;
}
if (context->appendReceivedData(&message->data[1], message->len - 1))
{
DEBUG_PRINT("In consequtive frame, change state\r\n");
context->setState(&IsoTpHandler::idleState);
}
context->incrementExpectedIndex();
return;
}
if (messageType == FLOW_CONTOL_FRAME)
{
DEBUG_PRINT("Received FLOW_CONTROL_FRAME, expected consequitve frame\r\n");
return;
}
DEBUG_PRINT("Invalid iso tp message, expected consequitve frame ?!\r\n");
}
void IsoTpHandler::ConsequtiveTransferState::onEnter(IsoTpHandler* context) const
{
}
void IsoTpHandler::ConsequtiveTransferState::onLeave(IsoTpHandler* context) const
{
}
IsoTpHandler::IsoTpHandler(CAN* canInterface)
: m_state(&idleState)
, m_canInterface (canInterface)
{
m_state->onEnter(this);
}
void IsoTpHandler::processCanMessage(const CANMessage* message)
{
DEBUG_PRINT("Received new CAN message:\r\n");
DEBUG_PRINT(" ID: 0x%X\r\n", message->id);
DEBUG_PRINT(" Len: %d\r\n", message->len);
DEBUG_PRINT(" Type: %s\r\n", (message->type == CANData ? "data" : "remote"));
DEBUG_PRINT(" Format: %s\r\n", (message->format == CANStandard ? "standard" : "extended"));
DEBUG_PRINT( "Data: ");
if (message->len > 8) {
//paranoia
error(" WRONG DATA LEN! ");
return;
}
for (unsigned int i = 0; i < message->len; ++i) {
DEBUG_PRINT("%X ", message->data[i]);
}
DEBUG_PRINT("\r\n");
m_state->processInput(message, this);
}
void IsoTpHandler::handle_decoded_packet(const uint8_t* data, uint16_t length)
{
//todo write into mailbox so another thread can consume this or directly call a callback
DEBUG_PRINT("New decoded packet: Length: %d\r\n", length);
DEBUG_PRINT(" Data: ");
for (uint16_t i = 0; i < length; ++i)
{
DEBUG_PRINT("%X ", data[i]);
}
DEBUG_PRINT("\r\n");
pidDecoder.decode(data, length);
}
void IsoTpHandler::init_consequtive_reading(uint16_t messageSize, const uint8_t* data)
{
char msgContent[8];
msgContent[0] = (FLOW_CONTOL_FRAME << 4) | CLEAR_TO_SEND;
msgContent[1] = 0; //remaining frames should to be sent without flow control or delay
msgContent[2] = 0; //Separation Time (ST), minimum delay time between frames (end of one frame and the beginning of the other)
//<= 127, separation time in milliseconds.
//0xF1 to 0xF9, 100 to 900 microseconds.
msgContent[3] = 0;
msgContent[4] = 0;
msgContent[5] = 0;
msgContent[6] = 0;
msgContent[7] = 0;
m_canInterface->write(CANMessage(0x7E0, msgContent, sizeof(msgContent))); //or 7DF?
memcpy(m_messageBuffer, data, 6);
m_expectedMessageSize = messageSize;
m_currentMessageSize = 6;
m_expectedIndex = 1;
}
void IsoTpHandler::setState(const State* state)
{
if (state == m_state)
{
return;
}
m_state->onLeave(this);
m_state = state;
m_state->onEnter(this);
}
bool IsoTpHandler::isValidIsoTpPacket(const CANMessage* message)
{
if (message->len < 1)
{
DEBUG_PRINT("Invalid iso tp message, length is zero\r\n");
return false;
}
uint8_t messageType = message->data[0] >> 4;
if (messageType > FLOW_CONTOL_FRAME)
{
DEBUG_PRINT("Invalid iso tp message type %d\r\n", messageType);
return false;
}
return true;
}
uint8_t IsoTpHandler::getExpectedIndex() const
{
return m_expectedIndex;
}
void IsoTpHandler::incrementExpectedIndex()
{
++m_expectedIndex;
if (m_expectedIndex >= 16)
{
m_expectedIndex = 0;
}
}
bool IsoTpHandler::appendReceivedData(const uint8_t* data, uint8_t length)
{
if (sizeof(m_messageBuffer) < m_currentMessageSize + length)
{
DEBUG_PRINT("Buffer in appendReceivedData too small, already got %d bytes, new %d bytes, expected %d bytes.\r\n", m_currentMessageSize, length, m_expectedMessageSize);
return true; //switch state
}
if (m_expectedMessageSize < m_currentMessageSize + length)
{
DEBUG_PRINT("Got too much data in appendReceivedData, already got %d bytes, new %d bytes, expected %d bytes.\r\n", m_currentMessageSize, length, m_expectedMessageSize);
length = m_expectedMessageSize - m_currentMessageSize;
}
memcpy(m_messageBuffer + m_currentMessageSize, data, length);
m_currentMessageSize += length;
if (m_expectedMessageSize == m_currentMessageSize)
{
handle_decoded_packet(m_messageBuffer, m_expectedMessageSize);
return true; //switch state
}
return false; //do not switch state
}