You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					233 lines
				
				7.9 KiB
			
		
		
			
		
	
	
					233 lines
				
				7.9 KiB
			| 
								 
											6 years ago
										 
									 | 
							
								#include "stdafx.h"
							 | 
						||
| 
								 | 
							
								#include "J2534Connection_ISO15765.h"
							 | 
						||
| 
								 | 
							
								#include "Timer.h"
							 | 
						||
| 
								 | 
							
								#include "constants_ISO15765.h"
							 | 
						||
| 
								 | 
							
								#include <chrono>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								J2534Connection_ISO15765::J2534Connection_ISO15765(
							 | 
						||
| 
								 | 
							
									std::shared_ptr<PandaJ2534Device> panda_dev,
							 | 
						||
| 
								 | 
							
									unsigned long ProtocolID,
							 | 
						||
| 
								 | 
							
									unsigned long Flags,
							 | 
						||
| 
								 | 
							
									unsigned long BaudRate
							 | 
						||
| 
								 | 
							
								) : J2534Connection(panda_dev, ProtocolID, Flags, BaudRate), wftMax(0) {
							 | 
						||
| 
								 | 
							
									this->port = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (BaudRate % 100 || BaudRate < 10000 || BaudRate > 5000000)
							 | 
						||
| 
								 | 
							
										throw ERR_INVALID_BAUDRATE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									panda_dev->panda->set_can_speed_cbps(panda::PANDA_CAN1, (uint16_t)(BaudRate / 100));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								unsigned long J2534Connection_ISO15765::validateTxMsg(PASSTHRU_MSG* msg) {
							 | 
						||
| 
								 | 
							
									if ((msg->DataSize < this->getMinMsgLen() + (msg_is_extaddr(msg) ? 1 : 0) ||
							 | 
						||
| 
								 | 
							
										msg->DataSize > this->getMaxMsgLen() + (msg_is_extaddr(msg) ? 1 : 0) ||
							 | 
						||
| 
								 | 
							
										(val_is_29bit(msg->TxFlags) != this->_is_29bit() && !check_bmask(this->Flags, CAN_ID_BOTH))))
							 | 
						||
| 
								 | 
							
										return ERR_INVALID_MSG;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									int fid = get_matching_out_fc_filter_id(std::string((const char*)msg->Data, msg->DataSize), msg->TxFlags, 0xFFFFFFFF);
							 | 
						||
| 
								 | 
							
									if (msg->DataSize > getMaxMsgSingleFrameLen() && fid == -1) return ERR_NO_FLOW_CONTROL; //11 bytes (4 for CANid, 7 payload) is max length of input frame.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return STATUS_NOERROR;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								std::shared_ptr<MessageTx> J2534Connection_ISO15765::parseMessageTx(PASSTHRU_MSG& msg) {
							 | 
						||
| 
								 | 
							
									int fid = get_matching_out_fc_filter_id(std::string((const char*)msg.Data, msg.DataSize), msg.TxFlags, 0xFFFFFFFF);
							 | 
						||
| 
								 | 
							
									if (msg.DataSize > getMaxMsgSingleFrameLen() && fid == -1) 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return std::dynamic_pointer_cast<MessageTx>(
							 | 
						||
| 
								 | 
							
										std::make_shared<MessageTx_ISO15765>(shared_from_this(), msg, (fid == -1) ? nullptr : this->filters[fid])
							 | 
						||
| 
								 | 
							
										);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//https://happilyembedded.wordpress.com/2016/02/15/can-multiple-frame-transmission/
							 | 
						||
| 
								 | 
							
								void J2534Connection_ISO15765::processMessage(const J2534Frame& msg) {
							 | 
						||
| 
								 | 
							
									if (msg.ProtocolID != CAN) return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									int fid = get_matching_in_fc_filter_id(msg, this->Flags);
							 | 
						||
| 
								 | 
							
									if (fid == -1) return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									auto filter = this->filters[fid];
							 | 
						||
| 
								 | 
							
									bool is_ext_addr = check_bmask(filter->flags, ISO15765_ADDR_TYPE);
							 | 
						||
| 
								 | 
							
									uint8_t addrlen = is_ext_addr ? 5 : 4;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									switch (msg_get_type(msg, addrlen)) {
							 | 
						||
| 
								 | 
							
									case FRAME_FLOWCTRL:
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											if (this->txbuff.size() == 0)
							 | 
						||
| 
								 | 
							
												return;
							 | 
						||
| 
								 | 
							
											if (msg.Data.size() < addrlen + 3) return;
							 | 
						||
| 
								 | 
							
											uint8_t flow_status = msg.Data[addrlen] & 0x0F;
							 | 
						||
| 
								 | 
							
											uint8_t block_size = msg.Data[addrlen + 1];
							 | 
						||
| 
								 | 
							
											uint8_t st_min = msg.Data[addrlen + 2];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											auto txConvo = std::static_pointer_cast<MessageTx_ISO15765>(this->txbuff.front());
							 | 
						||
| 
								 | 
							
											switch (flow_status) {
							 | 
						||
| 
								 | 
							
											case FLOWCTRL_CONTINUE: {
							 | 
						||
| 
								 | 
							
												if (st_min > 0xF9) break;
							 | 
						||
| 
								 | 
							
												if (st_min >= 0xf1 && st_min <= 0xf9) {
							 | 
						||
| 
								 | 
							
													txConvo->flowControlContinue(block_size, std::chrono::microseconds((st_min & 0x0F) * 100));
							 | 
						||
| 
								 | 
							
												} else if(st_min <= 0x7f) {
							 | 
						||
| 
								 | 
							
													txConvo->flowControlContinue(block_size, std::chrono::microseconds(st_min * 1000));
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
													break;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												txConvo->scheduleImmediate();
							 | 
						||
| 
								 | 
							
												this->rescheduleExistingTxMsgs();
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											case FLOWCTRL_WAIT:
							 | 
						||
| 
								 | 
							
												txConvo->flowControlWait(this->wftMax);
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											case FLOWCTRL_ABORT:
							 | 
						||
| 
								 | 
							
												txConvo->flowControlAbort();
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									case FRAME_SINGLE:
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											this->rxConversations[fid] = nullptr; //Reset any current transaction.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (is_ext_addr) {
							 | 
						||
| 
								 | 
							
												if ((msg.Data[5] & 0x0F) > 6) return;
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												if ((msg.Data[4] & 0x0F) > 7) return;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											J2534Frame outframe(ISO15765, msg.RxStatus, 0, msg.Timestamp);
							 | 
						||
| 
								 | 
							
											if (msg.Data.size() != 8 && check_bmask(this->Flags, ISO15765_FRAME_PAD))
							 | 
						||
| 
								 | 
							
												outframe.RxStatus |= ISO15765_PADDING_ERROR;
							 | 
						||
| 
								 | 
							
											if (is_ext_addr)
							 | 
						||
| 
								 | 
							
												outframe.RxStatus |= ISO15765_ADDR_TYPE;
							 | 
						||
| 
								 | 
							
											outframe.Data = msg.Data.substr(0, addrlen) + msg.Data.substr(addrlen + 1, msg.Data[addrlen]);
							 | 
						||
| 
								 | 
							
											outframe.ExtraDataIndex = outframe.Data.size();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											addMsgToRxQueue(outframe);
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									case FRAME_FIRST:
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											if (msg.Data.size() < 12) {
							 | 
						||
| 
								 | 
							
												//A frame was received that could have held more data.
							 | 
						||
| 
								 | 
							
												//No examples of this protocol show that happening, so
							 | 
						||
| 
								 | 
							
												//it will be assumed that it is grounds to reset rx.
							 | 
						||
| 
								 | 
							
												this->rxConversations[fid] = nullptr;
							 | 
						||
| 
								 | 
							
												return;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											J2534Frame outframe(ISO15765, msg.RxStatus | START_OF_MESSAGE, 0, msg.Timestamp);
							 | 
						||
| 
								 | 
							
											if (is_ext_addr)
							 | 
						||
| 
								 | 
							
												outframe.RxStatus |= ISO15765_ADDR_TYPE;
							 | 
						||
| 
								 | 
							
											outframe.Data = msg.Data.substr(0, addrlen);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											addMsgToRxQueue(outframe);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											this->rxConversations[fid] = std::make_shared<MessageRx>(
							 | 
						||
| 
								 | 
							
												((msg.Data[addrlen] & 0x0F) << 8) | msg.Data[addrlen + 1],
							 | 
						||
| 
								 | 
							
												msg.Data.substr(addrlen + 2, 12 - (addrlen + 2)),
							 | 
						||
| 
								 | 
							
												msg.RxStatus, filter);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											//TODO maybe the flow control should also be scheduled in the TX list.
							 | 
						||
| 
								 | 
							
											//Doing it this way because the filter can be 5 bytes in ext address mode.
							 | 
						||
| 
								 | 
							
											std::string flowfilter = filter->get_flowctrl();
							 | 
						||
| 
								 | 
							
											uint32_t flow_addr = (((uint8_t)flowfilter[0]) << 24) | ((uint8_t)(flowfilter[1]) << 16) | ((uint8_t)(flowfilter[2]) << 8) | ((uint8_t)flowfilter[3]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											std::string flowstrlresp;
							 | 
						||
| 
								 | 
							
											if (flowfilter.size() > 4)
							 | 
						||
| 
								 | 
							
												flowstrlresp += flowfilter[4];
							 | 
						||
| 
								 | 
							
											flowstrlresp += std::string("\x30\x00\x00", 3);
							 | 
						||
| 
								 | 
							
											if (check_bmask(filter->flags, ISO15765_FRAME_PAD)) {
							 | 
						||
| 
								 | 
							
												flowstrlresp += std::string(8 - flowstrlresp.size(), '\x00');
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (auto panda_dev_sp = this->panda_dev.lock()) {
							 | 
						||
| 
								 | 
							
												panda_dev_sp->panda->can_send(flow_addr, val_is_29bit(msg.RxStatus), (const uint8_t *)flowstrlresp.c_str(), (uint8_t)flowstrlresp.size(), panda::PANDA_CAN1);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									case FRAME_CONSEC:
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											auto& convo = this->rxConversations[fid];
							 | 
						||
| 
								 | 
							
											if (convo == nullptr) return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (!convo->rx_add_frame(msg.Data[addrlen], (is_ext_addr ? 6 : 7), msg.Data.substr(addrlen + 1))) {
							 | 
						||
| 
								 | 
							
												//Delete this conversation.
							 | 
						||
| 
								 | 
							
												convo = nullptr;
							 | 
						||
| 
								 | 
							
												return;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											std::string final_msg;
							 | 
						||
| 
								 | 
							
											if (convo->flush_result(final_msg)) {
							 | 
						||
| 
								 | 
							
												convo = nullptr;
							 | 
						||
| 
								 | 
							
												J2534Frame outframe(ISO15765, msg.RxStatus, 0, msg.Timestamp);
							 | 
						||
| 
								 | 
							
												if (is_ext_addr)
							 | 
						||
| 
								 | 
							
													outframe.RxStatus |= ISO15765_ADDR_TYPE;
							 | 
						||
| 
								 | 
							
												outframe.Data = msg.Data.substr(0, addrlen) + final_msg;
							 | 
						||
| 
								 | 
							
												outframe.ExtraDataIndex = outframe.Data.size();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												addMsgToRxQueue(outframe);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void J2534Connection_ISO15765::setBaud(unsigned long BaudRate) {
							 | 
						||
| 
								 | 
							
									if (auto panda_dev = this->getPandaDev()) {
							 | 
						||
| 
								 | 
							
										if (BaudRate % 100 || BaudRate < 10000 || BaudRate > 5000000)
							 | 
						||
| 
								 | 
							
											throw ERR_NOT_SUPPORTED;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										panda_dev->panda->set_can_speed_cbps(panda::PANDA_CAN1, (uint16_t)(BaudRate / 100));
							 | 
						||
| 
								 | 
							
										return J2534Connection::setBaud(BaudRate);
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										throw ERR_DEVICE_NOT_CONNECTED;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								long J2534Connection_ISO15765::PassThruStartMsgFilter(unsigned long FilterType, PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg,
							 | 
						||
| 
								 | 
							
									PASSTHRU_MSG *pFlowControlMsg, unsigned long *pFilterID) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (FilterType != FLOW_CONTROL_FILTER) return ERR_INVALID_FILTER_ID;
							 | 
						||
| 
								 | 
							
									return J2534Connection::PassThruStartMsgFilter(FilterType, pMaskMsg, pPatternMsg, pFlowControlMsg, pFilterID);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int J2534Connection_ISO15765::get_matching_out_fc_filter_id(const std::string& msgdata, unsigned long flags, unsigned long flagmask) {
							 | 
						||
| 
								 | 
							
									for (unsigned int i = 0; i < this->filters.size(); i++) {
							 | 
						||
| 
								 | 
							
										if (this->filters[i] == nullptr) continue;
							 | 
						||
| 
								 | 
							
										auto filter = this->filters[i]->get_flowctrl();
							 | 
						||
| 
								 | 
							
										if (filter == msgdata.substr(0, filter.size()) &&
							 | 
						||
| 
								 | 
							
											(this->filters[i]->flags & flagmask) == (flags & flagmask))
							 | 
						||
| 
								 | 
							
											return i;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return -1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int J2534Connection_ISO15765::get_matching_in_fc_filter_id(const J2534Frame& msg, unsigned long flagmask) {
							 | 
						||
| 
								 | 
							
									for (unsigned int i = 0; i < this->filters.size(); i++) {
							 | 
						||
| 
								 | 
							
										if (this->filters[i] == nullptr) continue;
							 | 
						||
| 
								 | 
							
										if (this->filters[i]->check(msg) == FILTER_RESULT_MATCH &&
							 | 
						||
| 
								 | 
							
											(this->filters[i]->flags & flagmask) == (msg.RxStatus & flagmask))
							 | 
						||
| 
								 | 
							
											return i;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return -1;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void J2534Connection_ISO15765::processIOCTLSetConfig(unsigned long Parameter, unsigned long Value) {
							 | 
						||
| 
								 | 
							
									switch (Parameter) {
							 | 
						||
| 
								 | 
							
									case ISO15765_WFT_MAX:
							 | 
						||
| 
								 | 
							
										this->wftMax = Value;
							 | 
						||
| 
								 | 
							
										break;
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										J2534Connection::processIOCTLSetConfig(Parameter, Value);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								unsigned long J2534Connection_ISO15765::processIOCTLGetConfig(unsigned long Parameter) {
							 | 
						||
| 
								 | 
							
									switch (Parameter) {
							 | 
						||
| 
								 | 
							
									case ISO15765_WFT_MAX:
							 | 
						||
| 
								 | 
							
										return this->wftMax;
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										return J2534Connection::processIOCTLGetConfig(Parameter);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |