bool J2534DiagInterface::disconnect()
{
	if (_j2534)
	{
		long ret = 0;
		// Remove filters:
		for (unsigned char k=0; k<_numFilters; k++)
		{
			ret = _j2534->PassThruStopMsgFilter(_ChannelID, _FilterID[k]);
#ifdef __FSSM_DEBUG__
			if (STATUS_NOERROR != ret)
				printErrorDescription("PassThruStopMsgFilter() failed: ", ret);
#endif
		}
		_numFilters = 0;
		// Disconnect channel:
		ret = _j2534->PassThruDisconnect(_ChannelID);
		if (STATUS_NOERROR != ret)
		{
#ifdef __FSSM_DEBUG__
			printErrorDescription("PassThruDisconnect() failed: ", ret);
#endif
			return false;
		}
		_connected = false;
		setProtocolType( protocol_NONE );
		setProtocolBaudrate( 0 );
		return true;
	}
	else
		return false;
}
bool J2534DiagInterface::close()
{
	if (_j2534)
	{
		long ret = 0;
		if (_connected)
			disconnect();
		// Close interface (only 0404-API):
		if (_j2534->libraryAPIversion() != J2534_API_version::v0202)
		{
			ret = _j2534->PassThruClose(_DeviceID);
			if (STATUS_NOERROR != ret)
			{
#ifdef __FSSM_DEBUG__
				printErrorDescription("PassThruClose() failed: ", ret);
#endif
				return false;
			}
		}
		// Clean up:
		delete _j2534;
		_j2534 = NULL;
		setName("J2534 Pass-Through");
		setVersion("");
		return true;
	}
	else
		return false;
}
bool J2534DiagInterface::clearReceiveBuffer()
{
	long ret = _j2534->PassThruIoctl(_ChannelID, CLEAR_RX_BUFFER, (void *)NULL, (void *)NULL);
	if (STATUS_NOERROR != ret)
	{
#ifdef __FSSM_DEBUG__
		printErrorDescription("PassThruIoctl() for parameter CLEAR_RX_BUFFER failed: ", ret);
#endif
		return false;
	}
	return true;
}
bool J2534DiagInterface::write(std::vector<char> buffer)
{
	if (_j2534 && _connected)
	{
		long ret = 0;
		// Setup message:
		PASSTHRU_MSG tx_msg;
		memset(&tx_msg, 0, sizeof(tx_msg));
		if (protocolType() == AbstractDiagInterface::protocol_SSM2_ISO14230)
		{ 
			tx_msg.ProtocolID = ISO9141;
		}
		else if (protocolType() == AbstractDiagInterface::protocol_SSM2_ISO15765)
		{
			tx_msg.ProtocolID = ISO15765;
			tx_msg.TxFlags = ISO15765_FRAME_PAD;
		}
		else
			return false;
		for (unsigned int k=0; k<buffer.size(); k++)
			tx_msg.Data[k] = buffer[k];
		tx_msg.DataSize = buffer.size();
		unsigned long txNumMsgs = 1;
		unsigned long timeout = 1000;	// wait until message has been transmitted
		// Send message:
		ret = _j2534->PassThruWriteMsgs(_ChannelID, &tx_msg, &txNumMsgs, timeout);
		if (STATUS_NOERROR == ret)
			return true;
		else
		{
#ifdef __FSSM_DEBUG__
			printErrorDescription("PassThruWriteMsgs() failed: ", ret);
#endif
			return false;
		}
	}
	else
		return false;
}
bool J2534DiagInterface::write(std::vector<char> buffer)
{
	if (_j2534 && _connected)
	{
		long ret = 0;
		// Setup message:
		PASSTHRU_MSG tx_msg;
		memset(&tx_msg, 0, sizeof(tx_msg));
		switch(protocolType()) {
		case AbstractDiagInterface::protocol_SSM2_ISO14230:
			tx_msg.ProtocolID = ISO9141;
			break;
		case AbstractDiagInterface::protocol_SSM2_ISO15765:
			tx_msg.ProtocolID = ISO15765;
			tx_msg.TxFlags = ISO15765_FRAME_PAD;
			break;
		default:
			return false;
		}
		std::copy(buffer.begin(), buffer.end(), tx_msg.Data);
		tx_msg.DataSize = buffer.size();
		unsigned long txNumMsgs = 1;
		unsigned long timeout = 1000;	// wait until message has been transmitted
		// Send message:
		ret = _j2534->PassThruWriteMsgs(_ChannelID, &tx_msg, &txNumMsgs, timeout);
		if (STATUS_NOERROR == ret)
			return true;
		else
		{
#ifdef __FSSM_DEBUG__
			printErrorDescription("PassThruWriteMsgs() failed: ", ret);
#endif
			return false;
		}
	}
	else
		return false;
}
bool J2534DiagInterface::read(std::vector<char> *buffer)
{
	if (_j2534 && _connected)
	{
		long ret = 0;
		// Setup message-container:
		PASSTHRU_MSG rx_msg;
		memset(&rx_msg, 0, sizeof(rx_msg));
		if (protocolType() == AbstractDiagInterface::protocol_SSM2_ISO14230)
		{
			rx_msg.ProtocolID = ISO9141;
		}
		else if (protocolType() == AbstractDiagInterface::protocol_SSM2_ISO15765)
		{
			rx_msg.ProtocolID = ISO15765;
		}
		else
			return false;
		unsigned long rxNumMsgs = 1;
		unsigned long timeout = 0;	// return immediately
		// Read all available messages:
		do
		{
			ret = _j2534->PassThruReadMsgs(_ChannelID, &rx_msg, &rxNumMsgs, timeout);
			if ((STATUS_NOERROR == ret) && rxNumMsgs)
			{
#ifdef __FSSM_DEBUG__
				std::cout << "PassThruReadMsgs(): received J2534-message with protocol id 0x" << std::hex << rx_msg.ProtocolID
					<< ", rx status 0x" << rx_msg.RxStatus << ", extra data index " << std::dec << rx_msg.ExtraDataIndex << ":\n"
					<< libFSSM::StrToMultiLineHexstr(rx_msg.Data, rx_msg.DataSize);
#endif
				if (rx_msg.RxStatus & TX_MSG_TYPE)
				{
#ifdef __FSSM_DEBUG__
					if (rx_msg.RxStatus & TX_DONE)	// SAE J2534-1 (dec 2004): ISO-15765 only
					{
						std::cout << "=> message is transmit confirmation message\n";
						continue;
					}
					else
						std::cout << "=> message is loopback message\n";
#endif
				}
				else
				{
					if (rx_msg.RxStatus & START_OF_MESSAGE)
					{
						/* NOTE:
						 * - incoming (multi-frame) msg transfer has commenced (ISO-15765) /
						 *   first byte of an incoming message has been received (ISO-9141 / ISO-14230)
						 * - ISO-15765: message contains CAN-ID only                                   */
#ifdef __FSSM_DEBUG__
						std::cout << "=> message indicates that an incoming message transfer has commenced.\n";
#endif
						continue;
					}
					if ((protocolType() == protocol_SSM2_ISO15765) && (rx_msg.RxStatus & ISO15765_PADDING_ERROR))
					{
						// NOTE: ISO-15765 CAN frame was received with less than 8 data bytes
#ifdef __FSSM_DEBUG__
						std::cout << "=> message indicates ISO15765 padding error.\n";
#endif
						continue;
					}
					// NOTE: all other flags do not affect the transferred data or are not defined for the ISO-protocols
				}
				// Extract data:
				if (rx_msg.DataSize > 0)
				{
#ifdef __FSSM_DEBUG__
					if ((rx_msg.ExtraDataIndex == 0) && (_j2534->libraryAPIversion() == J2534_API_version::v0404))
					{
						std::cout << "WARNING: ExtraDataIndex is 0, which should be the case only for pure status messages !\n";
					}
					else if (rx_msg.ExtraDataIndex < rx_msg.DataSize)
					{
						if ((_j2534->libraryAPIversion() == J2534_API_version::v0404) || (protocolType() != protocol_SSM2_ISO14230) ||
							((protocolType() == protocol_SSM2_ISO14230) && (rx_msg.ExtraDataIndex < (rx_msg.DataSize - 1))))
							std::cout << "WARNING: ExtraDataIndex is smaller than expected !\n";
						/* NOTE:
						 * - 04.04-API: (SAE-J2534-1, dec 2004): ExtraDataIndex only used with J1850 PWM
						 * - 02.02-API: (SAE-J2534, feb 2002):   ExtraDataIndex also used with J1850 VPW, ISO-9141, ISO-14230 */
					}
#endif
					buffer->reserve(rx_msg.DataSize);
					buffer->assign(rx_msg.Data, rx_msg.Data + rx_msg.DataSize);
				}
			}
		} while ((STATUS_NOERROR == ret) && rxNumMsgs);
		if ((STATUS_NOERROR == ret) || (ERR_BUFFER_EMPTY == ret))
			return true;
#ifdef __FSSM_DEBUG__
		else
			printErrorDescription("PassThruReadMsgs() failed: ", ret);
#endif
	}
	return false;
}
bool J2534DiagInterface::open( std::string name )
{
	if (_j2534)
		return false;
	else
	{
		_j2534 = new J2534_API;
		if (_j2534->selectLibrary(name))
		{
			char FirmwareVersion[80] = {0,};
			char DllVersion[80] = {0,};
			char ApiVersion[80] = {0,};
			long ret = 0;
			// Open interface (only 0404-API):
			if (_j2534->libraryAPIversion() != J2534_API_version::v0202)
			{
				_DeviceID = 0;
				ret = _j2534->PassThruOpen(NULL, &_DeviceID);
				if (STATUS_NOERROR != ret)
				{
#ifdef __FSSM_DEBUG__
					printErrorDescription("PassThruOpen() failed: ", ret);
#endif
					delete _j2534;
					_j2534 = NULL;
					return false;
				}
			}
			// Read hardware/software information:
			if (_j2534->libraryAPIversion() == J2534_API_version::v0202)
				ret = _j2534->PassThruReadVersion(FirmwareVersion, DllVersion, ApiVersion);
			else
				ret = _j2534->PassThruReadVersion(_DeviceID, FirmwareVersion, DllVersion, ApiVersion);
			if (STATUS_NOERROR == ret)
			{
				setVersion(std::string(FirmwareVersion) + " (DLL: " + std::string(DllVersion) + ", API: " + std::string(ApiVersion) +")");
#ifdef __FSSM_DEBUG__
				std::cout << "Interface information:\n";
				std::cout << "   Firmware version: " << FirmwareVersion << '\n';
				std::cout << "   DLL version:      " << DllVersion << '\n';
				std::cout << "   API version:      " << ApiVersion << '\n';
#endif
			}
#ifdef __FSSM_DEBUG__
			else
				printErrorDescription("PassThruReadVersion() failed: ", ret);
#endif
			// Get and save library data:
			for (const J2534Library& lib : J2534_API::getAvailableJ2534Libs())
			{
				if (lib.path == name)
				{
					// Interface name
					setName(lib.name);
					// Supported protocols
					std::vector<protocol_type> supportedProtocols;
					const J2534_protocol_flags p = lib.protocols;
					if (bool(p & J2534_protocol_flags::iso9141) ||
					    bool(p & J2534_protocol_flags::iso14230))
						supportedProtocols.push_back(protocol_SSM2_ISO14230);
					if (bool(p & J2534_protocol_flags::iso15765))
						supportedProtocols.push_back(protocol_SSM2_ISO15765);
					setSupportedProtocols(supportedProtocols);
					break;
				}
			}
			return true;
		}
		else
		{
#ifdef __FSSM_DEBUG__
			std::cout << "Error: invalid library selected\n";
#endif
			delete _j2534;
			_j2534 = NULL;
			return false;
		}
	}
}
bool J2534DiagInterface::connect(AbstractDiagInterface::protocol_type protocol)
{
	if ((protocol != AbstractDiagInterface::protocol_SSM2_ISO14230) && (protocol != AbstractDiagInterface::protocol_SSM2_ISO15765))
	{
#ifdef __FSSM_DEBUG__
		std::cout << "Error: selected protocol is not supported\n";
#endif
		return false;
	}
	if (_j2534)
	{
		unsigned long ProtocolID = 0;
		unsigned long Flags = 0;
		unsigned long BaudRate = 0;
		long ret = 0;
		if (protocol == AbstractDiagInterface::protocol_SSM2_ISO14230)
		{
			ProtocolID = ISO9141; // also: ISO14230
			Flags = ISO9141_NO_CHECKSUM;
			BaudRate = 4800;
		}
		else if (protocol == AbstractDiagInterface::protocol_SSM2_ISO15765)
		{
			ProtocolID = ISO15765;
			Flags = 0;
			BaudRate = 500000;
		}
		// CONNECT CHANNEL:
		if (_j2534->libraryAPIversion() == J2534_API_version::v0202)
			ret = _j2534->PassThruConnect(ProtocolID, Flags, &_ChannelID);
		else
			ret = _j2534->PassThruConnect(_DeviceID, ProtocolID, Flags, BaudRate, &_ChannelID);
		if (STATUS_NOERROR != ret)
		{
#ifdef __FSSM_DEBUG__
			printErrorDescription("PassThruConnect() failed: ", ret);
#endif
			return false;
		}
		/* ----- SET CONFIGURATION ----- */
		SCONFIG_LIST Input;
		SCONFIG CfgItems[1];
		// Echo (MANDATORY):
		CfgItems[0].Parameter = LOOPBACK;   // Echo off/on
		if (protocol == AbstractDiagInterface::protocol_SSM2_ISO14230)
			CfgItems[0].Value = ON;
		else
			CfgItems[0].Value = OFF;
		Input.NumOfParams = 1;
		Input.ConfigPtr = CfgItems;
		ret = _j2534->PassThruIoctl(_ChannelID, SET_CONFIG, (void *)&Input, (void *)NULL);
		if (STATUS_NOERROR != ret)
		{
#ifdef __FSSM_DEBUG__
			printErrorDescription("PassThruIoctl() for parameter LOOPBACK failed: ", ret);
#endif
			goto err_close;
		}
		// Baudrate (MANDATORY for 02.02-API only):
		CfgItems[0].Parameter = DATA_RATE;
		CfgItems[0].Value = BaudRate;
		Input.NumOfParams = 1;
		Input.ConfigPtr = CfgItems;
		ret = _j2534->PassThruIoctl(_ChannelID, SET_CONFIG, (void *)&Input, (void *)NULL);
		if (STATUS_NOERROR != ret)
		{
#ifdef __FSSM_DEBUG__
			printErrorDescription("PassThruIoctl() for parameter DATARATE failed: ", ret);
#endif
			if (_j2534->libraryAPIversion() == J2534_API_version::v0202)
				goto err_close;
		}
		if (protocol == AbstractDiagInterface::protocol_SSM2_ISO14230)
		{
			/* ----- SET CONFIGURATION (ISO-14230 specific) ----- */
			// P1_MIN (min. ECU inter-byte time)
			if (_j2534->libraryAPIversion() == J2534_API_version::v0202)	// 04.04-API: not adjustable, always 0ms
			{
				CfgItems[0].Parameter = P1_MIN;	// ISO-9141, ISO-14230 (normal timing paramter-set): min/def=0ms,
				CfgItems[0].Value = 0;	// [ms]
				Input.NumOfParams = 1;
				Input.ConfigPtr = CfgItems;
				ret = _j2534->PassThruIoctl(_ChannelID, SET_CONFIG, (void *)&Input, (void *)NULL);
#ifdef __FSSM_DEBUG__
				if (STATUS_NOERROR != ret)
					printErrorDescription("PassThruIoctl() for P1_MIN: ", ret);
#endif
			}
			// P1_MAX (max. ECU inter-byte time)
			CfgItems[0].Parameter = P1_MAX;	// ISO-9141, ISO-14230 (normal timing paramter-set): def/max=20ms,
			if (_j2534->libraryAPIversion() == J2534_API_version::v0202)
				CfgItems[0].Value = 5;	// [02.02-API: ms]
			else
				CfgItems[0].Value = 10;	// [04.04-API: *0.5ms]
			Input.NumOfParams = 1;
			Input.ConfigPtr = CfgItems;
			ret = _j2534->PassThruIoctl(_ChannelID, SET_CONFIG, (void *)&Input, (void *)NULL);
#ifdef __FSSM_DEBUG__
			if (STATUS_NOERROR != ret)
				printErrorDescription("PassThruIoctl() for P1_MAX: ", ret);
#endif
			// P2_MIN (min. ECU response time [ms] to a tester request or between ECU responses)
			if (_j2534->libraryAPIversion() == J2534_API_version::v0202)	// 04.04-API: not adjustable, always 0ms
			{
				CfgItems[0].Parameter = P2_MIN;	// ISO-9141, ISO-14230 (normal timing paramter-set): min=0ms, def=25ms
				CfgItems[0].Value = 0;	// [ms]
				Input.NumOfParams = 1;
				Input.ConfigPtr = CfgItems;
				ret = _j2534->PassThruIoctl(_ChannelID, SET_CONFIG, (void *)&Input, (void *)NULL);
#ifdef __FSSM_DEBUG__
				if (STATUS_NOERROR != ret)
					printErrorDescription("PassThruIoctl() for P1_MIN: ", ret);
#endif
			}
			// P2_MAX (max. ECU response time [ms] to a tester request or between ECU responses)
			if (_j2534->libraryAPIversion() == J2534_API_version::v0202)	// 04.04-API: not adjustable, value is ignored (all messages up to P3_min are accepted)
			{
				CfgItems[0].Parameter = P2_MAX;	// ISO-9141, ISO-14230 (normal timing paramter set): def=50ms, max=inf
				CfgItems[0].Value = 3000;
				Input.NumOfParams = 1;
				Input.ConfigPtr = CfgItems;
				ret = _j2534->PassThruIoctl(_ChannelID, SET_CONFIG, (void *)&Input, (void *)NULL);
#ifdef __FSSM_DEBUG__
				if (STATUS_NOERROR != ret)
					printErrorDescription("PassThruIoctl() for P2_MAX: ", ret);
#endif
			}
			// P3_MIN (min. time between end of ECU reponse and next tester request)
			CfgItems[0].Parameter = P3_MIN;     // ISO-9141, ISO-14230: min=0ms, def=55ms
			CfgItems[0].Value = 0;	// [02.02-API: ms, 04.04-API: *0.5ms]
			Input.NumOfParams = 1;
			Input.ConfigPtr = CfgItems;
			ret = _j2534->PassThruIoctl(_ChannelID, SET_CONFIG, (void *)&Input, (void *)NULL);
#ifdef __FSSM_DEBUG__
			if (STATUS_NOERROR != ret)
				printErrorDescription("PassThruIoctl() for P3_MIN: ", ret);
#endif
			// P3_MAX (max. time between end of ECU reponse and next tester request)
			if (_j2534->libraryAPIversion() == J2534_API_version::v0202)	// 04.04-API: not adjustable, tester allows sending message at any time after P3_MIN
			{
				CfgItems[0].Parameter = P3_MAX;     // ISO-9141, ISO-14230: def=5000ms, max=inf
				CfgItems[0].Value = 0xffff; // [ms] => 65535ms = max. value
				Input.NumOfParams = 1;
				Input.ConfigPtr = CfgItems;
				ret = _j2534->PassThruIoctl(_ChannelID, SET_CONFIG, (void *)&Input, (void *)NULL);
#ifdef __FSSM_DEBUG__
				if (STATUS_NOERROR != ret)
					printErrorDescription("PassThruIoctl() for P3_MIN: ", ret);
#endif
			}
			// P4_MIN (min. tester inter-byte time)
			CfgItems[0].Parameter = P4_MIN;	// ISO-9141, ISO-14230: min=0ms, def=5ms
			CfgItems[0].Value = 0;	// [02.02-API: ms, 04.04-API: *0.5ms]
			Input.NumOfParams = 1;
			Input.ConfigPtr = CfgItems;
			ret = _j2534->PassThruIoctl(_ChannelID, SET_CONFIG, (void *)&Input, (void *)NULL);
#ifdef __FSSM_DEBUG__
			if (STATUS_NOERROR != ret)
				printErrorDescription("PassThruIoctl() for P4_MIN: ", ret);
#endif
			// P4_MAX (max. tester inter-byte time)
			if (_j2534->libraryAPIversion() == J2534_API_version::v0202)	// 04.04-API: not adjustable, device always uses P4_MIN
			{
				CfgItems[0].Parameter = P4_MAX;	// ISO-9141, ISO-14230: def/max=50ms
				CfgItems[0].Value = 5;	// [ms]
				Input.NumOfParams = 1;
				Input.ConfigPtr = CfgItems;
				ret = _j2534->PassThruIoctl(_ChannelID, SET_CONFIG, (void *)&Input, (void *)NULL);
#ifdef __FSSM_DEBUG__
				if (STATUS_NOERROR != ret)
					printErrorDescription("PassThruIoctl() for P4_MAX: ", ret);
#endif
			}
			// Data bits:
			if (_j2534->libraryAPIversion() == J2534_API_version::v0404)
			{
				CfgItems[0].Parameter = DATA_BITS;
				CfgItems[0].Value = DATA_BITS_8;	// should be default
				Input.NumOfParams = 1;
				Input.ConfigPtr = CfgItems;
				ret = _j2534->PassThruIoctl(_ChannelID, SET_CONFIG, (void *)&Input, (void *)NULL);
#ifdef __FSSM_DEBUG__
				if (STATUS_NOERROR != ret)
					printErrorDescription("PassThruIoctl() for parameter DATA_BITS failed: ", ret);
#endif
			}
			// Parity:
			CfgItems[0].Parameter = PARITY;
			CfgItems[0].Value = NO_PARITY;
			Input.NumOfParams = 1;	// should be default
			Input.ConfigPtr = CfgItems;
			ret = _j2534->PassThruIoctl(_ChannelID, SET_CONFIG, (void *)&Input, (void *)NULL);
#ifdef __FSSM_DEBUG__
			if (STATUS_NOERROR != ret)
				printErrorDescription("PassThruIoctl() for parameter PARITY failed: ", ret);
#endif
			/* APPLY MESSAGE FILTER (Receive all messages) */
			PASSTHRU_MSG MaskMsg;
			PASSTHRU_MSG PatternMsg;
			memset(&MaskMsg, 0, sizeof(MaskMsg));		// .Data=0-array means "do not examine any bits"
			memset(&PatternMsg, 0, sizeof(PatternMsg));	// .Data must be zero, if no Data bits are examined
			MaskMsg.DataSize = 1;
			MaskMsg.ProtocolID = ISO9141;
			PatternMsg.DataSize = 1;
			PatternMsg.ProtocolID = ISO9141;
			if (STATUS_NOERROR != _j2534->PassThruStartMsgFilter(_ChannelID, PASS_FILTER, &MaskMsg, &PatternMsg, NULL, _FilterID))
			{
#ifdef __FSSM_DEBUG__
				printErrorDescription("PassThruStartMsgFilter() for ISO-14230 failed: ", ret);
#endif
				goto err_close;
			}
			_numFilters = 1;
		}
		else if (protocol == AbstractDiagInterface::protocol_SSM2_ISO15765)
		{
			// NOTE: also tweak values of ISO15765_BS, ISO15765_STMIN ?
			/* APPLY MESSAGE FILTERS */
			PASSTHRU_MSG MaskMsg;
			PASSTHRU_MSG PatternMsg;
			PASSTHRU_MSG FlowCtrlMsg;
			memset(&MaskMsg, 0, sizeof(MaskMsg));
			memset(&PatternMsg, 0, sizeof(PatternMsg));
			memset(&FlowCtrlMsg, 0, sizeof(FlowCtrlMsg));
			// ECU:
			MaskMsg.Data[0] = '\xFF';
			MaskMsg.Data[1] = '\xFF';
			MaskMsg.Data[2] = '\xFF';
			MaskMsg.Data[3] = '\xFF';
			MaskMsg.DataSize = 4;
			MaskMsg.ProtocolID = ISO15765;
			MaskMsg.TxFlags = ISO15765_FRAME_PAD;
			PatternMsg.Data[0] =  '\x00';
			PatternMsg.Data[1] =  '\x00';
			PatternMsg.Data[2] =  '\x07';
			PatternMsg.Data[3] =  '\xE8';
			PatternMsg.DataSize = 4;
			PatternMsg.ProtocolID = ISO15765;
			PatternMsg.TxFlags = ISO15765_FRAME_PAD;
			FlowCtrlMsg.Data[0] = '\x00';
			FlowCtrlMsg.Data[1] = '\x00';
			FlowCtrlMsg.Data[2] = '\x07';
			FlowCtrlMsg.Data[3] = '\xE0';
			FlowCtrlMsg.DataSize = 4;
			FlowCtrlMsg.ProtocolID = ISO15765;
			FlowCtrlMsg.TxFlags = ISO15765_FRAME_PAD;
			if (STATUS_NOERROR != _j2534->PassThruStartMsgFilter(_ChannelID, FLOW_CONTROL_FILTER, &MaskMsg, &PatternMsg, &FlowCtrlMsg, _FilterID + _numFilters))
			{
#ifdef __FSSM_DEBUG__
				printErrorDescription("PassThruStartMsgFilter() #1 for ISO-15765 failed: ", ret);
#endif
				goto err_close;
			}
			_numFilters = 1;
			// TCU:
			PatternMsg.Data[3] =  '\xE9';
			FlowCtrlMsg.Data[3] = '\xE1';
			if (STATUS_NOERROR != _j2534->PassThruStartMsgFilter(_ChannelID, FLOW_CONTROL_FILTER, &MaskMsg, &PatternMsg, &FlowCtrlMsg, _FilterID + _numFilters))
			{
#ifdef __FSSM_DEBUG__
				printErrorDescription("PassThruStartMsgFilter() #2 for ISO-15765 failed: ", ret);
#endif
				// Clean up configured message filter
				ret = _j2534->PassThruStopMsgFilter(_ChannelID, _FilterID[0]);
#ifdef __FSSM_DEBUG__
				if (STATUS_NOERROR != ret)
					printErrorDescription("PassThruStopMsgFilter() for ISO-15765 failed: ", ret);
#endif
				_numFilters = 0;
				goto err_close;
			}
			_numFilters = 2;
			// TODO: add support for additional addresses (requires layer/API changes)
		}
		_connected = true;
		setProtocolType( protocol );
		setProtocolBaudrate( BaudRate );
		return true;
	}
	else
		return false;

err_close:
#ifdef __FSSM_DEBUG__
	long ret = _j2534->PassThruDisconnect(_ChannelID);
	if (STATUS_NOERROR != ret)
		printErrorDescription("PassThruDisconnect() failed: ", ret);
#else
	_j2534->PassThruDisconnect(_ChannelID);
#endif
	return false;
}