public bool Clear(bool wipe) { bool failed = false; // ??? //failed |= OmApi.OM_FAILED(OmApi.OmCommit(deviceId)); failed |= OmApi.OM_FAILED(OmApi.OmSetSessionId(deviceId, 0)); // Clear the session id failed |= OmApi.OM_FAILED(OmApi.OmSetMetadata(deviceId, "", 0)); // No metadata failed |= OmApi.OM_FAILED(OmApi.OmSetDelays(deviceId, OmApi.OM_DATETIME_INFINITE, OmApi.OM_DATETIME_INFINITE)); // Never log failed |= OmApi.OM_FAILED(OmApi.OmSetAccelConfig(deviceId, OmApi.OM_ACCEL_DEFAULT_RATE, OmApi.OM_ACCEL_DEFAULT_RANGE)); // Default configuration failed |= OmApi.OM_FAILED(OmApi.OmEraseDataAndCommit(deviceId, wipe ? OmApi.OM_ERASE_LEVEL.OM_ERASE_WIPE : OmApi.OM_ERASE_LEVEL.OM_ERASE_QUICKFORMAT)); // Erase data and commit //failed |= OmApi.OM_FAILED(OmApi.OmClearDataAndCommit(deviceId)); // Clear data and commit //validData = false; if (!failed) { this.sessionId = 0; this.startTime = OmApi.OmDateTimeUnpack(OmApi.OM_DATETIME_INFINITE); this.stopTime = OmApi.OmDateTimeUnpack(OmApi.OM_DATETIME_INFINITE); } hasChanged = true; om.OnChanged(new OmDeviceEventArgs(this)); return(!failed); }
/** Private constructor (singleton class) */ private Om() { // Register our log callback handler first (before startup) logCallbackDelegate = new OmApi.OmLogCallback(LogCallback); GC.SuppressFinalize(logCallbackDelegate); OmApi.OmSetLogCallback(logCallbackDelegate, IntPtr.Zero); // Register our device callback handler (before startup, so we get the initial set of devices) deviceCallbackDelegate = new OmApi.OmDeviceCallback(DeviceCallback); GC.SuppressFinalize(deviceCallbackDelegate); OmApi.OmSetDeviceCallback(deviceCallbackDelegate, IntPtr.Zero); // Startup the API int result = OmApi.OmStartup(OmApi.OM_VERSION); OmAssert(result, "OmStartup"); /* * // Get the existing device ids * int total = OmApi.OmGetDeviceIds(null, 0); * int[] deviceIds = new int[total]; * int count = OmApi.OmGetDeviceIds(deviceIds, deviceIds.Length); * if (count > deviceIds.Length) { count = deviceIds.Length; } * for (int i = 0; i < count; i++) * { * Console.WriteLine("" + (i + 1) + "/" + count + " = " + deviceIds[i]); * deviceCallbackDelegate(IntPtr.Zero, deviceIds[i], OmApi.OM_DEVICE_STATUS.OM_DEVICE_CONNECTED); * } */ downloadCallbackDelegate = new OmApi.OmDownloadCallback(DownloadCallback); GC.SuppressFinalize(downloadCallbackDelegate); OmApi.OmSetDownloadCallback(downloadCallbackDelegate, IntPtr.Zero); }
/** Dispose handler */ public void Dispose(bool disposing) { if (!disposed) { if (disposing) { // Dispose of any managed resources ; } // Clean up unmanaged resources OmApi.OmShutdown(); // Allow finalizing if (logCallbackDelegate != null) { GC.ReRegisterForFinalize(logCallbackDelegate); } if (deviceCallbackDelegate != null) { GC.ReRegisterForFinalize(deviceCallbackDelegate); } // Disposing complete disposed = true; } }
public void Close() { if (Handle != IntPtr.Zero) { OmApi.OmReaderClose(Handle); Handle = IntPtr.Zero; } }
/** Macro to assert an OmApi value was successful, throws an exception otherwise */ public static void OmAssert(int result, string message = null) { if (OmApi.OM_FAILED(result)) { throw new OmException(result, message); } return; }
// Pos public int Pos() { if (Handle == IntPtr.Zero) { return(0); } return(OmApi.OmReaderDataBlockPosition(Handle)); }
// Seek public bool Seek(int dataBlock) { if (Handle == IntPtr.Zero) { return(false); } return(OmApi.OM_SUCCEEDED(OmApi.OmReaderDataBlockSeek(Handle, dataBlock))); }
// Factory method to open a device data stream public static OmReader Open(uint deviceId) { IntPtr handle = OmApi.OmReaderOpenDeviceData((int)deviceId); if (handle == null) { return(null); } return(new OmReader(Om.Instance, deviceId, handle)); }
// Factory method to open a file public static OmReader Open(string filename) { IntPtr handle = OmApi.OmReaderOpen(filename); if (handle == null) { return(null); } return(new OmReader(Om.Instance, filename, handle)); }
public bool Update() { bool changed = false; DateTime now = DateTime.Now; if (!validData) { bool error = false; int res; // TODO: Error checking res = OmApi.OmGetVersion(deviceId, out firmwareVersion, out hardwareVersion); error |= OmApi.OM_FAILED(res); uint time; res = OmApi.OmGetTime(deviceId, out time); error |= OmApi.OM_FAILED(res); timeDifference = (OmApi.OmDateTimeUnpack(time) - now); uint startTimeValue, stopTimeValue; res = OmApi.OmGetDelays(deviceId, out startTimeValue, out stopTimeValue); error |= OmApi.OM_FAILED(res); startTime = OmApi.OmDateTimeUnpack(startTimeValue); stopTime = OmApi.OmDateTimeUnpack(stopTimeValue); res = OmApi.OmGetSessionId(deviceId, out sessionId); error |= OmApi.OM_FAILED(res); error = false; // Ignore error here as retrying won't help up (log to console) Console.WriteLine("ERROR: Problem fetching data for device: " + deviceId); changed = true; if (!error) { validData = true; } } if (lastBatteryUpdate == DateTime.MinValue || (now - lastBatteryUpdate) > TimeSpan.FromSeconds(60.0f)) { int newBatteryLevel = OmApi.OmGetBatteryLevel(deviceId); lastBatteryUpdate = now; if (newBatteryLevel != batteryLevel) { batteryLevel = newBatteryLevel; changed = true; } } changed |= hasChanged; hasChanged = false; return(changed); }
public DateTime TimeForSample(int i) { if (Handle == IntPtr.Zero) { return(DateTime.MinValue); } ushort fractional = 0x0000; uint timestamp = OmApi.OmReaderTimestamp(Handle, i, out fractional); return(OmApi.OmDateTimeUnpack(timestamp, fractional)); }
public bool SetLed(OmApi.OM_LED_STATE state) { ledColor = state; if (OmApi.OM_FAILED(OmApi.OmSetLed(deviceId, (int)ledColor))) { return(false); } hasChanged = true; om.OnChanged(new OmDeviceEventArgs(this)); return(true); }
private void EnsureMetadataRead() { // Check if already read if (metadata != null) { return; } // Get metadata int deviceIdInt = 0; metadata = OmApi.OmReaderMetadata(Handle, out deviceIdInt, out sessionId); deviceId = (ushort)deviceIdInt; }
public OmDevice(Om om, ushort deviceId) { this.om = om; this.deviceId = deviceId; validData = false; filename = null; try { StringBuilder filenamesb = new StringBuilder(256); if (OmApi.OmGetDataFilename(deviceId, filenamesb) == OmApi.OM_OK) { filename = filenamesb.ToString(); } } catch (Exception) { Console.Error.WriteLine("ERROR: Problem getting data filename for device " + deviceId + "."); } }
public bool SetSessionId(uint sessionId, bool commit) { bool failed = false; failed |= OmApi.OM_FAILED(OmApi.OmSetSessionId(deviceId, sessionId)); if (commit) { failed |= OmApi.OM_FAILED(OmApi.OmCommit(deviceId)); } //validData = false; if (!failed) { this.sessionId = sessionId; } hasChanged = true; om.OnChanged(new OmDeviceEventArgs(this)); return(!failed); }
public bool SyncTime() { DateTime time; DateTime previous = DateTime.Now; while ((time = DateTime.Now) == previous) { volatileTemp = 0; } // Spin until the second rollover (up to 1 second) // ...now set the time. if (OmApi.OM_FAILED(OmApi.OmSetTime(deviceId, OmApi.OmDateTimePack(time)))) { return(false); } timeDifference = TimeSpan.Zero; hasChanged = true; om.OnChanged(new OmDeviceEventArgs(this)); return(true); }
public bool SetInterval(DateTime start, DateTime stop) { bool failed = false; failed |= OmApi.OM_FAILED(OmApi.OmSetDelays(deviceId, OmApi.OmDateTimePack(start), OmApi.OmDateTimePack(stop))); if (!failed) { failed |= OmApi.OM_FAILED(OmApi.OmCommit(deviceId)); } //validData = false; if (!failed) { this.startTime = start; this.stopTime = stop; } hasChanged = true; om.OnChanged(new OmDeviceEventArgs(this)); return(!failed); }
// ReadBlock public short[] ReadBlock() { if (Handle == IntPtr.Zero) { return(new short[0]); } int sampleCount = OmApi.OmReaderNextBlock(Handle); if (sampleCount <= 0) { return(null); } Channels = OmApi.OmReaderGetValue(Handle, OmApi.OM_READER_VALUE_TYPE.OM_VALUE_AXES); SequenceId = (uint)OmApi.OmReaderGetValue(Handle, OmApi.OM_READER_VALUE_TYPE.OM_VALUE_SEQUENCEID); // DWORD @10 offset in block AccelOneG = OmApi.OmReaderGetValue(Handle, OmApi.OM_READER_VALUE_TYPE.OM_VALUE_SCALE_ACCEL); GyroRange = OmApi.OmReaderGetValue(Handle, OmApi.OM_READER_VALUE_TYPE.OM_VALUE_SCALE_GYRO); Light = OmApi.OmReaderGetValue(Handle, OmApi.OM_READER_VALUE_TYPE.OM_VALUE_LIGHT); Temp = OmApi.OmReaderGetValue(Handle, OmApi.OM_READER_VALUE_TYPE.OM_VALUE_TEMPERATURE_MC); Batt = OmApi.OmReaderGetValue(Handle, OmApi.OM_READER_VALUE_TYPE.OM_VALUE_BATTERY_PERCENT); BattRaw = OmApi.OmReaderGetValue(Handle, OmApi.OM_READER_VALUE_TYPE.OM_VALUE_BATTERY_MV); int numValues = sampleCount * Channels; if (numValues > 360) { numValues = 360; } // packed triaxials if (numValues < 0) { numValues = 0; } short[] samples = new short[numValues]; IntPtr buffer = OmApi.OmReaderBuffer(Handle); System.Runtime.InteropServices.Marshal.Copy(buffer, samples, 0, numValues); return(samples); }
// Base constructor protected OmReader(Om om, IntPtr handle) { this.om = om; Handle = handle; // Get data range int dataBlockSize = 0, dataOffsetBlocks = 0, dataNumBlocks = 0; uint startTime = 0, endTime = 0; OmApi.OmReaderDataRange(handle, out dataBlockSize, out dataOffsetBlocks, out dataNumBlocks, out startTime, out endTime); DataBlockSize = dataBlockSize; DataOffsetBlocks = dataOffsetBlocks; DataNumBlocks = dataNumBlocks; StartTime = OmApi.OmDateTimeUnpack(startTime); EndTime = OmApi.OmDateTimeUnpack(endTime); // Defer this //EnsureMetadataRead(); // Seek Seek(0); }
public OmDevice(Om om, uint deviceId) { this.om = om; this.deviceId = deviceId; validData = false; filename = null; port = null; serialId = null; try { StringBuilder filenamesb = new StringBuilder(256); if (OmApi.OmGetDataFilename((int)deviceId, filenamesb) == OmApi.OM_OK) { filename = filenamesb.ToString(); path = Path.GetDirectoryName(filename); } StringBuilder pathsb = new StringBuilder(256); if (OmApi.OmGetDevicePath((int)deviceId, pathsb) == OmApi.OM_OK) { path = pathsb.ToString(); } StringBuilder portsb = new StringBuilder(256); if (OmApi.OmGetDevicePort((int)deviceId, portsb) == OmApi.OM_OK) { port = portsb.ToString(); } StringBuilder serialIdsb = new StringBuilder(256); if (OmApi.OmGetDeviceSerial((int)deviceId, serialIdsb) == OmApi.OM_OK) { serialId = serialIdsb.ToString(); } } catch (Exception) { Console.Error.WriteLine("ERROR: Problem getting data filename for device " + deviceId + "."); } }
// ReadBlock public short[] ReadBlock() { if (Handle == IntPtr.Zero) { return(new short[0]); } int sampleCount = OmApi.OmReaderNextBlock(Handle); if (sampleCount <= 0) { return(null); } short[] samples = new short[sampleCount * 3]; IntPtr buffer = OmApi.OmReaderBuffer(Handle); System.Runtime.InteropServices.Marshal.Copy(buffer, samples, 0, sampleCount * 3); Light = OmApi.OmReaderGetValue(Handle, OmApi.OM_READER_VALUE_TYPE.OM_VALUE_LIGHT); Temp = OmApi.OmReaderGetValue(Handle, OmApi.OM_READER_VALUE_TYPE.OM_VALUE_TEMPERATURE_MC); Batt = OmApi.OmReaderGetValue(Handle, OmApi.OM_READER_VALUE_TYPE.OM_VALUE_BATTERY_PERCENT); BattRaw = OmApi.OmReaderGetValue(Handle, OmApi.OM_READER_VALUE_TYPE.OM_VALUE_BATTERY_MV); return(samples); }
public void CancelDownload() { OmApi.OmCancelDownload(deviceId); }
public void BeginDownloading(string filename, string renameFilename) { downloadFilename = filename; downloadFilenameRename = renameFilename; OmApi.OmBeginDownloading(deviceId, 0, -1, filename); }
public bool Update(int resetIfUnresponsive, bool force = false) { bool changed = false; DateTime now = DateTime.Now; double updateInterval = 30.0; // Usually a 30 second update interval updateInterval = updateInterval + (failedCount * 10.0); updateInterval = Math.Min(updateInterval, 120.0); // At most, 2 minute interval if not communicating if (force || lastUpdate == DateTime.MinValue || (now - lastUpdate) > TimeSpan.FromSeconds(updateInterval)) { int error = 0; //Console.WriteLine("backgroundWorkerUpdate - checking battery for " + this.deviceId + "..."); int newBatteryLevel = OmApi.OmGetBatteryLevel((int)deviceId); lastUpdate = now; if (OmApi.OM_FAILED(newBatteryLevel)) { error |= 0x10; } // Battery level has changed, or first error reading battery level if (newBatteryLevel != batteryLevel || (error != 0 && failedCount == 0)) { batteryLevel = newBatteryLevel; changed = true; } if (error == 0 && !validData) { //Console.WriteLine("backgroundWorkerUpdate - first check for " + this.deviceId + "..."); int res; // TODO: Error checking res = OmApi.OmGetVersion((int)deviceId, out firmwareVersion, out hardwareVersion); error |= (OmApi.OM_FAILED(res) ? 0x01 : 0); uint time; res = OmApi.OmGetTime((int)deviceId, out time); error |= (OmApi.OM_FAILED(res) ? 0x02 : 0); DateTime deviceTime = OmApi.OmDateTimeUnpack(time); timeDifference = (deviceTime - now); // DateTime deviceTime = DateTime.Now + omDevice.TimeDifference; // Caution the user if the battery was allowed to reset // (the RTC clock became reset) DateTime cautionDate = new DateTime(2008, 1, 1, 0, 0, 0); if (deviceWarning < 1 && deviceTime < cautionDate) { deviceWarning = 1; // Completely flattening battery may damage it changed = true; } // Warn the user of likely damaged device if RTC reset less than // 15 minutes ago, yet the device reports >= 70% charge DateTime warningDate = new DateTime(2000, 1, 1, 0, 15, 0); int warningPercent = 70; if (deviceWarning < 2 && deviceTime < warningDate && batteryLevel >= warningPercent) { deviceWarning = 2; // Device battery or RTC may be damaged changed = true; } uint startTimeValue, stopTimeValue; res = OmApi.OmGetDelays((int)deviceId, out startTimeValue, out stopTimeValue); error |= (OmApi.OM_FAILED(res) ? 0x04 : 0); startTime = OmApi.OmDateTimeUnpack(startTimeValue); stopTime = OmApi.OmDateTimeUnpack(stopTimeValue); res = OmApi.OmGetSessionId((int)deviceId, out sessionId); error |= (OmApi.OM_FAILED(res) ? 0x08 : 0); changed = true; if (error == 0) { validData = true; } } if (error != 0) { if (error != 0) { Console.WriteLine("ERROR: Problem fetching data for device: " + deviceId + " (code " + error + ")"); } failedCount++; // Every odd failure, try to reset the device if (resetIfUnresponsive > 0 && (failedCount % resetIfUnresponsive) == 0 && !this.IsDownloading) { Console.WriteLine("NOTE: Resetting device " + deviceId + " (failed " + failedCount + " times)..."); Reset(); } } } changed |= hasChanged; hasChanged = false; return(changed); }
public static volatile int volatileTemp = 0; // Junk to prevent code elimination public bool SyncTime() { uint newTime = 0; // last received timestamp (packed) int retries = 12; do { DateTime previous = DateTime.Now; DateTime time; Console.WriteLine("TIMESYNC-DEBUG: Waiting for roll-over from: " + previous); while ((time = DateTime.Now).Second == previous.Second) { volatileTemp++; } // Busy spin until the second rollover (up to 1 second) // ...now set the time (always to the nearest second) DateTime setTime = new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second); Console.WriteLine("TIMESYNC-DEBUG: Setting time: " + setTime); if (OmApi.OM_FAILED(OmApi.OmSetTime((int)deviceId, OmApi.OmDateTimePack(setTime)))) { Console.WriteLine("TIMESYNC: Failed to write time."); continue; } // Verify that the clock was set as expected if (OmApi.OM_FAILED(OmApi.OmGetTime((int)deviceId, out newTime))) { Console.WriteLine("TIMESYNC: Failed to read time."); continue; } DateTime newDateTime = OmApi.OmDateTimeUnpack(newTime); timeDifference = newDateTime - setTime; Console.WriteLine("TIMESYNC-DEBUG: Received time: " + newDateTime + ", delta: " + timeDifference.TotalMilliseconds + " ms"); if (Math.Abs(timeDifference.TotalMilliseconds) > 3000) { Console.WriteLine("TIMESYNC: Time was not within range: " + (int)timeDifference.TotalSeconds); continue; } Console.WriteLine("TIMESYNC-DEBUG: Set time ok, checking for ticks..."); break; // everything ok } while (--retries > 0); if (retries <= 0) { Console.WriteLine("TIMESYNC: Failed to set time successfully"); return(false); } hasChanged = true; om.OnChanged(new OmDeviceEventArgs(this)); // Verify that the clock is ticking DateTime checkStart = DateTime.Now; for (; ;) { if (OmApi.OM_FAILED(OmApi.OmGetTime((int)deviceId, out uint currentTime))) { Console.WriteLine("TIMESYNC: Failed to read time while checking change."); return(false); // Failed to read time } if (currentTime > newTime && ((DateTime.Now - OmApi.OmDateTimeUnpack(currentTime)).TotalMilliseconds < 5000)) { break; // The clock is ticking and within a few seconds of now } var td = DateTime.Now - checkStart; if (Math.Abs(td.TotalMilliseconds) > 4000) { Console.WriteLine("TIMESYNC: Time is not ticking on device after " + (int)td.TotalSeconds + " sec."); return(false); // The clock is not ticking } } return(true); }
// /*OmDevice*/ public delegate void OmDeviceDownloadCompleteCallback(ushort id, OmApi.OM_DOWNLOAD_STATUS status, string filename); public void DownloadCompleteCallback(ushort id, OmApi.OM_DOWNLOAD_STATUS status, string filename) { string timeNow, type; timeNow = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); type = "DOWNLOAD-OK"; string logLine = "" + timeNow + "," + type + "," + Path.GetFileName(filename); if (downloadDumpFile != null) { for (; ; ) // [dump] { string errorMessage = "Problem while appending to download log file (" + downloadDumpFile + ") - check the folder exists, you have write permission, and the file is not locked open by another process."; try { StreamWriter sw = File.AppendText(downloadDumpFile); sw.WriteLine(logLine); sw.Close(); break; } catch (Exception ex) { errorMessage = errorMessage + "\r\n\r\nDetails: " + ex.Message + ""; Console.WriteLine("Warning: " + errorMessage); } DialogResult ddr = MessageBox.Show(null, errorMessage, "Warning", MessageBoxButtons.RetryCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2); if (ddr != System.Windows.Forms.DialogResult.Retry) { break; } } } }
//TS - TODO - Doesn't check if it is already open or not. public static void Close(OmReader reader) { OmApi.OmReaderClose(reader.Handle); }
public void UpdateDownloadStatus(OmApi.OM_DOWNLOAD_STATUS status, int value) { downloadStatus = status; downloadValue = value; hasChanged = true; om.OnChanged(new OmDeviceEventArgs(this, status)); }
public bool Update(int resetIfUnresponsive, bool force = false) { bool changed = false; DateTime now = DateTime.Now; double updateInterval = 30.0; // Usually a 30 second update interval updateInterval = updateInterval + (failedCount * 10.0); updateInterval = Math.Min(updateInterval, 120.0); // At most, 2 minute interval if not communicating if (force || lastUpdate == DateTime.MinValue || (now - lastUpdate) > TimeSpan.FromSeconds(updateInterval)) { int error = 0; //Console.WriteLine("backgroundWorkerUpdate - checking battery for " + this.deviceId + "..."); int newBatteryLevel = OmApi.OmGetBatteryLevel(deviceId); lastUpdate = now; if (OmApi.OM_FAILED(newBatteryLevel)) { error |= 0x10; } // Battery level has changed, or first error reading battery level if (newBatteryLevel != batteryLevel || (error != 0 && failedCount == 0)) { batteryLevel = newBatteryLevel; changed = true; } if (error == 0 && !validData) { //Console.WriteLine("backgroundWorkerUpdate - first check for " + this.deviceId + "..."); int res; // TODO: Error checking res = OmApi.OmGetVersion(deviceId, out firmwareVersion, out hardwareVersion); error |= (OmApi.OM_FAILED(res) ? 0x01 : 0); uint time; res = OmApi.OmGetTime(deviceId, out time); error |= (OmApi.OM_FAILED(res) ? 0x02 : 0); timeDifference = (OmApi.OmDateTimeUnpack(time) - now); uint startTimeValue, stopTimeValue; res = OmApi.OmGetDelays(deviceId, out startTimeValue, out stopTimeValue); error |= (OmApi.OM_FAILED(res) ? 0x04 : 0); startTime = OmApi.OmDateTimeUnpack(startTimeValue); stopTime = OmApi.OmDateTimeUnpack(stopTimeValue); res = OmApi.OmGetSessionId(deviceId, out sessionId); error |= (OmApi.OM_FAILED(res) ? 0x08 : 0); changed = true; if (error == 0) { validData = true; } } if (error != 0) { if (error != 0) { Console.WriteLine("ERROR: Problem fetching data for device: " + deviceId + " (code " + error + ")"); } failedCount++; // Every odd failure, try to reset the device if (resetIfUnresponsive > 0 && (failedCount % resetIfUnresponsive) == 0 && !this.IsDownloading) { Console.WriteLine("NOTE: Resetting device " + deviceId + " (failed " + failedCount + " times)..."); Reset(); } } } changed |= hasChanged; hasChanged = false; return(changed); }
public bool SetDebug(int debugCode) { int status = OmApi.OmCommand(deviceId, "\r\nDEBUG " + debugCode + "\r\n", null, 0, "DEBUG=", 2000, IntPtr.Zero, 0); return(status >= 0); }
public OmException(int code, string message) : base(OmApi.OmErrorString(code) + " - " + message) { }
public int Reset() { // [DllImport("libomapi.dll")] public static extern int OmCommand(int deviceId, string command, [MarshalAs(UnmanagedType.LPStr)] StringBuilder metadata, int bufferSize, string expected, uint timeoutMs, IntPtr parseParts, int parseMax); // char **parseParts return(OmApi.OmCommand((int)deviceId, "\r\nreset\r\n", (StringBuilder)null, 0, "RESET", (uint)2000, IntPtr.Zero, 0)); }
public bool SetLed(OmApi.OM_LED_STATE state) { ledColor = state; if (OmApi.OM_FAILED(OmApi.OmSetLed(deviceId, (int)ledColor))) { return false; } hasChanged = true; om.OnChanged(new OmDeviceEventArgs(this)); return true; }