//----------------------------------------------------------------------- // // Copyright © 2012 Nils Hammar. All rights reserved. // //----------------------------------------------------------------------- /* * Software to access vehicle information via the OBD-II connector. * * Copyright © 2012 Nils Hammar * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Alternative licensing is possible, see the licensing document. * * The above text may not be removed or modified. */ namespace DeviceApi.Serial { using System.Collections.Generic; using System.Threading; using global::SharedObjects.Api; using global::SharedObjects.Protocol; /// /// Class for when using Serial interface with AT commands. /// /// Notice that much of this class will not be called and that the communication /// with the device is done with the protocol handler. /// /// public abstract class SerialAtPassThru : IPassThru { /// /// Supported connection flags by the device. /// private static CanFlags[] connFlags = new CanFlags[] { }; /// /// Supported filter flags by the device. /// private static CanFlags[] filterFlags = new CanFlags[] { }; /// /// List of supported protocols by device. /// private Protocols[] protos = null; /// /// Gets or sets array of supported protocols by device. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Reviewed, intentional.")] public Protocols[] protocols { get { return this.protos; } protected set { this.protos = value; } } /// /// To return an unique device ID for each opening of the device. /// private int DeviceIdCounter = 1; /// /// To return an unique connection ID for each opening of the device. /// private int ChannelIdCounter = 1; /// /// To return an unique filter ID for each opening of the device. /// private int FilterIdCounter = 1; /// /// Dictionary of open devices. /// private Dictionary> openDevices = new Dictionary>(); /// /// Dictionary of open channels. /// private Dictionary openChannels = new Dictionary(); /// /// Dictionary of active filters. /// private Dictionary activeFilters = new Dictionary(); /// /// Default serial port parameters for the protocol. /// private SerialPortParameters serialPortPars = null; /// /// Gets or sets the default parameters for the protocol. /// public SerialPortParameters serialPortParameters { get { return new SerialPortParameters(this.serialPortPars); } protected set { this.serialPortPars = value; } } /// /// Initializes a new instance of the class. /// protected SerialAtPassThru() { } /// /// Get list of supported protocols. /// /// Array of supported protocols by the device. public Protocols[] getProtocols() { return this.protocols; } /// /// Indicate if the interface is a serial device. /// /// Notice that this also applies to Serial on USB devices. /// /// /// 'true' if serial device. public bool isSerial() { return true; } /// /// Gets the name of the device. /// public abstract string name { get; } /// /// Gets the name of the device. /// public abstract string code { get; } /// /// Get flag indicating if device has disconnect bug. /// /// Flag indicating disconnect bug. public bool disconnectBug() { return false; } /// /// Get the available connection flags for the device. /// /// Array of flags. public CanFlags[] getConnFlags() { return connFlags; } /// /// Get the available message flags for the device. /// /// Array of flags. public CanFlags[] getMessageFlags() { return filterFlags; } /// /// Open the device. /// /// Device Name (Shall be 'null') /// Assigned Device ID (out value) /// Status of operation, 0=Success. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Provided data shall never be 'null'.")] public unsafe PassThruConstants.resultCode PassThruOpen(void* pName, int* pDeviceID) { this.openDevices.Add(this.DeviceIdCounter, new List()); *pDeviceID = this.DeviceIdCounter++; return PassThruConstants.resultCode.ERR_SUCCESS; } /// /// Close the device. /// /// ID of device to close. /// Status of operation, 0=Success. public PassThruConstants.resultCode PassThruClose(int DeviceID) { if (this.openDevices.ContainsKey(DeviceID)) { List deviceChannels = this.openDevices[DeviceID]; foreach (SimulatedChannel channel in deviceChannels) { this.PassThruDisconnect(channel.channelId); } this.openDevices.Remove(DeviceID); return PassThruConstants.resultCode.ERR_SUCCESS; } return PassThruConstants.resultCode.ERR_INVALID_DEVICE_ID; } /// /// Establish a connection to the device. /// /// ID of device. /// ID of protocol. /// Connection flags. /// Baudrate to connect with. /// Assigned channel ID (out value) /// Status of operation, 0=Success. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "4", Justification = "Provided data shall never be 'null'.")] public unsafe PassThruConstants.resultCode PassThruConnect(int DeviceID, int ProtocolID, uint Flags, uint Baudrate, int* pChannelID) { if (this.openDevices.ContainsKey(DeviceID)) { Protocols protocol = Protocols.getProtocolById(ProtocolID); foreach (SimulatedChannel channel in this.openChannels.Values) { Protocols proto1 = Protocols.getProtocolById(channel.protocol.id); if (proto1.families == protocol.families) { return PassThruConstants.resultCode.ERR_CHANNEL_IN_USE; } } List deviceChannels = this.openDevices[DeviceID]; SimulatedChannel simulatedConnection = new SimulatedChannel(DeviceID, this.ChannelIdCounter, protocol); deviceChannels.Add(simulatedConnection); *pChannelID = this.ChannelIdCounter; this.openChannels.Add(this.ChannelIdCounter++, simulatedConnection); return PassThruConstants.resultCode.ERR_SUCCESS; } return PassThruConstants.resultCode.ERR_DEVICE_NOT_CONNECTED; } /// /// Disconnect from device. /// /// Channel to disconnect. /// Status of operation, 0=Success. public PassThruConstants.resultCode PassThruDisconnect(int ChannelID) { if (this.openChannels.ContainsKey(ChannelID)) { SimulatedChannel channel = this.openChannels[ChannelID]; List deviceChannels = this.openDevices[channel.deviceId]; if (deviceChannels.Contains(channel)) { deviceChannels.Remove(channel); } this.openChannels.Remove(ChannelID); return PassThruConstants.resultCode.ERR_SUCCESS; } return PassThruConstants.resultCode.ERR_INVALID_CHANNEL_ID; } /// /// Read messages from device. /// /// Channel to read from. /// Pointer to message struct. /// Number of messages to read, set to actual number of messages read when returned. /// Timeout waiting for messages. /// Status of operation, 0=Success. public unsafe PassThruConstants.resultCode PassThruReadMsgs(int ChannelID, PASSTHRU_MSG* pMsg, int* pNumMsgs, int Timeout) { if (this.openChannels.ContainsKey(ChannelID)) { Thread.Sleep(Timeout); return PassThruConstants.resultCode.ERR_SUCCESS; } return PassThruConstants.resultCode.ERR_INVALID_CHANNEL_ID; } /// /// Write messages to device. /// /// Channel to write to. /// Pointer to message struct. /// Number of messages to send. /// Timeout sending message. /// Status of operation, 0=Success. public unsafe PassThruConstants.resultCode PassThruWriteMsgs(int ChannelID, PASSTHRU_MSG* pMsg, int* pNumMsgs, int Timeout) { if (this.openChannels.ContainsKey(ChannelID)) { return PassThruConstants.resultCode.ERR_SUCCESS; } return PassThruConstants.resultCode.ERR_INVALID_CHANNEL_ID; } /// /// Configure periodic message to send. /// /// Channel to send on. /// Message to send. /// ID of message being sent. (out data) /// Interval between each transmission. /// Status of operation, 0=Success. public unsafe PassThruConstants.resultCode PassThruStartPeriodicMsg(int ChannelID, PASSTHRU_MSG* pMsg, int* pMsgID, int TimeInterval) { if (this.openChannels.ContainsKey(ChannelID)) { return PassThruConstants.resultCode.ERR_SUCCESS; } return PassThruConstants.resultCode.ERR_INVALID_CHANNEL_ID; } /// /// Stop sending periodic message. /// /// Channel to stop sending on. /// ID of message to stop sending. /// Status of operation, 0=Success. public PassThruConstants.resultCode PassThruStopPeriodicMsg(int ChannelID, int MsgID) { if (this.openChannels.ContainsKey(ChannelID)) { return PassThruConstants.resultCode.ERR_SUCCESS; } return PassThruConstants.resultCode.ERR_INVALID_CHANNEL_ID; } /// /// Add a message filter. /// /// Channel to add filter to. /// Type of filter. /// Mask message. /// Pattern message. /// Flow control message. /// ID of filter added. (out value) /// Result status, 0=success. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "5", Justification = "Provided data shall never be 'null'.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "2", Justification = "Provided data shall never be 'null'.")] public unsafe PassThruConstants.resultCode PassThruStartMsgFilter( int ChannelID, int FilterType, PASSTHRU_MSG* pMaskMsg, PASSTHRU_MSG* pPatternMsg, PASSTHRU_MSG* pFlowControlMsg, int* pMsgID) { if (this.openChannels.ContainsKey(ChannelID)) { this.activeFilters.Add( this.FilterIdCounter, new FilterItem( this.FilterIdCounter, (uint)FilterType, pMaskMsg->DataSize, parseMask(pMaskMsg), parseMask(pPatternMsg), parseMask(pFlowControlMsg), (uint)pMaskMsg->TxFlags, pMaskMsg->ProtocolID)); *pMsgID = this.FilterIdCounter; this.FilterIdCounter++; return PassThruConstants.resultCode.ERR_SUCCESS; } return PassThruConstants.resultCode.ERR_INVALID_CHANNEL_ID; } /// /// Remove message filter. /// /// Channel to remove filter from. /// ID of filter to remove. /// Result status, 0=success. public PassThruConstants.resultCode PassThruStopMsgFilter(int ChannelID, int MsgID) { if (this.openChannels.ContainsKey(ChannelID)) { if (this.activeFilters.ContainsKey(MsgID)) { return PassThruConstants.resultCode.ERR_SUCCESS; } else { return PassThruConstants.resultCode.ERR_INVALID_FILTER_ID; } } return PassThruConstants.resultCode.ERR_INVALID_CHANNEL_ID; } /// /// Set the programming voltage for the device. /// /// ID of device to set voltage on. /// Pin to set voltage on. /// Voltage to set. /// Result status, 0=success. public PassThruConstants.resultCode PassThruSetProgrammingVoltage(int DeviceID, int Pin, int Voltage) { if (this.openDevices.ContainsKey(DeviceID)) { return PassThruConstants.resultCode.ERR_SUCCESS; } return PassThruConstants.resultCode.ERR_INVALID_DEVICE_ID; } /// /// Read version of API. /// /// ID of device to read API version from. /// Firmware Version (out value) /// DLL Version (out value) /// API Version (out value) /// Result status, 0=success. public unsafe PassThruConstants.resultCode PassThruReadVersion(int DeviceID, byte* pFirmwareVersion, byte* pDllVersion, byte* pApiVersion) { if (this.openDevices.ContainsKey(DeviceID)) { return PassThruConstants.resultCode.ERR_SUCCESS; } return PassThruConstants.resultCode.ERR_INVALID_DEVICE_ID; } /// /// Get the last error from the API. /// /// Error text. /// Result status, 0=success. public unsafe PassThruConstants.resultCode PassThruGetLastError(sbyte* pErrorDescription) { return PassThruConstants.resultCode.ERR_SUCCESS; } /// /// Perform IOCTL operation on channel. /// /// Channel to perform operation on. /// IOCTL operation. /// Input data to operation. /// Result data from operation. /// Result status, 0=success. public unsafe PassThruConstants.resultCode PassThruIoctl( int ChannelID, int IoctlID, void* pInput, void* pOutput) { if (this.openChannels.ContainsKey(ChannelID)) { return PassThruConstants.resultCode.ERR_SUCCESS; } return PassThruConstants.resultCode.ERR_INVALID_CHANNEL_ID; } /// /// Parse the msg mask. /// /// Pointer to struct. /// Parsed value private static unsafe uint parseMask(PASSTHRU_MSG* pMsg) { return parseMask(new PassThruMsg(pMsg)); } /// /// Parse the msg mask. /// /// Message instance. /// Parsed value private static uint parseMask(PassThruMsg msg) { uint mask = (uint)(msg.Data[0] << 24 | msg.Data[1] << 16 | msg.Data[2] << 8 | msg.Data[3]); return mask; } /// /// Item for a simulated channel. /// private class SimulatedChannel { /// /// Gets ID of device. /// public int deviceId { get; private set; } /// /// Gets ID of channel. /// public int channelId { get; private set; } /// /// Gets protocol instance. /// public Protocols protocol { get; private set; } /// /// Initializes a new instance of the class. /// /// ID of device. /// ID of channel. /// Protocol instance. public SimulatedChannel(int deviceId, int channelId, Protocols protocol) { this.deviceId = deviceId; this.channelId = channelId; this.protocol = protocol; } } /// /// Item for a filter. /// private class FilterItem { /// /// Gets ID of filter. /// public int msgId { get; private set; } /// /// Gets type of filter. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Reviewed.")] public uint filterType { get; private set; } /// /// Gets datasize. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Reviewed.")] public int datasize { get; private set; } /// /// Gets filter mask. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Reviewed.")] public uint mask { get; private set; } /// /// Gets filter pattern. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Reviewed.")] public uint pattern { get; private set; } /// /// Gets filter flow. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Reviewed.")] public uint flow { get; private set; } /// /// Gets filter TX flags. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Reviewed.")] public uint txFlags { get; private set; } /// /// Gets filter protocol ID. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Reviewed.")] public int protocol { get; private set; } /// /// Initializes a new instance of the class. /// /// Filter ID /// Type of filter /// Data Size /// Filter Mask /// Filter Pattern /// Filter Flow /// Filter TX flags /// Filter protocol ID public FilterItem( int msgId, uint filterType, int datasize, uint mask, uint pattern, uint flow, uint txFlags, int protocol) { this.msgId = msgId; this.filterType = filterType; this.datasize = datasize; this.protocol = protocol; this.mask = mask; this.pattern = pattern; this.flow = flow; this.txFlags = txFlags; } /// /// Get string representation of filter. /// /// String representation public override string ToString() { #if TRACE return "msgId=" + this.msgId + ", filterType=" + this.filterType + ", datasize=" + this.datasize + ", protocol=0x" + this.protocol.ToString("x2") + ", mask=0x" + this.mask.ToString("x4") + ", pattern=0x" + this.pattern.ToString("x4") + ", flow=0x" + this.flow.ToString("x4") + ", txFlags=0x" + this.txFlags.ToString("x4") + "\r\n"; #else return "msgId=" + this.msgId + "\r\n"; #endif } } } }