Initial commit
12d36273bda7f111dd933c39d145f87e47475153
10 files changed
HidApiNet.HidDevice.csHidApiNet.HidDeviceInfo.csHidApiNet.HidDeviceInfoCollection.csHidApiNet.Interop.csMakefileProgram.csWeather.Data.csWeather.IContract.csWeather.Server.csWeather.Weather.cs
diff --git a/HidApiNet.HidDevice.cs b/HidApiNet.HidDevice.cs
new file mode 100644
index 0000000..36b437f
--- /dev/null
+++ b/HidApiNet.HidDevice.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace HidApiNet
+{
+ class HidDevice : IDisposable
+ {
+ public HidDeviceInfo info;
+ private IntPtr hid = IntPtr.Zero;
+
+ public HidDevice(string path)
+ {
+ var res = Interop.hid_init();
+ if (res != 0)
+ return;
+ this.hid = Interop.hid_open_path(path);
+ }
+
+ public HidDevice(ushort vid, ushort pid)
+ {
+ var res = Interop.hid_init();
+ if (res != 0)
+ return;
+ //this.hid = HIDApi.hid_open(vid, pid, null);
+
+ var ptr = Interop.hid_enumerate(vid, pid);
+ if (ptr == IntPtr.Zero)
+ return;
+
+ this.info = (HidDeviceInfo)Marshal.PtrToStructure(ptr, typeof(HidDeviceInfo));
+ this.hid = Interop.hid_open_path(info.path);
+ }
+
+ public bool IsOpen
+ {
+ get
+ {
+ return this.hid != IntPtr.Zero;
+ }
+ }
+
+ private enum PropName
+ {
+ Unknown,
+ ProductString,
+ ManufacturerString,
+ SerialNumberString,
+ IndexedString
+ }
+
+ private string GetPropValue(PropName name, int index = 0)
+ {
+ int res;
+ string s = new string('*', 128);
+ switch (name)
+ {
+ case PropName.ProductString:
+ res = Interop.hid_get_product_string(this.hid, s, s.Length);
+ break;
+ case PropName.ManufacturerString:
+ res = Interop.hid_get_manufacturer_string(this.hid, s, s.Length);
+ break;
+ case PropName.SerialNumberString:
+ res = Interop.hid_get_serial_number_string(this.hid, s, s.Length);
+ break;
+ case PropName.IndexedString:
+ res = Interop.hid_get_indexed_string(this.hid, index, s, s.Length);
+ break;
+ default:
+ return null;
+ }
+ if (res != 0)
+ return null;
+ else
+ return s;
+ }
+
+ public string ProductString
+ {
+ get
+ {
+ return GetPropValue(PropName.ProductString);
+ }
+ }
+
+ public string ManufacturerString
+ {
+ get
+ {
+ return GetPropValue(PropName.ManufacturerString);
+ }
+ }
+
+ public string SerialNumberString
+ {
+ get
+ {
+ return GetPropValue(PropName.SerialNumberString);
+ }
+ }
+
+ public string IndexedString(int index)
+ {
+ return GetPropValue(PropName.IndexedString, index);
+ }
+
+ public int SetNonBlocking()
+ {
+ return Interop.hid_set_nonblocking(this.hid, 1);
+ }
+
+ public int Write(byte[] buffer)
+ {
+ return Interop.hid_write(this.hid, buffer, buffer.Length);
+ }
+
+ public int Read(byte[] buffer, int len)
+ {
+ return Interop.hid_read(this.hid, buffer, len);
+ }
+
+ public int ReadTimeOut(byte[] buffer, int t)
+ {
+ return Interop.hid_read_timeout(this.hid, buffer, buffer.Length, t);
+ }
+
+
+ public void Dispose()
+ {
+ if (this.hid != IntPtr.Zero)
+ Interop.hid_close(hid);
+ Interop.hid_exit();
+ }
+ }
+}
diff --git a/HidApiNet.HidDeviceInfo.cs b/HidApiNet.HidDeviceInfo.cs
new file mode 100644
index 0000000..855f673
--- /dev/null
+++ b/HidApiNet.HidDeviceInfo.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace HidApiNet
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
+ unsafe struct HidDeviceInfo
+ {
+ [MarshalAs(UnmanagedType.LPStr)]
+ public readonly string path;
+ public readonly ushort vendor_id;
+ public readonly ushort product_id;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ private readonly IntPtr _serial_number;
+ public readonly ushort release_number;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ private readonly IntPtr _manufacturer_string;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ private readonly IntPtr _product_string;
+ public readonly ushort usage_page;
+ public readonly ushort usage;
+ public readonly int interface_number;
+ public readonly IntPtr next;
+
+ private int StringLength(IntPtr ptr, int maxlen)
+ {
+ if (ptr == IntPtr.Zero)
+ return 0;
+ for (int intLen = 0; intLen < maxlen; intLen++)
+ {
+ int* endchar = (int*)ptr;
+ if (*endchar == 0)
+ return intLen;
+ ptr = new IntPtr(ptr.ToInt32() + 4);
+ }
+ return 0;
+ }
+ private string GetString(IntPtr ptr)
+ {
+ int intLen = StringLength(ptr, 128);
+ if (intLen == 0)
+ return null;
+ var buf = new byte[intLen * 4];
+ Marshal.Copy(ptr, buf, 0, buf.Length);
+ return Encoding.Unicode.GetString(buf);
+ }
+
+ public string product_string
+ {
+ get
+ {
+ return GetString(_product_string);
+ }
+ }
+ public string manufacturer_string
+ {
+ get
+ {
+ return GetString(_manufacturer_string);
+ }
+ }
+ public string serial_number
+ {
+ get
+ {
+ return GetString(_serial_number);
+ }
+ }
+ }
+
+
+}
diff --git a/HidApiNet.HidDeviceInfoCollection.cs b/HidApiNet.HidDeviceInfoCollection.cs
new file mode 100644
index 0000000..2cbaa53
--- /dev/null
+++ b/HidApiNet.HidDeviceInfoCollection.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace HidApiNet
+{
+ class HidDeviceInfoCollection : List<HidDeviceInfo>, IDisposable
+ {
+ private IntPtr devs = IntPtr.Zero;
+
+ public HidDeviceInfoCollection()
+ {
+ var res = Interop.hid_init();
+ if (res != 0)
+ return;
+
+ this.devs = Interop.hid_enumerate(0x00, 0x00);
+ var curdev = new IntPtr(this.devs.ToInt32());
+ while (curdev != IntPtr.Zero)
+ {
+ var info = (HidDeviceInfo)Marshal.PtrToStructure(curdev, typeof(HidDeviceInfo));
+ this.Add(info);
+ curdev = info.next;
+ }
+ }
+
+ public void Dispose()
+ {
+ if (this.devs != IntPtr.Zero)
+ Interop.hid_free_enumeration(this.devs);
+ }
+
+ }
+
+}
diff --git a/HidApiNet.Interop.cs b/HidApiNet.Interop.cs
new file mode 100644
index 0000000..da6cb6a
--- /dev/null
+++ b/HidApiNet.Interop.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Runtime.InteropServices;
+
+//Wraps: libhidapi-libusb
+
+namespace HidApiNet
+{
+ class Interop
+ {
+ [DllImport("libhidapi-libusb.so")]
+ public static extern int hid_init();
+
+ [DllImport("libhidapi-libusb.so")]
+ public static extern int hid_exit();
+
+ [DllImport("libhidapi-libusb.so")]
+ public static extern IntPtr hid_enumerate(UInt16 vendorId, UInt16 productId);
+
+ [DllImport("libhidapi-libusb.so")]
+ public static extern void hid_free_enumeration(IntPtr devs);
+
+ [DllImport("libhidapi-libusb.so", CharSet = CharSet.Auto)]
+ public static extern IntPtr hid_open(UInt16 vendorId, UInt16 productId, string serialNumber);
+
+ [DllImport("libhidapi-libusb.so")]
+ public static extern void hid_close(IntPtr device);
+
+ [DllImport("libhidapi-libusb.so", CharSet = CharSet.Ansi)]
+ public static extern IntPtr hid_open_path(string path);
+
+ [DllImport("libhidapi-libusb.so")]
+ public static extern int hid_set_nonblocking(IntPtr device, int nonBlock);
+
+ [DllImport("libhidapi-libusb.so")]
+ public static extern int hid_read(IntPtr device, [Out] byte[] data, int length);
+
+ [DllImport("libhidapi-libusb.so")]
+ public static extern int hid_read_timeout(IntPtr device, [Out] byte[] data, int length, int milliseconds);
+
+ [DllImport("libhidapi-libusb.so")]
+ public static extern int hid_write(IntPtr device, [In] byte[] data, int length);
+
+ [DllImport("libhidapi-libusb.so")]
+ public static extern int hid_get_feature_report(IntPtr device, [Out] string buf, int length);
+
+ [DllImport("libhidapi-libusb.so")]
+ public static extern int hid_send_feature_report(IntPtr device, [In] byte[] buf, int length);
+
+ [DllImport("libhidapi-libusb.so", CharSet = CharSet.Unicode)]
+ public static extern int hid_get_manufacturer_string(IntPtr device, [Out] string buf, int len);
+
+ [DllImport("libhidapi-libusb.so", CharSet = CharSet.Unicode)]
+ public static extern int hid_get_product_string(IntPtr device, [Out] string buf, int len);
+
+ [DllImport("libhidapi-libusb.so", CharSet = CharSet.Unicode)]
+ public static extern int hid_get_serial_number_string(IntPtr device, [Out] string buf, int len);
+
+ [DllImport("libhidapi-libusb.so", CharSet = CharSet.Unicode)]
+ public static extern int hid_get_indexed_string(IntPtr device, int index, [Out] string buf, int len);
+
+ [DllImport("libhidapi-libusb.so", CharSet = CharSet.Unicode)]
+ public static extern String hid_error(IntPtr device);
+ }
+}
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..8a265d7
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,15 @@
+#PHONY : build clean
+
+all : run
+
+#build : HIDProject.exe
+# @# do nothing
+
+HIDProject.exe : Program.cs HidApiNet.HidDevice.cs HidApiNet.HidDeviceInfo.cs HidApiNet.HidDeviceInfoCollection.cs HidApiNet.Interop.cs Weather.Data.cs Weather.IContract.cs Weather.Server.cs Weather.Weather.cs
+ mcs -unsafe Program.cs HidApiNet.HidDevice.cs HidApiNet.HidDeviceInfo.cs HidApiNet.HidDeviceInfoCollection.cs HidApiNet.Interop.cs Weather.Data.cs Weather.IContract.cs Weather.Server.cs Weather.Weather.cs -r:System.ServiceModel -Out:HIDProject.exe
+
+clean :
+ rm -rf HIDProject.exe
+
+run : HIDProject.exe
+ mono HIDProject.exe
diff --git a/Program.cs b/Program.cs
new file mode 100644
index 0000000..2623276
--- /dev/null
+++ b/Program.cs
@@ -0,0 +1,153 @@
+using System;
+using System.Diagnostics;
+using System.ServiceModel;
+using System.Text;
+
+namespace HIDProject
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ const ushort vid = 0x1941;
+ const ushort pid = 0x8021;
+
+ if (args.Length == 0)
+ {
+ Console.WriteLine("commands: ... l(ist) r(ead) s(erver) d(dump) c(urrent)");
+ return;
+ }
+
+ var command = args[0];
+
+ if (command[0] == 'l')
+ {
+ var devs = new HidApiNet.HidDeviceInfoCollection();
+ foreach (var cur_dev in devs)
+ {
+ Console.WriteLine("Device Found");
+ Console.WriteLine("\ttype: {0:x4} {1:x4}", cur_dev.vendor_id, cur_dev.product_id);
+ Console.WriteLine("\tpath: {0}", cur_dev.path);
+ Console.WriteLine("\tserial_number: {0}", cur_dev.serial_number ?? "(null)");
+ Console.WriteLine("\tManufacturer: {0}", cur_dev.manufacturer_string ?? "(null)");
+ Console.WriteLine("\tProduct: {0}", cur_dev.product_string ?? "(null)");
+ Console.WriteLine("\tRelease: {0:x}", cur_dev.release_number);
+ Console.WriteLine("\tInterface: {0}", cur_dev.interface_number);
+ Console.WriteLine();
+ }
+ devs.Dispose();
+ return;
+ }
+
+ if (command[0] == 'r')
+ {
+ var station = new Weather.Station(vid, pid);
+ if (station.IsOpen)
+ {
+ var buffer = new byte[32];
+ for (ushort adres = 0x0000; adres < 0x100; adres += 0x20)
+ {
+ var len = station.ReadBlock(adres, buffer);
+ var sb = new StringBuilder();
+ sb.AppendFormat("{0:x4} ", adres);
+ for (int intJ = 0; intJ < len; intJ++)
+ sb.AppendFormat("{0:x2} ", buffer[intJ]);
+ Console.WriteLine(sb.ToString());
+ }
+ station.Dispose();
+ }
+ else
+ {
+ Console.WriteLine("WeatherStation not found");
+ }
+ }
+
+ if (command[0] == 'd')
+ {
+ var station = new Weather.Station(vid, pid);
+ if (station.IsOpen)
+ {
+ var buffer = new byte[32];
+ for (ushort adres = 0x0000; adres < 0x100; adres += 0x20)
+ {
+ var len = station.ReadBlock(adres, buffer);
+ var sb = new StringBuilder();
+ //sb.AppendFormat("{0:x4} ", adres);
+ for (int intJ = 0; intJ < len; intJ++)
+ sb.AppendFormat("{0:x2} ", buffer[intJ]);
+ Console.Write(sb.ToString());
+ }
+ station.Dispose();
+ Console.WriteLine();
+ }
+ else
+ {
+ Console.WriteLine("WeatherStation not found");
+ }
+ }
+
+ if (command[0] == 's')
+ {
+ Console.WriteLine("Server: " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
+ Console.WriteLine("Starting host listening on port 20402");
+ var host = new ServiceHost(typeof(Weather.Server),
+ new Uri[] { new Uri("http://localhost:20402/Path1") });
+
+ host.AddServiceEndpoint(typeof(Weather.IContract), new BasicHttpBinding(), "MyTest1");
+ host.Open();
+
+ Console.WriteLine("Hit return to stop server");
+ Console.ReadLine();
+
+ host.Close();
+
+ }
+
+ if (command[0] == 'c')
+ {
+ var weatherstation = new Weather.Station(vid, pid);
+ if (weatherstation.IsOpen)
+ {
+ var total = new byte[256];
+ var buffer = new byte[32];
+ int intIndex = 0;
+ for (ushort adres = 0x0000; adres < 0x100; adres += 0x20)
+ {
+ Debug.WriteLine("Reading block {0:x}", adres);
+ var len = weatherstation.ReadBlock(adres, buffer);
+ Array.Copy(buffer, 0, total, intIndex, buffer.Length);
+ intIndex += buffer.Length;
+ Debug.WriteLine("Done.");
+ System.Threading.Thread.Sleep(100);
+ }
+
+ var stationData = Weather.Data.Helper.BytesToStruct<Weather.Data.StationData>(total);
+
+ Debug.WriteLine("Getting CurrentData");
+
+ var settings1 = stationData.settings_1.ToEnum<Weather.Data.Settings1Enum>();
+ var settings2 = stationData.settings_2.ToEnum<Weather.Data.Settings2Enum>();
+
+ ushort currentPosition = stationData.current_pos.ToUInt16();
+ var lenLiveData = weatherstation.ReadBlock(currentPosition, buffer);
+
+ weatherstation.Dispose();
+
+ Debug.WriteLine("Read {0} bytes", lenLiveData);
+ //var liveData = Helper.BytesToStruct<LiveData1080>(buffer);
+
+ var sb = new StringBuilder();
+ for (int intI = 0; intI < 16; intI++)
+ sb.AppendFormat("{0:x2}", buffer[intI]);
+
+ Console.WriteLine(""+sb);
+ }
+ else
+ {
+ Console.WriteLine("WeatherStation not found");
+ }
+ }
+
+ }
+ }
+}
diff --git a/Weather.Data.cs b/Weather.Data.cs
new file mode 100644
index 0000000..88e2bea
--- /dev/null
+++ b/Weather.Data.cs
@@ -0,0 +1,443 @@
+using System;
+using System.Text;
+using System.Runtime.InteropServices;
+
+// From: https://jim-easterbrook.github.io/pywws/doc/en/html/_modules/pywws/WeatherStation.html
+
+namespace Weather.Data
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct _date_time
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
+ private byte[] buffer;
+ public override string ToString()
+ {
+ return ToDateTime.ToString();
+ }
+
+ private int BCD2INT(byte b)
+ {
+ return (10 * (b >> 4)) + (b & 0x0f);
+ }
+
+ public DateTime ToDateTime
+ {
+ get
+ {
+ return new DateTime(2000 + BCD2INT(buffer[0]), BCD2INT(buffer[1]), BCD2INT(buffer[2]), BCD2INT(buffer[3]), BCD2INT(buffer[4]), 0);
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct _time
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+ private byte[] buffer;
+ public override string ToString()
+ {
+ return ToTimeSpan.ToString();
+ }
+
+ public TimeSpan ToTimeSpan
+ {
+ get
+ {
+ return new TimeSpan(buffer[0], buffer[1], 0);
+ }
+ }
+ }
+
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct _unsigned_int3
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ private byte[] buffer;
+
+ public override string ToString()
+ {
+ return ToInt.ToString();
+ }
+
+ public int ToInt
+ {
+ get
+ {
+ return (buffer[2] << 16) + (buffer[1] << 8) + buffer[0];
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct _signed_byte
+ {
+ private byte buffer;
+
+ public override string ToString()
+ {
+ return ToInt.ToString();
+ }
+
+ public int ToInt
+ {
+ get
+ {
+ if (buffer >= 128)
+ return 128 - buffer;
+ else
+ return buffer;
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct _unsigned_short
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+ private byte[] buffer;
+
+ public override string ToString()
+ {
+ return ToUInt16().ToString();
+ }
+
+ public ushort ToUInt16()
+ {
+ return Convert.ToUInt16((buffer[1] << 8) + buffer[0]);
+ }
+ }
+
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct _signed_short
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+ private byte[] buffer;
+
+ public override string ToString()
+ {
+ return ToInt16().ToString();
+ }
+
+ public short ToInt16()
+ {
+ if (buffer[1] >= 128)
+ return Convert.ToInt16(((128 - buffer[1]) << 8) - buffer[0]);
+ else
+ return Convert.ToInt16((buffer[1] << 8) + buffer[0]);
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+
+ public struct _wind
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ private byte[] buffer;
+
+ // wind average - 12 bits split across a byte and a nibble
+ public int Average
+ {
+ get
+ {
+ return buffer[0] + ((buffer[2] & 0x0F) << 8);
+ }
+ }
+ public int Gust
+ {
+ get
+ {
+ return buffer[0] + ((buffer[1] & 0xF0) << 4);
+ }
+ }
+ public int Direction
+ {
+ get
+ {
+ return buffer[3];
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct _wind_gust
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ private byte[] buffer;
+
+ // wind gust - 12 bits split across a byte and a nibble
+ public int ToInt
+ {
+ get
+ {
+ return buffer[0] + ((buffer[1] & 0xF0) << 4);
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct _bit_field
+ {
+ private byte buffer;
+
+ public override string ToString()
+ {
+ var sb = new StringBuilder();
+ int intMask = 0x80;
+ for (int intI = 0; intI < 8; intI++)
+ {
+ if ((buffer & intMask) != 0)
+ sb.Append("1");
+ else
+ sb.Append("0");
+ intMask = intMask >> 1;
+ }
+ return sb.ToString();
+ }
+
+ public T ToEnum<T>()
+ {
+ return (T)Enum.ToObject(typeof(T), buffer);
+ }
+ }
+
+ [Flags]
+ public enum Settings1Enum : uint
+ {
+ temp_in_F = 0x01,
+ temp_out_F = 0x02,
+ rain_in = 0x04,
+ bit3 = 0x08,
+ bit4 = 0x10,
+ pressure_hPa = 0x20,
+ pressure_inHg = 0x40,
+ pressure_mmHg = 0x80
+ }
+
+ [Flags]
+ public enum Settings2Enum : uint
+ {
+ wind_mps = 0x01,
+ wind_kmph = 0x02,
+ wind_knot = 0x04,
+ wind_mph = 0x08,
+ wind_bft = 0x10,
+ bit5 = 0x20,
+ bit6 = 0x40,
+ bit7 = 0x80
+ }
+
+ [Flags]
+ public enum Display1Enum : uint
+ {
+ pressure_rel = 0x01,
+ wind_gust = 0x02,
+ clock_12hr = 0x04,
+ date_mdy = 0x08,
+ time_scale_24 = 0x10,
+ show_year = 0x20,
+ show_day_name = 0x40,
+ alarm_time = 0x80
+ }
+
+ [Flags]
+ public enum Display2Enum : uint
+ {
+ temp_out_temp = 0x01,
+ temp_out_chill = 0x02,
+ temp_out_dew = 0x04,
+ rain_hour = 0x08,
+ rain_day = 0x10,
+ rain_week = 0x20,
+ rain_month = 0x40,
+ rain_total = 0x80
+ }
+
+ [Flags]
+ public enum Alarm1Enum : uint
+ {
+ bit0, time = 0x01,
+ wind_dir = 0x02,
+ bit3 = 0x04,
+ hum_in_lo = 0x08,
+ hum_in_hi = 0x10,
+ hum_out_lo = 0x20,
+ hum_out_hi = 0x40
+ }
+
+ [Flags]
+ public enum Alarm2Enum : uint
+ {
+ wind_ave = 0x01,
+ wind_gust = 0x02,
+ rain_hour = 0x04,
+ rain_day = 0x08,
+ pressure_abs_lo = 0x10,
+ pressure_abs_hi = 0x20
+ }
+
+ [Flags]
+ public enum Alarm3Enum : uint
+ {
+ temp_in_lo = 0x01,
+ temp_in_hi = 0x02,
+ temp_out_lo = 0x04,
+ temp_out_hi = 0x08,
+ wind_chill_lo = 0x10,
+ wind_chill_hi = 0x20,
+ dew_point_lo = 0x40,
+ dew_point_hi = 0x80
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct LiveData1080
+ {
+ public byte delay;
+ public byte hum_in;
+ public _signed_short temp_in;
+ public byte hum_out;
+ public _signed_short temp_out;
+ public _unsigned_short abs_pressure;
+ public _wind wind;
+ public _unsigned_short rain;
+ public byte status;
+ }
+
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct StationData
+ {
+ public ushort MagicNumber; // 00
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)]
+ public byte[] FF; // 02..15
+ public byte read_period; // 16
+ public _bit_field settings_1; // 17
+ public _bit_field settings_2; // 18
+ public _bit_field display_1; // 19
+ public _bit_field display_2; // 20
+ public _bit_field alarm_1; // 21
+ public _bit_field alarm_2; // 22
+ public _bit_field alarm_3; // 23
+ public _signed_byte timezone; // 24
+ public byte unknown_01; // 25
+ public byte data_changed; // 26
+ public _unsigned_short data_count; // 27
+ public _bit_field display_3; // 29
+ public _unsigned_short current_pos; // 30
+ public _unsigned_short rel_pressure; // 32
+ public _unsigned_short abs_pressure; // 34
+ public _unsigned_short lux_wm2_coeff; // 36
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
+ public byte[] unknown1; // 38
+ public _date_time date_time; // 43
+
+ // Alarm block
+ public byte alarm_hum_in_hi; // 48
+ public byte alarm_hum_in_low; // 49
+ public _signed_short alarm_temp_in_hi; // 50
+ public _signed_short alarm_temp_in_low; // 52
+ public byte alarm_hum_out_hi; // 54
+ public byte alarm_hum_out_low; // 55
+ public _signed_short alarm_temp_out_hi; // 56
+ public _signed_short alarm_temp_out_lo; // 58
+ public _signed_short alarm_windchill_hi; // 60
+ public _signed_short alarm_windchill_lo; // 62
+ public _signed_short alarm_dewpoint_hi; // 64
+ public _signed_short alarm_dewpoint_lo; // 66
+ public _unsigned_short alarm_abs_pressure_hi; // 68
+ public _unsigned_short alarm_abs_pressure_lo; // 70
+ public _unsigned_short alarm_rel_pressure_hi; // 72
+ public _unsigned_short alarm_rel_pressure_lo; // 74
+ public byte alarm_wind_ave_bft; // 76
+ public byte alarm_wind_ave_ms; // 77
+ public byte alarm_wind_gust_bft; // 79
+ public byte alarm_wind_gust_ms; // 80
+ public byte alarm_wind_dir; // 82
+ public _unsigned_short alarm_rain_hour; // 83
+ public _unsigned_short alarm_rain_day; // 85
+ public _time alarm_time; // 87
+ public _unsigned_int3 alarm_illuminance; // 89
+ public byte alarm_uv; // 92
+
+ // Max block
+ public byte max_uv_val; // 93
+ public _unsigned_int3 max_illuminance_val; // 94
+ public byte unknown_18; // 97
+ public byte max_hum_val; // 98
+ public byte min_hum_in_val; // 99
+ public byte max_hum_out_val; // 100
+ public byte min_hum_out_val; // 101
+ public _signed_short max_temp_in_val; // 102
+ public _signed_short min_temp_in_val; // 104
+ public _signed_short max_temp_out_val; // 106
+ public _signed_short min_temp_out_val; // 108
+ public _signed_short max_windchill_val; // 110
+ public _signed_short min_windchill_val; // 112
+ public _signed_short max_dewpoint_val; // 114
+ public _signed_short min_dewpoint_val; // 116
+ public _unsigned_short max_abs_pressure_val; // 118
+ public _unsigned_short min_abs_pressure_val; // 120
+ public _unsigned_short max_rel_pressure_val; // 122
+ public _unsigned_short min_rel_pressure_val; // 124
+ public _unsigned_short max_wind_ave_val; // 126
+ public _unsigned_short max_wind_gust_val; // 128
+
+ // Rain
+
+ public _unsigned_short max_rain_hour_val; // 130
+ public _unsigned_short max_rain_day_val; // 132
+ public _unsigned_short max_rain_week_val; // 134
+ public _unsigned_short max_rain_month_val; // 136
+ public _unsigned_short max_rain_total_val; // 138
+
+ public byte TODO; // 140
+
+ public _date_time max_hum_date; // 141
+ public _date_time min_hum_in_date; // 146
+ public _date_time max_hum_out_date; // 151
+ public _date_time min_hum_out_date; // 156
+ public _date_time max_temp_in_date; // 161
+ public _date_time min_temp_in_date; // 166
+ public _date_time max_temp_out_date; // 171
+ public _date_time min_temp_out_date; // 176
+ public _date_time max_windchill_date; // 181
+ public _date_time min_windchill_date; // 186
+ public _date_time max_dewpoint_date; // 191
+ public _date_time min_dewpoint_date; // 196
+ public _date_time max_abs_pressure_date; // 201
+ public _date_time min_abs_pressure_date; // 206
+ public _date_time max_rel_pressure_date; // 211
+ public _date_time min_rel_pressure_date; // 216
+ public _date_time max_wind_ave_date; // 221
+ public _date_time max_wind_gust_date; // 226
+ public _date_time max_rain_hour_date; // 231
+ public _date_time max_rain_day_date; // 236
+ public _date_time max_rain_week_date; // 241
+ public _date_time max_rain_month_date; // 246
+ public _date_time max_rain_total_date; // 251
+
+ public _unsigned_short LastOne; // 254 en 255
+ }
+
+ public class Helper
+ {
+ public static T BytesToStruct<T>(byte[] rawData) where T : struct
+ {
+ T result = default(T);
+ GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
+ try
+ {
+ result = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
+ }
+ finally
+ {
+ handle.Free();
+ }
+ return result;
+ }
+ }
+
+}
+
diff --git a/Weather.IContract.cs b/Weather.IContract.cs
new file mode 100644
index 0000000..7879b81
--- /dev/null
+++ b/Weather.IContract.cs
@@ -0,0 +1,17 @@
+using System.ServiceModel;
+
+namespace Weather
+{
+ [ServiceContract]
+ interface IContract
+ {
+ [OperationContract]
+ string Info();
+
+ [OperationContract]
+ int ReadBlock(ushort vid, ushort pid, ushort adres, ref byte[] buffer);
+
+ [OperationContract]
+ bool WriteByte(ushort vid, ushort pid, ushort adres, byte b);
+ }
+}
diff --git a/Weather.Server.cs b/Weather.Server.cs
new file mode 100644
index 0000000..b59791e
--- /dev/null
+++ b/Weather.Server.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Text;
+
+namespace Weather
+{
+ public class Server : IContract
+ {
+ public string Info()
+ {
+ var sb = new StringBuilder();
+ var devs = new HidApiNet.HidDeviceInfoCollection();
+ foreach (var cur_dev in devs)
+ {
+ sb.AppendFormat("Device Found"+Environment.NewLine);
+ sb.AppendFormat("\ttype: {0:x4} {1:x4}" + Environment.NewLine, cur_dev.vendor_id, cur_dev.product_id);
+ sb.AppendFormat("\tpath: {0}" + Environment.NewLine, cur_dev.path);
+ sb.AppendFormat("\tserial_number: {0}" + Environment.NewLine, cur_dev.serial_number ?? "(null)");
+ sb.AppendFormat("\tManufacturer: {0}" + Environment.NewLine, cur_dev.manufacturer_string ?? "(null)");
+ sb.AppendFormat("\tProduct: {0}" + Environment.NewLine, cur_dev.product_string ?? "(null)");
+ sb.AppendFormat("\tRelease: {0:x}" + Environment.NewLine, cur_dev.release_number);
+ sb.AppendFormat("\tInterface: {0}" + Environment.NewLine, cur_dev.interface_number);
+ sb.AppendLine();
+ }
+ devs.Dispose();
+ return sb.ToString();
+ }
+
+ public int ReadBlock(ushort vid, ushort pid, ushort intAdres, ref byte[] buffer)
+ {
+ //Console.WriteLine("{0}\\{1} on {2}", Environment.UserDomainName, Environment.UserName, Environment.MachineName);
+ var res = 0;
+ var station = new Weather.Station(vid, pid);
+ //Console.WriteLine("Openened {0:x4} {1:x4} {2} ", vid, pid, station.IsOpen);
+ if (station.IsOpen)
+ res = station.ReadBlock(intAdres, buffer);
+ station.Dispose();
+ //Console.WriteLine("Read " + res + " bytes");
+ return res;
+ }
+
+ public bool WriteByte(ushort vid, ushort pid, ushort intAdres, byte b)
+ {
+ bool res = false;
+ var station = new Weather.Station(vid, pid);
+ if (station.IsOpen)
+ res = station.WriteByte(intAdres, b);
+ station.Dispose();
+ //Console.WriteLine("Read " + res + " bytes");
+ return res;
+ }
+
+ }
+}
diff --git a/Weather.Weather.cs b/Weather.Weather.cs
new file mode 100644
index 0000000..d44d992
--- /dev/null
+++ b/Weather.Weather.cs
@@ -0,0 +1,99 @@
+using System;
+using HidApiNet;
+
+namespace Weather
+{
+ class Station : IDisposable
+ {
+ private HidDevice device;
+
+ private const byte EndMark = 0x20;
+ private const byte ReadCommand = 0xA1;
+ private const byte WriteCommand = 0xA0;
+ private const byte WriteCommandWord = 0xA2;
+ private const byte Zero = 0x00;
+
+ private const byte Acknowledge = 0xA5;
+
+ public Station(ushort vid, ushort pid)
+ {
+ this.device = new HidDevice(vid, pid);
+ }
+
+ public int SetNonBlocking()
+ {
+ return this.device.SetNonBlocking();
+ }
+
+ public bool IsOpen
+ {
+ get
+ {
+ return this.device.IsOpen;
+ }
+ }
+
+ private int ReadTimeOut(byte[] buffer, int t)
+ {
+ return device.ReadTimeOut(buffer, t);
+ }
+
+ public void Dispose()
+ {
+ device.Dispose();
+ }
+
+ private int Write(byte[] buffer)
+ {
+ return device.Write(buffer);
+ }
+
+ private int Read(byte[] buffer)
+ {
+ int total = 0;
+ var smallbuffer = new byte[8];
+ while (total < buffer.Length)
+ {
+ int intToRead = Math.Min(buffer.Length - total, smallbuffer.Length);
+ int len = device.Read(smallbuffer, intToRead);
+ if (len == 0)
+ break;
+ Array.Copy(smallbuffer, 0, buffer, total, len);
+ total += len;
+ }
+ return total;
+ }
+
+ public int ReadBlock(ushort intAdres, byte[] buffer)
+ {
+ var send = new byte[] { ReadCommand, (byte)(intAdres >> 8), (byte)(intAdres & 0xff), EndMark, ReadCommand, (byte)(intAdres >> 8), (byte)(intAdres & 0xff), EndMark };
+
+ var len = Write(send);
+ if (len != send.Length)
+ return 0;
+ return Read(buffer);
+ }
+
+ public bool WriteByte(ushort adres, byte b)
+ {
+ var send = new byte[] { WriteCommand, (byte)(adres >> 8), (byte)(adres & 0xff), EndMark, WriteCommandWord, b, Zero, EndMark };
+
+ var len = Write(send);
+ if (len != send.Length)
+ return false;
+
+ var buffer = new byte[8];
+ var intRead = Read(buffer);
+ if (intRead == 0)
+ return false;
+
+ for (int intI = 0; intI < buffer.Length; intI++)
+ {
+ if (buffer[intI] != Acknowledge)
+ return false;
+ }
+ return true;
+ }
+
+ }
+}