telldus/bindings/dotnet/TelldusNETWrapper/TelldusNETWrapper.cs

860 lines
33 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace TelldusWrapper
{
public sealed class TelldusNETWrapper //don't allow inheritance
{
int lastEventID = 0;
Dictionary<int, Object> callbackFunctionReferenceList = new Dictionary<int, Object>(); //this prevents errors in "unknown module" due to callback functions being garbage collected since there are no reference to them
//TODO
List<Object> lista = new List<object>();
//Device methods
public const int TELLSTICK_TURNON = 1;
public const int TELLSTICK_TURNOFF = 2;
public const int TELLSTICK_BELL = 4;
public const int TELLSTICK_TOGGLE = 8;
public const int TELLSTICK_DIM = 16;
public const int TELLSTICK_LEARN = 32;
public const int TELLSTICK_EXECUTE = 64;
public const int TELLSTICK_UP = 128;
public const int TELLSTICK_DOWN = 256;
public const int TELLSTICK_STOP = 512;
//Error codes
public const int TELLSTICK_SUCCESS = 0;
public const int TELLSTICK_ERROR_NOT_FOUND = -1;
public const int TELLSTICK_ERROR_PERMISSION_DENIED = -2;
public const int TELLSTICK_ERROR_DEVICE_NOT_FOUND = -3;
public const int TELLSTICK_ERROR_METHOD_NOT_SUPPORTED = -4;
public const int TELLSTICK_ERROR_COMMUNICATION = -5;
public const int TELLSTICK_ERROR_CONNECTING_SERVICE = -6;
public const int TELLSTICK_ERROR_UNKNOWN_RESPONSE = -7;
public const int TELLSTICK_ERROR_UNKNOWN = -99;
//Device typedef
public const int TELLSTICK_TYPE_DEVICE = 1;
public const int TELLSTICK_TYPE_GROUP = 2;
public const int TELLSTICK_TYPE_SCENE = 3;
//Device changes
public const int TELLSTICK_DEVICE_ADDED = 1;
public const int TELLSTICK_DEVICE_CHANGED = 2;
public const int TELLSTICK_DEVICE_REMOVED = 3;
public const int TELLSTICK_DEVICE_STATE_CHANGED = 4;
//Change types
public const int TELLSTICK_CHANGE_NAME = 1;
public const int TELLSTICK_CHANGE_PROTOCOL = 2;
public const int TELLSTICK_CHANGE_MODEL = 3;
//variables for event callback (e.g. turnon, turnoff)
public delegate int EventCallbackFunction(int deviceId, int method, string data, int callbackId, Object obj);
Dictionary<int, EventCallbackFunction> eventList = new Dictionary<int, EventCallbackFunction>();
GCHandle eventContextHandle;
int registeredEventFunctionId = -1;
//variables for device event callback (e.g. change of name/protocol)
public delegate int DeviceChangeEventCallbackFunction(int deviceId, int changeEvent, int changeType, int callbackId, Object obj);
Dictionary<int, DeviceChangeEventCallbackFunction> deviceChangeEventList = new Dictionary<int, DeviceChangeEventCallbackFunction>();
GCHandle deviceChangeEventContextHandle;
int registeredDeviceChangeEventFunctionId = -1;
//variables for raw controller listening callback (e.g. Tellstick Duo receives data)
public delegate int RawListeningCallbackFunction(string data, int controllerId, int callbackId, Object obj);
Dictionary<int, RawListeningCallbackFunction> rawListenerList = new Dictionary<int, RawListeningCallbackFunction>();
GCHandle rawListenerContextHandle;
int registeredRawListenerFunctionId = -1;
public TelldusNETWrapper()
{
}
~TelldusNETWrapper()
{
//clean up
if (registeredEventFunctionId != -1)
{
UnmanagedImport.tdUnregisterCallback(registeredEventFunctionId);
}
if (registeredDeviceChangeEventFunctionId != -1)
{
UnmanagedImport.tdUnregisterCallback(registeredDeviceChangeEventFunctionId);
}
if (registeredRawListenerFunctionId != -1)
{
UnmanagedImport.tdUnregisterCallback(registeredRawListenerFunctionId);
}
UnmanagedImport.tdClose(); //Close the library and clean up the cache it uses.
if (eventContextHandle.IsAllocated)
{
eventContextHandle.Free();
}
if (deviceChangeEventContextHandle.IsAllocated)
{
deviceChangeEventContextHandle.Free();
}
if (rawListenerContextHandle.IsAllocated)
{
rawListenerContextHandle.Free();
}
}
/// <summary>
/// Imported functions from TelldusCore.dll
/// </summary>
private sealed class UnmanagedImport
{
private UnmanagedImport() { } //cannot instantiate this class
#region Unmanaged Code
[DllImport("TelldusCore.dll")]
public static extern int tdGetNumberOfDevices();
[DllImport("TelldusCore.dll")]
public static extern int tdGetDeviceId(int value);
[DllImport("TelldusCore.dll")]
public static unsafe extern char* tdGetName(int deviceId);
[DllImport("TelldusCore.dll")]
public static unsafe extern char* tdGetProtocol(int deviceId);
[DllImport("TelldusCore.dll")]
public static unsafe extern char* tdGetModel(int deviceId);
[DllImport("TelldusCore.dll")]
public static unsafe extern char* tdGetDeviceParameter(int deviceId, char* name, char* defaultValue);
[DllImport("TelldusCore.dll")]
public static unsafe extern bool tdSetName(int deviceId, char* name);
[DllImport("TelldusCore.dll")]
public static unsafe extern bool tdSetProtocol(int deviceId, char* protocol);
[DllImport("TelldusCore.dll")]
public static unsafe extern bool tdSetModel(int deviceId, char* model);
[DllImport("TelldusCore.dll")]
public static unsafe extern bool tdSetDeviceParameter(int deviceId, char* name, char* value);
[DllImport("TelldusCore.dll")]
public static unsafe extern int tdAddDevice();
[DllImport("TelldusCore.dll")]
public static unsafe extern bool tdRemoveDevice(int deviceId);
[DllImport("TelldusCore.dll")]
public static unsafe extern int tdMethods(int deviceId, int methodsSupported);
[DllImport("TelldusCore.dll")]
public static extern int tdTurnOn(int deviceId);
[DllImport("TelldusCore.dll")]
public static extern int tdTurnOff(int deviceId);
[DllImport("TelldusCore.dll")]
public static extern int tdBell(int deviceId);
[DllImport("TelldusCore.dll")]
public static extern int tdDim(int deviceId, char level);
[DllImport("TelldusCore.dll")]
public static extern int tdExecute(int deviceId);
[DllImport("TelldusCore.dll")]
public static extern int tdUp(int deviceId);
[DllImport("TelldusCore.dll")]
public static extern int tdDown(int deviceId);
[DllImport("TelldusCore.dll")]
public static extern int tdStop(int deviceId);
[DllImport("TelldusCore.dll")]
public static unsafe extern char* tdGetErrorString(int errorNo);
[DllImport("TelldusCore.dll")]
public static extern void tdClose();
[DllImport("TelldusCore.dll")]
public static extern void tdInit();
[DllImport("TelldusCore.dll")]
public static unsafe extern int tdRegisterDeviceEvent(Delegate eventFunction, void* context);
[DllImport("TelldusCore.dll")]
public static extern int tdLastSentCommand(int deviceId, int methods);
[DllImport("TelldusCore.dll")]
public static extern int tdGetDeviceType(int deviceId);
[DllImport("TelldusCore.dll")]
public static unsafe extern int tdSendRawCommand(char* command, int reserved);
[DllImport("TelldusCore.dll")]
public static unsafe extern int tdRegisterRawDeviceEvent(Delegate rawListeningFunction, void* context);
[DllImport("TelldusCore.dll")]
public static extern int tdLearn(int deviceId);
[DllImport("TelldusCore.dll")]
public static unsafe extern char* tdLastSentValue(int deviceId);
[DllImport("TelldusCore.dll")]
public static unsafe extern void tdReleaseString(char* value);
[DllImport("TelldusCore.dll")]
public static unsafe extern int tdUnregisterCallback(int eventId);
[DllImport("TelldusCore.dll")]
public static unsafe extern int tdRegisterDeviceChangeEvent(Delegate deviceEventFunction, void* context);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public unsafe delegate void EventFunctionDelegate(); //int deviceId, int method, int callbackId, void* context [MarshalAs(UnmanagedType.LPStr)]string data,
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public unsafe delegate void DeviceChangeEventFunctionDelegate(int deviceId, int changeEvent, int changeType, int callbackId, void* context);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public unsafe delegate void RawListeningDelegate(char* data, int controllerId, int callbackId, void* context);
#endregion
}
#region Public Methods
/// <summary>
/// Add a new device to the global database of devices. This function must be called first before
/// any call to tdSetName(), tdSetProtocol() and similar functions.
/// </summary>
/// <returns> The device id for the newly created device. If the creation fails it returnes a
/// negative value.</returns>
public static int tdAddDevice()
{
return UnmanagedImport.tdAddDevice();
}
/// <summary>
/// Sends bell command to devices supporting this.
/// Make sure the device supports this by calling tdMethods() before any calls to this function.
/// </summary>
/// <param name="deviceId">Id of device to sound the bell on</param>
/// <returns>Success or error code</returns>
public static int tdBell(int deviceId)
{
return UnmanagedImport.tdBell(deviceId);
}
/// <summary>
/// Close the library and clean up the cache it uses.
/// This should be called when the library is not supposed to be used anymore.
/// Do not use when this has been instantiated, will be closed in destructor then, only on static methods.
/// </summary>
public static void tdClose()
{
UnmanagedImport.tdClose();
}
/// <summary>
/// Dims a device.
/// Make sure the device supports this by calling tdMethods() before any calls to this function.
/// </summary>
/// <param name="deviceId">The device id to dim</param>
/// <param name="level">The level the device should dim to. This value should be 0-255</param>
/// <returns>Success or error code</returns>
public static int tdDim(int deviceId, char level)
{
return UnmanagedImport.tdDim(deviceId, level);
}
/// <summary>
/// Send "down" command to device.
/// Make sure the device supports this by calling tdMethods() before any calls to this function.
/// </summary>
/// <param name="deviceId">The device id to send the command to</param>
/// <returns>Success or error code</returns>
public static int tdDown(int deviceId)
{
return UnmanagedImport.tdDown(deviceId);
}
/// <summary>
/// Execute a scene action.
/// Make sure the device supports this by calling tdMethods() before any calls to this function.
/// </summary>
/// <param name="deviceId">Id of device to perform the execute action on</param>
/// <returns>Success or error code</returns>
public static int tdExecute(int deviceId)
{
return UnmanagedImport.tdExecute(deviceId);
}
/// <summary>
/// This function returns the unique id of a device with a specific index.
/// To get all the id numbers you should loop over all the devices, use tdGetNumberOfDevices() to get the number of devices
/// </summary>
/// <param name="order">Device index</param>
/// <returns>Id of device at that position</returns>
public static int tdGetDeviceId(int order)
{
return UnmanagedImport.tdGetDeviceId(order);
}
/// <summary>
/// Get a protocol specific device parameter
/// </summary>
/// <param name="deviceId">The id of the device to query</param>
/// <param name="name">The name of the parameter to query</param>
/// <param name="defaultValue">A defaultValue to return if the current parameter hasn't previously been set</param>
/// <returns>Any protocol specific parameter specified by "name"</returns>
public static unsafe string tdGetDeviceParameter(int deviceId, string name, string defaultValue)
{
return getString(UnmanagedImport.tdGetDeviceParameter(deviceId, stringToChar(name), stringToChar(defaultValue)));
}
/// <summary>
/// Returns which type the device is
/// </summary>
/// <param name="deviceId">Id of the device</param>
/// <returns>TELLSTICK_TYPE_DEVICE or TELLSTICK_TYPE_GROUP</returns>
public static int tdGetDeviceType(int deviceId)
{
return UnmanagedImport.tdGetDeviceType(deviceId);
}
/// <summary>
/// Get a human readable string from an error code returned from a function in telldus-core
/// </summary>
/// <param name="errorNo">The error code to translate</param>
/// <returns>A string ready to show to the user.
/// TELLSTICK_SUCCESS
/// TELLSTICK_ERROR_NOT_FOUND
/// TELLSTICK_ERROR_PERMISSION_DENIED
/// TELLSTICK_ERROR_DEVICE_NOT_FOUND
/// TELLSTICK_ERROR_METHOD_NOT_SUPPORTED
/// TELLSTICK_ERROR_COMMUNICATION
/// TELLSTICK_ERROR_CONNECTING_SERVICE
/// TELLSTICK_ERROR_UNKNOWN_RESPONSE
/// TELLSTICK_ERROR_UNKNOWN
/// </returns>
public static unsafe string tdGetErrorString(int errorNo)
{
return getString(UnmanagedImport.tdGetErrorString(errorNo));
}
/// <summary>
/// Query a device for its name
/// </summary>
/// <param name="deviceId">Id of device to query</param>
/// <returns>The name of the device or an empty string if the device is not found</returns>
public static unsafe string tdGetName(int deviceId)
{
return getString(UnmanagedImport.tdGetName(deviceId));
}
/// <summary>
/// Query a device for which methods it supports. By supplying the methods you support
/// the library could remap the methods a device support for better fit the application.
/// </summary>
/// <param name="deviceId">Id of device to query</param>
/// <param name="methodsSupported">Methods that the client application supports</param>
/// <returns>Supported (both by client application and by device) method-flags OR'ed into an integer
/// TELLSTICK_TURNON
/// TELLSTICK_TURNOFF
/// TELLSTICK_BELL
/// TELLSTICK_TOGGLE
/// TELLSTICK_DIM
/// TELLSTICK_EXECUTE
/// TELLSTICK_UP
/// TELLSTICK_DOWN
/// TELLSTICK_EXECUTE
/// TELLSTICK_LEARN
/// </returns>
public static int tdMethods(int deviceId, int methodsSupported)
{
return UnmanagedImport.tdMethods(deviceId, methodsSupported);
}
/// <summary>
/// Query a device for its model
/// </summary>
/// <param name="deviceId">Id of device to query</param>
/// <returns>The model for a device. Not all protocols use this.</returns>
public static unsafe string tdGetModel(int deviceId)
{
return getString(UnmanagedImport.tdGetModel(deviceId));
}
/// <summary>
/// This function returns the number of devices configured
/// </summary>
/// <returns>The total number of devices configured</returns>
public static int tdGetNumberOfDevices()
{
return UnmanagedImport.tdGetNumberOfDevices();
}
/// <summary>
/// Query a device for its protocol
/// </summary>
/// <param name="deviceId">Id of device to query</param>
/// <returns>The protocol for a device.</returns>
public static unsafe string tdGetProtocol(int deviceId)
{
return getString(UnmanagedImport.tdGetProtocol(deviceId));
}
/// <summary>
/// Returns the last sent command to a specific device
/// </summary>
/// <param name="deviceId">Id of device to query</param>
/// <param name="methods">The methods supported by the client. See tdMethods() for more information.</param>
/// <returns>The last sent command as integer, for example TELLSTICK_TURNON or TELLSTICK_TURNOFF</returns>
public static int tdLastSentCommand(int deviceId, int methods)
{
return UnmanagedImport.tdLastSentCommand(deviceId, methods);
}
/// <summary>
/// If the last sent command it TELLSTICK_DIM this returns the dimmed value
/// </summary>
/// <param name="deviceId">Id of device to query</param>
/// <returns>The the value as a human readable string, for example "128" for 50%</returns>
public static unsafe string tdLastSentValue(int deviceId)
{
return getString(UnmanagedImport.tdLastSentValue(deviceId));
}
/// <summary>
/// Sends a special learn command to some devices that need a special learn-command to be used from TellStick
/// Make sure the device supports this by calling tdMethods() before any calls to this function.
/// </summary>
/// <param name="deviceId">Id of device to learn</param>
/// <returns>Success or error code</returns>
public static int tdLearn(int deviceId)
{
return UnmanagedImport.tdLearn(deviceId);
}
/// <summary>
/// Register a callback event function to be called when a device event (e.g. turn on, turn off) occurs
/// </summary>
/// <param name="eventFunc">Callback function to be called</param>
/// <param name="obj">Context object that will be echoed back when function is called. Only the object when the first function is registered will be used. Set to null if not used.</param>
/// <returns>Callback event id</returns>
public unsafe int tdRegisterDeviceEvent(EventCallbackFunction eventFunc, Object obj)
{
int returnValue = 0;
if (eventList.Count == 0)
{
//first added, register with dll too
//only the context object of the first event will be registered
UnmanagedImport.EventFunctionDelegate eventFunctionDelegate = new UnmanagedImport.EventFunctionDelegate(eventFunction);
if (obj != null)
{
eventContextHandle = GCHandle.Alloc(obj);
registeredEventFunctionId = UnmanagedImport.tdRegisterDeviceEvent(eventFunctionDelegate, (void*)GCHandle.ToIntPtr(eventContextHandle)); //context here or above?
}
else
{
registeredEventFunctionId = UnmanagedImport.tdRegisterDeviceEvent(eventFunctionDelegate, (void*)null); //context here or above?
}
GC.Collect();
callbackFunctionReferenceList.Add(registeredEventFunctionId, eventFunctionDelegate);
}
++lastEventID;
returnValue = lastEventID;
eventList.Add(returnValue, eventFunc);
return returnValue;
}
/// <summary>
/// Register a callback device change event function to be called when a device change event (e.g. change of name, device added) occurs
/// </summary>
/// <param name="deviceEventFunc">Callback function to be called</param>
/// <param name="obj">Context object that will be echoed back when function is called. Only the object when the first function is registered will be used. Set to null if not used.</param>
/// <returns>Callback event id</returns>
public unsafe int tdRegisterDeviceChangeEvent(DeviceChangeEventCallbackFunction deviceEventFunc, Object obj)
{
int returnValue = 0;
if (deviceChangeEventList.Count == 0)
{
//first added, register with dll too
//only the context object of the first event will be registered
UnmanagedImport.DeviceChangeEventFunctionDelegate deviceChangeEventFunctionDelegate = new UnmanagedImport.DeviceChangeEventFunctionDelegate(deviceEventFunction);
if (obj != null)
{
deviceChangeEventContextHandle = GCHandle.Alloc(obj);
registeredDeviceChangeEventFunctionId = UnmanagedImport.tdRegisterDeviceChangeEvent(deviceChangeEventFunctionDelegate, (void*)GCHandle.ToIntPtr(deviceChangeEventContextHandle));
}
else
{
registeredDeviceChangeEventFunctionId = UnmanagedImport.tdRegisterDeviceChangeEvent(deviceChangeEventFunctionDelegate, (void*)null);
}
GC.Collect();
callbackFunctionReferenceList.Add(registeredDeviceChangeEventFunctionId, deviceChangeEventFunctionDelegate);
}
++lastEventID;
returnValue = lastEventID;
deviceChangeEventList.Add(returnValue, deviceEventFunc);
return returnValue;
}
/// <summary>
/// Register a callback listening function to be called when a listening event (e.g. data is received with Tellstick Duo) occurs
/// </summary>
/// <param name="listeningFunc">Callback function to be called</param>
/// <param name="obj">Context object that will be echoed back when function is called. Only the object when the first function is registered will be used. Set to null if not used.</param>
/// <returns>Callback event id</returns>
public unsafe int tdRegisterRawDeviceEvent(RawListeningCallbackFunction listeningFunc, Object obj)
{
int returnValue = 0;
if (rawListenerList.Count == 0)
{
//first added, register with dll too
//only the context object of the first event will be registered
UnmanagedImport.RawListeningDelegate listeningFunctionDelegate = new UnmanagedImport.RawListeningDelegate(rawListeningFunction);
if (obj != null)
{
rawListenerContextHandle = GCHandle.Alloc(obj);
registeredRawListenerFunctionId = UnmanagedImport.tdRegisterRawDeviceEvent(listeningFunctionDelegate, (void*)GCHandle.ToIntPtr(rawListenerContextHandle));
}
else
{
registeredRawListenerFunctionId = UnmanagedImport.tdRegisterRawDeviceEvent(listeningFunctionDelegate, (void*)null);
}
GC.Collect();
callbackFunctionReferenceList.Add(registeredRawListenerFunctionId, listeningFunctionDelegate);
}
++lastEventID;
returnValue = lastEventID;
rawListenerList.Add(returnValue, listeningFunc);
return returnValue;
}
/// <summary>
/// Removes a device.
/// </summary>
/// <param name="deviceId">Id of device to remove</param>
/// <returns>True on success, false otherwise</returns>
public static bool tdRemoveDevice(int deviceId)
{
return UnmanagedImport.tdRemoveDevice(deviceId);
}
/// <summary>
/// Send a raw command to TellStick. Please read the TellStick protocol definition on how the command should be constructed.
/// </summary>
/// <param name="command">The command for TellStick in its native format</param>
/// <param name="reserved"></param>
/// <returns>Success or error code</returns>
public static unsafe int tdSendRawCommand(string command, int reserved)
{
char* commandChar = stringToChar(command);
int returnValue = UnmanagedImport.tdSendRawCommand(commandChar, reserved);
Marshal.FreeHGlobal((IntPtr)commandChar);
return returnValue;
}
/// <summary>
/// Sets a new protocol specific parameter. Please see the documentation of the protocols before setting any parameter.
/// </summary>
/// <param name="deviceId">Id of device to change</param>
/// <param name="name">The name of the parameter to change</param>
/// <param name="value">The new value for the parameter</param>
/// <returns>Success or error code</returns>
public static unsafe bool tdSetDeviceParameter(int deviceId, string name, string value)
{
char* nameChar = stringToChar(name);
char* valueChar = stringToChar(value);
bool returnValue = UnmanagedImport.tdSetDeviceParameter(deviceId, nameChar, valueChar);
Marshal.FreeHGlobal((IntPtr)nameChar);
Marshal.FreeHGlobal((IntPtr)valueChar);
return returnValue;
}
/// <summary>
/// Sets a new model for a device. Which model to set depends on the current protocol.
/// </summary>
/// <param name="deviceId">Id of device to change</param>
/// <param name="model">The new model</param>
/// <returns>Success or error code</returns>
public static unsafe bool tdSetModel(int deviceId, string model)
{
char* modelChar = stringToChar(model);
bool returnValue = UnmanagedImport.tdSetModel(deviceId, modelChar);
Marshal.FreeHGlobal((IntPtr)modelChar);
return returnValue;
}
/// <summary>
/// Sets a new name for a device.
/// </summary>
/// <param name="deviceId">Id of device to change</param>
/// <param name="name">The new name</param>
/// <returns>Success or error code</returns>
public static unsafe bool tdSetName(int deviceId, string name)
{
char* nameChar = stringToChar(name);
bool returnValue = UnmanagedImport.tdSetName(deviceId, nameChar);
Marshal.FreeHGlobal((IntPtr)nameChar);
return returnValue;
}
/// <summary>
/// This changes the current protocol used by a device. After changing the protocol, setting new parameters is required.
/// </summary>
/// <param name="deviceId">Id of device to change</param>
/// <param name="protocol">The new protocol to use</param>
/// <returns>Success or error code</returns>
public static unsafe bool tdSetProtocol(int deviceId, string protocol)
{
char* protocolChar = stringToChar(protocol);
bool returnValue = UnmanagedImport.tdSetProtocol(deviceId, protocolChar);
Marshal.FreeHGlobal((IntPtr)protocolChar);
return returnValue;
}
/// <summary>
/// Send "stop" command to device.
/// Make sure the device supports this by calling tdMethods() before any calls to this function.
/// </summary>
/// <param name="deviceId">The device id to stop</param>
/// <returns>Success or error code</returns>
public static int tdStop(int deviceId)
{
return UnmanagedImport.tdStop(deviceId);
}
/// <summary>
/// Turns a device on.
/// Make sure the device supports this by calling tdMethods() before any calls to this function.
/// </summary>
/// <param name="deviceId">Id of device to turn on</param>
/// <returns>Success or error code</returns>
public static int tdTurnOn(int deviceId)
{
return UnmanagedImport.tdTurnOn(deviceId);
}
/// <summary>
/// Turns a device off.
/// Make sure the device supports this by calling tdMethods() before any calls to this function.
/// </summary>
/// <param name="deviceId">Id of device to turn off</param>
/// <returns>Success or error code</returns>
public static int tdTurnOff(int deviceId)
{
return UnmanagedImport.tdTurnOff(deviceId);
}
/// <summary>
/// Unregister a callback function. All functions will be unregistered automatically when this objekt is deleted.
/// </summary>
/// <param name="eventId">Id of callback even to unregister</param>
public void unregisterCallback(int eventId)
{
eventList.Remove(eventId);
if (eventList.Count == 0)
{
//no more events in list
UnmanagedImport.tdUnregisterCallback(registeredEventFunctionId);
callbackFunctionReferenceList.Remove(registeredEventFunctionId);
if (eventContextHandle.IsAllocated)
{
eventContextHandle.Free();
}
}
deviceChangeEventList.Remove(eventId);
if (deviceChangeEventList.Count == 0)
{
//no more events in list
UnmanagedImport.tdUnregisterCallback(registeredDeviceChangeEventFunctionId);
callbackFunctionReferenceList.Remove(registeredDeviceChangeEventFunctionId);
if (deviceChangeEventContextHandle.IsAllocated)
{
deviceChangeEventContextHandle.Free();
}
}
rawListenerList.Remove(eventId);
if (rawListenerList.Count == 0)
{
//no more events in list
UnmanagedImport.tdUnregisterCallback(registeredRawListenerFunctionId);
callbackFunctionReferenceList.Remove(registeredRawListenerFunctionId);
if (rawListenerContextHandle.IsAllocated)
{
rawListenerContextHandle.Free();
}
}
}
/// <summary>
/// Send "up" command to device.
/// Make sure the device supports this by calling tdMethods() before any calls to this function.
/// </summary>
/// <param name="deviceId">The device id to send the command to</param>
/// <returns>Success or error code</returns>
public static int tdUp(int deviceId)
{
return UnmanagedImport.tdUp(deviceId);
}
#endregion
#region Private Methods
/// <summary>
/// Convert char* to correctly encoded string, clean up received char*
/// </summary>
/// <param name="input">Char* to convert</param>
/// <returns>Converted string</returns>
private static unsafe string getString(char* input)
{
return getString(input, true);
}
/// <summary>
/// Convert char* to correctly encoded string, clean up of received char* is optional
/// </summary>
/// <param name="input">Char* to convert</param>
/// <param name="release">Clean up char* or not (don't do that if it is still should be used somewhere)</param>
/// <returns>Converted string</returns>
private static unsafe string getString(char* input, bool release)
{
string returnString = System.Text.Encoding.UTF8.GetString(System.Text.Encoding.Unicode.GetBytes(new string(input)));
if (returnString.Contains("\0"))
{
returnString = returnString.Substring(0, returnString.IndexOf('\0'));
}
if (release)
{
UnmanagedImport.tdReleaseString(input);
}
GC.Collect();
return returnString;
}
/// <summary>
/// Convert string to correctly encoded char*
/// </summary>
/// <param name="input">String to convert</param>
/// <returns>Converted char*</returns>
private static unsafe char* stringToChar(string input)
{
input = String.Concat(input, char.MinValue); //add null terminator
byte[] inputByte = System.Text.Encoding.UTF8.GetBytes(input);
int size = Marshal.SystemDefaultCharSize * inputByte.Length;
IntPtr inputPointer = Marshal.AllocHGlobal(size);
Marshal.Copy(inputByte, 0, inputPointer, inputByte.Length);
return (char*)inputPointer;
}
/// <summary>
/// Event function wrapper that will call all registered event functions with C#-arguments when
/// this event function is called from telldus core, with C++-style arguments. This function will
/// be registered with telldus core when the first event callback function is added.
/// </summary>
/// <param name="deviceId">Id of affected device</param>
/// <param name="method">Method that was executed on device</param>
/// <param name="data">Optional data that was sent to the method (e.g. dim value)</param>
/// <param name="callbackId">Callback event id</param>
/// <param name="context">Context (optional)</param>
/// <returns>0</returns>
private unsafe void eventFunction() //int deviceId, int method, int callbackId, void* context[MarshalAs(UnmanagedType.LPStr)]string data
{
foreach (EventCallbackFunction eventFunc in eventList.Values)
{
/*
if (context != null)
{
GCHandle eventContextHandle = GCHandle.FromIntPtr((IntPtr)context);
eventFunc(deviceId, method, "", callbackId, (Object)eventContextHandle.Target); //data
}
else
{
eventFunc(deviceId, method, "", callbackId, null);
}
*/
eventFunc(1, 1, "", 1, null);
GC.Collect();
}
}
/// <summary>
/// Event function wrapper that will call all registered device change event functions with C#-arguments when
/// this device change event function is called from telldus core, with C++-style arguments. This function will
/// be registered with telldus core when the first device change event callback function is added.
/// </summary>
/// <param name="deviceId">Id of affected device</param>
/// <param name="changeEvent">Method that was executed, TELLSTICK_DEVICE_ADDED, TELLSTICK_DEVICE_CHANGED, TELLSTICK_DEVICE_REMOVED, TELLSTICK_DEVICE_STATE_CHANGED</param>
/// <param name="changeType">Type of change TELLSTICK_CHANGE_NAME, TELLSTICK_CHANGE_PROTOCOL, TELLSTICK_CHANGE_MODEL</param>
/// <param name="callbackId">Callback event id</param>
/// <param name="context">Context (optional)</param>
/// <returns>0</returns>
private unsafe void deviceEventFunction(int deviceId, int changeEvent, int changeType, int callbackId, void* context)
{
foreach (DeviceChangeEventCallbackFunction deviceEventFunc in deviceChangeEventList.Values)
{
if (context != null)
{
GCHandle deviceChangeEventContextHandle = GCHandle.FromIntPtr((IntPtr)context);
deviceEventFunc(deviceId, changeEvent, changeType, callbackId, (Object)deviceChangeEventContextHandle.Target);
}
else
{
deviceEventFunc(deviceId, changeEvent, changeType, callbackId, null);
}
GC.Collect();
}
}
/// <summary>
/// Event function wrapper that will call all registered listening functions with C#-arguments when
/// this listening function is called from telldus core, with C++-style arguments. This function will
/// be registered with telldus core when the first listening callback function is added.
/// </summary>
/// <param name="data">Received data</param>
/// <param name="controllerId">Id of receiving controller</param>
/// <param name="callbackId">Callback event id</param>
/// <param name="context">Context (optional)</param>
/// <returns>0</returns>
private unsafe void rawListeningFunction(char* data, int controllerId, int callbackId, void* context)
{
foreach (RawListeningCallbackFunction rawListeningFunc in rawListenerList.Values)
{
if (context != null)
{
GCHandle rawListenerContextHandle = GCHandle.FromIntPtr((IntPtr)context);
rawListeningFunc(getString(data, false), controllerId, callbackId, (Object)rawListenerContextHandle.Target); //strings cannot be released here, since they are still in use by calling core (sent to other clients aswell), let the core take care of it with shared pointer
}
else
{
rawListeningFunc(getString(data, false), controllerId, callbackId, null);
}
GC.Collect();
}
}
#endregion
}
}