//-----------------------------------------------------------------------
//
// 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 DynamicApiLoading.Api.Dynamic.RP1210
{
using System;
using System.Runtime.InteropServices;
using System.Text;
///
/// RP1210 Native API methods.
///
public class NativeMethods : IDisposable
{
///
/// This function is called by the client application seeking connection with a DLL.
/// This connection corresponds to the implementation of the API for the VDA being selected.
/// Inside the API DLL, the function allocates and initializes any client data structures,
/// and loads, initializes, or activates any device drivers (virtual or otherwise) to communicate
/// with the hardware and sets all client appliation variables to their defaults (EchoMode,FilterStates, etc.).
/// If the connection is successful, the function shall return a unique identifier,
/// corresponding to the ID of the client application, as assigned by the API DLL.
///
/// This parameter is no longer necessary and is unused (Windows 3.1).
/// The value should be set to NULL (0x00) if an application is not developed for Windows 3.1.
/// The device to which the client application is requesting connection.
/// Pointer to a null-terminated string of the protocol name
/// to be used by the device designated in the previous parameter.
/// (See Protocol Connect String section for protocol strings and variations.)
/// A long integer for the requested size (in bytes) of the client transmit
/// buffer to be allocated by the API for the queuing of messages sought to be ransmitted by the client
/// application.
///
/// Should be passed as 0 if the application does not want to dictate the buffer size and
/// the API DLL default of 8K is acceptable.
/// A long integer for the requested size (in bytes) of the
/// client receive buffer to be allocated by the API for the queuing of messages meant
/// to be received by the client application.
/// Should be passed as 0 if the application does not want to dictate the buffer
/// size and the API DLL default of 8K is acceptable.
/// A flag that is relevant only for J1939.
/// Should be set to zero if the application wants the lower-level components to
/// perform the tasks of fragmenting the message into packets and return complete
/// messages assembled from packets received.
/// Should be set to 1 in the rare case where the application itself will
/// perform the packetizing of message fragments.
/// If the connection is successful, then the function returns a value between 0 and 127,
/// corresponding to the client identifier that the application program is assigned by the API DLL.
/// The application program must save this return value in order to conduct future transactions with the DLL.
/// If the connection is unsuccessful, then an error code is returned that corresponds to a number greater than 127.
/// The typical error codes are described below.
/// More descriptive or proprietary codes may be returned by individual vendor implementations as
/// long as the numerical equivalents of these return values are greater
/// than 192 and are clearly documented by the vendor.
///
/// Mnemonic (Return Codes) Description
/// ERR_CLIENT_ALREADY_CONNECTED A client is already connected to the specified device.
/// ERR_CLIENT_AREA_FULL The maximum number of connections has been reached.
/// ERR_CONNECT_NOT_ALLOWED Only one connection is allowed in the requested Mode.
/// ERR_DEVICE_IN_USE The specified device is already in use and does not have the ability to maintain connections with multiple clients simultaneously.
/// ERR_DLL_NOT_INITIALIZED The API DLL was not initialized.
/// ERR_HARDWARE_NOT_RESPONDING The device is not responding.
/// ERR_INVALID_DEVICE The specified device ID is invalid.
/// ERR_INVALID_PROTOCOL The specified protocol is invalid or unsupported or
/// the extended connect string (fpchProtocol) was incorrect or unsupported.
/// ERR_NOT_ENOUGH_MEMORY The API DLL could not allocate enough memory to create the client.
/// ERR_J1708_BAUD_SET_NONSTANDARD See RP1210_ClientConnect Notes.
/// ERR_J1939_BAUD_SET_NONSTANDARD See RP1210_ClientConnect Notes.
/// ERR_CAN_BAUD_SET_NONSTANDARD See RP1210_ClientConnect Notes.
/// ERR_MULTIPLE_CONNECTIONS_NOT_ALLOWED_NOW See RP1210_ClientConnect Notes.
///
///
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate int TRP1210ClientConnect(IntPtr hwndClient, short nDeviceId, StringBuilder fpchProtocol, int lSendBuffer, int lReceiveBuffer, short nIsAppPacketizingIncomingMsgs);
///
/// RP1210 Client Disconnect
///
/// Client ID (return value from TRP1210ClientConnect in range 0 to 127)
/// Status of operation.
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate short TRP1210ClientDisconnect(short nClientID);
///
/// RP1210 Send Message.
///
/// Client ID (return value from TRP1210ClientConnect in range 0 to 127)
/// Message to send.
/// Size of message.
/// Windows 3.1 legacy parameter.
/// Flag indicate if method shall block on sending.
/// Status of operation.
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate short TRP1210SendMessage(short nClientID, byte[] fpchClientMessage, short nMessageSize, short nNotifyStatusOnTx, short nBlockOnSend);
///
/// RP1210 Read Message.
///
/// Client ID (return value from TRP1210ClientConnect in range 0 to 127)
/// Buffer to receive message to.
/// Size of buffer.
/// Flag to indicate if the method shall block until message is read.
/// 0 at no message, <192 for message size, > 192 for error code.
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate short TRP1210ReadMessage(short nClientID, byte[] fpchAPIMessage, short nBufferSize, short nBlockOnRead);
///
/// RP1210 Send Command.
///
/// RP1210 Command Number
/// Client ID (return value from TRP1210ClientConnect in range 0 to 127)
/// Pointer to buffer.
/// Size of buffer.
/// Status of operation.
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate short TRP1210SendCommand(short nCommandNumber, short nClientID, StringBuilder fpchClientCommand, short nMessageSize);
///
/// RP1210 Read Version.
///
/// DLL Major version.
/// DLL Minor version.
/// API Major version.
/// API Minor version.
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate void TRP1210ReadVersion(StringBuilder fpchDLLMajorVersion, StringBuilder fpchDLLMinorVersion, StringBuilder fpchAPIMajorVersion, StringBuilder fpchAPIMinorVersion);
///
/// RP1210 This function is called by the client application seeking to get detailed information about the vendor API and/or firmware of the device to which it is connected.
///
/// Client ID (return value from TRP1210ClientConnect in range 0 to 127)
/// API version info.
/// Pointer to a buffer that is 17 bytes long.
/// The API may return up to 16 bytes in this field (with NULL terminator) to describe the version of the API interface.
///
/// DLL version info.
/// Pointer to a buffer that is 17 bytes long.
/// The API may return up to 16 bytes in this field (with NULL terminator) to describe the version of the DLL.
/// Firmware version info.
/// Pointer to a buffer that is 17 bytes long.
/// The API may return up to 16 bytes in this field (with NULL terminator) to describe the version of
/// the firmware that is present in the device.
/// A NULL string is also a valid return if the VDA does not have associated firmware.
/// Status of operation.
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate short TRP1210ReadDetailedVersion(short nClientID, StringBuilder fpchAPIVersionInfo, StringBuilder fpchDLLVersionInfo, StringBuilder fpchFWVersionInfo);
///
/// RP1210 Get Hardware Status
///
/// Client ID (return value from TRP1210ClientConnect in range 0 to 127)
/// A pointer to the buffer (allocated by the client application) where hardware status information is to be placed.
/// Always set to 18 bytes.
/// A flag to indicate whether the function must block on requesting the hardware status or not.
/// Status of operation.
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate short TRP1210GetHardwareStatus(short nClientID, StringBuilder fpchClientInfo, short nInfoSize, short nBlockOnRequest);
///
/// Type declaration for dynamically loaded RP1210 API.
///
/// Numerical value for the last error which occurred.
/// A pointer to the buffer (allocated by the client application) of 80 bytes, used to return the error message associated with the error code.
/// Status of operation.
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate short TRP1210GetErrorMsg(short err_code, StringBuilder fpchMessage);
///
/// Gets RP1210_ClientConnect method instance.
///
internal TRP1210ClientConnect RP1210_ClientConnect { get; private set; }
///
/// Gets RP1210_ClientDisconnect method instance.
///
internal TRP1210ClientDisconnect RP1210_ClientDisconnect { get; private set; }
///
/// Gets RP1210_SendMessage method instance.
///
internal TRP1210SendMessage RP1210_SendMessage { get; private set; }
///
/// Gets RP1210_ReadMessage method instance.
///
internal TRP1210ReadMessage RP1210_ReadMessage { get; private set; }
///
/// Gets RP1210_SendCommand method instance.
///
internal TRP1210SendCommand RP1210_SendCommand { get; private set; }
///
/// Gets RP1210_ReadVersion method instance.
///
internal TRP1210ReadVersion RP1210_ReadVersion { get; private set; }
///
/// Gets RP1210_ReadDetailedVersion method instance.
///
internal TRP1210ReadDetailedVersion RP1210_ReadDetailedVersion { get; private set; }
///
/// Gets RP1210_GetHardwareStatus method instance.
///
internal TRP1210GetHardwareStatus RP1210_GetHardwareStatus { get; private set; }
///
/// Gets RP1210_GetErrorMsg method instance.
///
internal TRP1210GetErrorMsg RP1210_GetErrorMsg { get; private set; }
///
/// DLL instance handle.
///
private SafeLibraryHandle safeLibraryHandle;
///
/// Name of DLL.
///
private string library;
///
/// Initializes a new instance of the class.
///
/// Name of DLL.
public NativeMethods(string library)
{
this.library = library;
this.safeLibraryHandle = SafeLibraryHandle.LoadLibraryW(library);
if (this.safeLibraryHandle.IsInvalid)
{
throw new DynamicLoaderException("LoadLibrary('" + library + "') failed!");
}
this.RP1210_ClientConnect = (TRP1210ClientConnect)Marshal.GetDelegateForFunctionPointer(this.getProcedureAddress("RP1210_ClientConnect"), typeof(TRP1210ClientConnect));
this.RP1210_ClientDisconnect = (TRP1210ClientDisconnect)Marshal.GetDelegateForFunctionPointer(this.getProcedureAddress("RP1210_ClientDisconnect"), typeof(TRP1210ClientDisconnect));
this.RP1210_SendMessage = (TRP1210SendMessage)Marshal.GetDelegateForFunctionPointer(this.getProcedureAddress("RP1210SendMessage"), typeof(TRP1210SendMessage));
this.RP1210_ReadMessage = (TRP1210ReadMessage)Marshal.GetDelegateForFunctionPointer(this.getProcedureAddress("RP1210_ReadMessage"), typeof(TRP1210ReadMessage));
this.RP1210_SendCommand = (TRP1210SendCommand)Marshal.GetDelegateForFunctionPointer(this.getProcedureAddress("RP1210_SendCommand"), typeof(TRP1210SendCommand));
this.RP1210_ReadVersion = (TRP1210ReadVersion)Marshal.GetDelegateForFunctionPointer(this.getProcedureAddress("RP1210_ReadVersion"), typeof(TRP1210ReadVersion));
this.RP1210_ReadDetailedVersion = (TRP1210ReadDetailedVersion)Marshal.GetDelegateForFunctionPointer(this.getProcedureAddress("RP1210_ReadDetailedVersion"), typeof(TRP1210ReadDetailedVersion));
this.RP1210_GetHardwareStatus = (TRP1210GetHardwareStatus)Marshal.GetDelegateForFunctionPointer(this.getProcedureAddress("RP1210_GetHardwareStatus"), typeof(TRP1210GetHardwareStatus));
this.RP1210_GetErrorMsg = (TRP1210GetErrorMsg)Marshal.GetDelegateForFunctionPointer(this.getProcedureAddress("RP1210_GetErrorMsg"), typeof(TRP1210GetErrorMsg));
}
///
/// Dispose instance.
///
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Dispose instance.
///
/// 'true' if call to Dispose() was made, 'false' if the class was finalized.
protected virtual void Dispose(bool disposing)
{
this.safeLibraryHandle.Dispose();
}
///
/// Finalizes an instance of the class.
///
~NativeMethods()
{
this.Dispose(false);
}
///
/// Gets the address of the given procedure, throws Exception when failing.
///
/// Name of procedure to locate.
/// Pointer to function
/// Thrown when unable to get address to function.
private IntPtr getProcedureAddress(string functionName)
{
IntPtr pAddress = this.safeLibraryHandle.GetProcAddress(functionName);
if (pAddress == IntPtr.Zero)
{
throw new DynamicLoaderException("GetProcAddress('" + functionName + "'), library '" + this.library + "' failed!");
}
return pAddress;
}
}
}