//-----------------------------------------------------------------------
//
// 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
}
}
}
}