C#
🚀 Getting Started
Hardware Connection Guide
Before starting your development, please check out our FAQ for details on turning the device on/off, understanding the LED indicators, and device pairing procedures across all platforms: Device Setup & FAQ.
System Requirements
- OS: Windows 10 build 10.0.15063 or higher.
- IDE: Visual Studio 2019 or newer.
- Target Framework: .NET Framework 4.7.2+ or .NET Core 3.1+ is highly recommended.
Windows Environment Debugging Tips
Windows has significant fragmentation in onboard Bluetooth chips. For reliable connections, your PC's network card LMP (Link Manager Protocol) must be 11.x (Bluetooth 5.2) or higher. Otherwise, you will run into scanner failures and random connection drops. If your machine’s built-in adapter doesn't meet these requirements, we highly recommend purchasing an external USB Bluetooth 5.0/5.2 adapter. Check our Windows Usage Guide for recommendations on specific hardware and driver troubleshooting.
Installation & Integration
Unlike some ecosystems where you'd have to deal with manual unmanaged C++ imports, the OxyZen SDK comes with a ready-to-use NuGet package and a clean C# wrapper.
Integration process:
- Import the C# SDK wrapper project and its native
.dlldependency files. - Under Visual Studio's NuGet Package Manager, restore your project to download any required abstractions.
- Important Check: Make sure your build configuration architecture is explicitly set to
x64. Do NOT useAnyCPU, as relying on generic architecture targets will cause runtime failures when your program attempts to invoke the native 64-bit DLLs.
Core API Reference
BleAPI (Class)
A static gateway meant to initiate scans and discover BLE peripherals around you. (The code retains the Zenlite prefix as it was the product's historical codename):
public static class BleAPI
{
// Start scanning for nearby devices
public static void StartScan(Action<ZenliteDevice> callback);
// Stop scanning
public static void StopScan();
}ZenliteDevice (Class)
The main operational handle for a single OxyZen hardware device. You use this to configure data streams, read battery drops, and manage lifecycles.
public class ZenliteDevice
{
// --- Device Properties ---
public string Name { get; }
public string Address { get; }
public bool IsInPairingMode { get; }
public BLEConnectivity Connectivity { get; }
// --- Connection Management ---
public void SetListener(DeviceManager listener);
public void Connect();
public void Disconnect();
public void Pair(Action<ZenliteDevice, ZenliteError> callback);
// --- Sensor Configurations ---
public void StartEEGStream(EEGSampleRate sampleRate, Action<ZenliteDevice, ZenliteError> callback);
public void StopEEGStream(Action<ZenliteDevice, ZenliteError> callback);
public void StartIMUStream(IMUSampleRate sampleRate, IMUMode mode, Action<ZenliteDevice, ZenliteError> callback);
public void StopIMUStream(Action<ZenliteDevice, ZenliteError> callback);
public void StartPPGStream(PPGReportRate reportRate, PPGMode mode, Action<ZenliteDevice, ZenliteError> callback);
public void StopPPGStream(Action<ZenliteDevice, ZenliteError> callback);
// --- Device Settings ---
public void SetDeviceName(string name, Action<ZenliteDevice, ZenliteError> callback);
public void SetSleepIdleTime(int seconds, Action<ZenliteDevice, ZenliteError> callback);
public void GetSysInfo(Action<ZenliteDevice, ZenliteError> callback);
}DeviceManager (Class)
Usually attached to SetListener(), this class relies on C# Action delegates to hook into all hardware events and data streams.
public class DeviceManager
{
// --- Connection and Hardware States ---
public Action<ZenliteDevice, BLEConnectivity> OnConnectivityChanged;
public Action<ZenliteDevice, BleDeviceInfo> OnDeviceInfo;
public Action<ZenliteDevice, int> OnBatteryLevelChanged;
public Action<ZenliteDevice, ContactState> OnContactStateChanged;
public Action<ZenliteDevice, Orientation> OnOrientationChanged;
// --- High-Speed Sensor Arrays ---
public Action<ZenliteDevice, EEGData> OnEEGData;
public Action<ZenliteDevice, BrainWave> OnBrainWave;
public Action<ZenliteDevice, IMUData> OnIMUData;
public Action<ZenliteDevice, PPGData> OnPPGData;
// --- Computed Insights ---
public Action<ZenliteDevice, float, float, float> OnMeditation;
public Action<ZenliteDevice, SleepStage, float, float> OnSleep;
// --- Expections ---
public Action<ZenliteDevice, ZenliteError> OnError;
}Data Models
EEG (Brainwave Data)
public struct EEGData
{
public uint SequenceNumber; // Sequence number
public float SampleRate; // Sample rate
public float[] Data; // Microvolts array
}BrainWave (Frequency Band Indicators)
public struct BrainWave
{
public float Delta; // 0.5-4 Hz
public float Theta; // 4-8 Hz
public float Alpha; // 8-13 Hz
public float LowBeta; // 13-17 Hz
public float HighBeta; // 17-30 Hz
public float Gamma; // 30-50 Hz
}IMU (Inertial Measurement Unit Data)
public struct IMUData
{
public float[] AccData; // [x, y, z] Accelerometer array
public float[] GyroData; // [x, y, z] Gyroscope array
public float[] EulerAngleData; // [roll, pitch, yaw] Math representation
public float SampleRate; // Rate descriptor
}PPG Data (Heart Rate/SpO2)
public struct PPGData
{
public uint SequenceNumber; // Dropped-packet tracking ID
public float SampleRate; // Sensing rate
public int[] RawData; // Direct optical metrics array
public PPGAlgoData[] AlgoData; // Analyzed outcome array
}
public struct PPGAlgoData
{
public int HeartRate; // Human-readable HR (bpm)
public int SpO2; // Blood Oxygen Saturation (%)
}Enums & Constants
Connectivity
public enum BLEConnectivity
{
Connecting = 0,
Connected = 1,
Disconnecting = 2,
Disconnected = 3
}Physical Contact and Device Orientation
public enum ContactState
{
Unknown = 0,
Off = 1, // Not worn correctly
EEG = 2, // Good EEG contact
All = 3 // Both EEG and PPG have good contact
}
public enum Orientation
{
Unknown = 0,
Upward = 1, // Worn normally
Downward = 2 // Worn upside down
}Troubleshooting & Best Practices
Connection Problems
If you're having trouble discovering or connecting to the device, be sure to check the global troubleshooting section: 👉 Device Setup & FAQ
"Type Initialization Exception" / DLL Missing
Because .NET handles multiple compilation paradigms (x86/x64/Core/Framework), failing to instruct exactly how libraries are imported causes instant runtime dumps.
- Confirm
libzenlite.dllaligns with the C# wrapper's processor target. - As emphasized earlier, check your Visual Studio Solutions platforms settings and switch defaults from
AnyCPUdirectly tox64.
UI Thread Safety in WPF and WinForms
All the action delegates defined under DeviceManager (such as OnEEGData handling arrays) are evaluated inside background worker threads managed by the SDK. If you attempt to pipe incoming data right into a TextBox or your Charting controllers, you will trigger cross-thread access violations resulting in critical application failures.
You must safely pipe these elements using native main thread dispatchers:
- In WPF Environments:
Application.Current.Dispatcher.Invoke(() => { ... }) - In WinForms Environments:
this.Invoke(new Action(() => { ... })) - Because an EEG channel pumps at 256 updates per second minimum, avoid pushing every single array natively back to the UI. Try buffering them inside a Ring Buffer structure to implement clean, batch visual updates, reducing UI render lag.
📖 Complete Integration Example
We provide multiple sample implementations—from console tests to WPF visualization applications.
They demonstrate:
- Thread-safe delegate binding for high-frequency data callbacks.
- Ring Buffer-based rendering for continuous EEG data streams.
- Handling Windows BLE pairing/trust prompts in C#.
Access the open-source sample implementation here:
