Error Codes#
Complete error catalog — All error messages, causes, and recovery strategies. Includes detection patterns and best practices for robust error handling in DSI API applications.
If you are new to the DSI API, please start with the Getting Started Guide and refer to the Quick Reference for function lookups. If an error occurs that you cannot resolve, please contact Wearable Sensing support via the contact page.
Table of Contents#
Error System Overview#
The DSI API uses a global error string system for error reporting:
Error Propagation Flow#
Setting Errors: Internal functions set a global error string when errors occur
Checking Errors: Call
DSI_Error()to check if an error occurred (non-destructive)Clearing Errors: Call
DSI_ClearError()to retrieve and clear the error stateCallbacks: Set
DSI_SetErrorCallback()for automatic error notifications
Key Functions#
const char* DSI_Error(void) // Check error (non-destructive)
const char* DSI_ClearError(void) // Retrieve and clear error
void DSI_SetErrorCallback(DSI_MessageCallback func) // Register error callback
Error Callback Signature#
typedef int (*DSI_MessageCallback)(const char* msg, int debugLevel);
// debugLevel values:
// 0 = Critical
// 1 = Error
// 2 = Warning
// 3 = Info
// 4 = Debug
Error Categories#
Errors are organized by functional area to help quickly identify the source of problems. Each category includes the error message, root cause, and recommended recovery steps.
Connection Errors#
Serial port and communication errors that occur during device connection and data transmission.
Error Message |
Cause |
Recovery |
|---|---|---|
|
Serial port doesn’t exist |
Verify port name, check device connection |
|
Port already opened by another process |
Close other applications, use different port |
|
No response from headset within timeout period |
Check cables, power, try reconnecting |
|
Headset connected but not communicating |
Power cycle headset, check battery |
|
Connected device is not a DSI headset |
Verify correct device, check firmware |
|
Cannot initialize Bluetooth subsystem |
Check Bluetooth drivers, permissions |
|
No default port configured |
Provide explicit port name or set DSISerialPort |
|
Attempted operation on closed port |
Connect first using |
|
Commands sent before connection |
Wait for connection to complete |
|
Read attempted before connection |
Ensure |
Detection Pattern:
// Helper function for error checking (from demo.c)
int CheckError(void) {
if (DSI_Error()) return fprintf(stderr, "%s\n", DSI_ClearError());
else return 0;
}
#define CHECK if (CheckError() != 0) return -1;
// Use in connection code
DSI_Headset h = DSI_Headset_New(NULL); CHECK
DSI_Headset_Connect(h, "COM3"); CHECK
// Or check explicitly without macro
DSI_Headset_Connect(h, "COM4");
if (DSI_Error()) {
fprintf(stderr, "Connection failed: %s\n", DSI_ClearError());
// Try alternative approach
}
Configuration Errors#
Errors from setting up channels, montages, sampling rates, and device features.
Error Message |
Cause |
Recovery |
|---|---|---|
|
Requested rate not supported by hardware |
Use model-appropriate rate (DSI-7: 300Hz, DSI-24: up to 1200Hz) |
|
Filter mode not recognized |
Use valid filter mode (0-3) |
|
Feature not available on this model |
Check |
|
Malformed channel specification |
Check syntax: “Ch1,Ch2,Ch3” or “Ch1-Ch2” |
|
Parsing error in montage string |
Verify electrode names, check separator usage |
|
Electrode name doesn’t exist |
Use |
|
Name doesn’t match any known sensors |
Check spelling, verify source is active |
|
Ambiguous electrode specification |
Use full unique name or index |
|
Source index out of range |
Use index 1 to N (not 0-based) |
|
Invalid bipolar/reference combination |
Verify both sources exist and are compatible |
|
Naming conflict |
Choose different name or rename conflicting source |
|
Ambiguous alias specification |
Use unique identifiers |
|
Invalid naming scheme |
Use “10-20”, “BIOSEMI”, “NUMBERED”, or “FACTORY” |
|
Invalid common mode reference selection |
Use valid sensor index for reference |
|
Incomplete calibration read |
Read all pages before writing |
|
Calibration page out of range |
Use valid page index |
|
Headset rejected accelerometer configuration |
Use supported rate (0, 10, 50, 100 Hz) |
Detection Pattern:
// Helper function for error checking (from demo.c)
int CheckError(void) {
if (DSI_Error()) return fprintf(stderr, "%s\n", DSI_ClearError());
else return 0;
}
#define CHECK if (CheckError() != 0) return -1;
// Use CHECK macro for montage configuration
DSI_Headset_ChooseChannels(h, "P3,Pz,P4", "A1+A2", 1); CHECK
// Or check explicitly for troubleshooting
DSI_Headset_ChooseChannels(h, "P3,Pz,P4", "A1+A2", 1);
if (DSI_Error()) {
fprintf(stderr, "Montage error: %s\n", DSI_ClearError());
// List available sources using iteration pattern
fprintf(stderr, "Available sources:\n");
int n = DSI_Headset_GetNumberOfSources(h);
for (int i = 0; i < n; i++) {
DSI_Source src = DSI_Headset_GetSourceByIndex(h, i);
fprintf(stderr, " %s\n", DSI_Source_GetName(src));
}
// Try simpler montage
DSI_Headset_ChooseChannels(h, "@1,@2,@3,@4", "@A1+@A2", 1);
}
Runtime Errors#
Errors that occur during active data acquisition, including buffer management and data integrity issues.
Error Message |
Cause |
Recovery |
|---|---|---|
|
Data arriving faster than being read |
Increase buffer size, optimize processing |
|
Attempted to read from empty buffer |
Wait for samples, check acquisition status |
|
Buffer not initialized |
Call |
|
LookBack exceeds buffer capacity |
Increase buffer size or reduce lookback |
|
Not enough samples buffered yet |
Wait for more samples to accumulate |
|
Packet checksum failed |
Check cables, reduce EMI, replace cable |
|
Data packet corrupted |
Verify signal integrity, check grounding |
|
Unexpected packet length |
May indicate firmware/API mismatch |
|
Headset rejected command |
Check command validity for this model |
|
Exceeded retry limit (20 attempts) |
Power cycle headset, check communication |
|
Low-level write failure |
Check USB connection, drivers, permissions |
|
Partial transmission |
Retry command, check port stability |
|
USB communication failure |
Reconnect cable, check USB hub/port |
Detection Pattern:
// Monitor buffer health
size_t overflow = DSI_Headset_GetNumberOfOverflowedSamples(h);
if (overflow > 0) {
fprintf(stderr, "WARNING: Lost %zu samples!\n", overflow);
// Increase buffer
DSI_Headset_StopBackgroundAcquisition(h);
DSI_Headset_ReallocateBuffers(h, 20.0, 0.0); // 20 seconds
DSI_Headset_FlushBuffers(h);
DSI_Headset_StartBackgroundAcquisition(h);
}
// Check for data corruption
const char* err = DSI_Error();
if (err && strstr(err, "CRC")) {
fprintf(stderr, "Data corruption detected: %s\n", err);
DSI_ClearError();
// Log incident, continue acquisition
}
Resource Errors#
System resource allocation failures including memory, threads, and OS primitives.
Error Message |
Cause |
Recovery |
|---|---|---|
|
Out of memory |
Reduce buffer sizes, close other applications |
|
Cannot create background thread |
Check system resources, thread limits |
|
Insufficient memory for buffers |
Use smaller buffer sizes |
|
Windows timer creation failed |
Check system resources, restart application |
|
Windows timer configuration failed |
Verify timer parameters, check permissions |
|
Windows synchronization primitive failed |
Check system state, restart application |
|
NULL pointer passed to C interface |
Verify handle validity before function calls |
Detection Pattern:
int allocateBuffers(DSI_Headset h, double seconds) {
DSI_Headset_ReallocateBuffers(h, seconds, 0.0);
if (DSI_Error()) {
fprintf(stderr, "Buffer allocation failed: %s\n", DSI_ClearError());
// Try smaller buffer
double reduced = seconds / 2.0;
fprintf(stderr, "Trying smaller buffer: %.1f seconds\n", reduced);
DSI_Headset_ReallocateBuffers(h, reduced, 0.0);
if (DSI_Error()) {
fprintf(stderr, "Cannot allocate even minimal buffer\n");
return 0;
}
}
return 1;
}
File I/O Errors#
Errors related to reading and writing calibration files and other persistent data.
Error Message |
Cause |
Recovery |
|---|---|---|
|
Cannot write calibration file |
Check permissions, disk space, path validity |
|
Cannot read calibration file |
Verify file exists, check permissions |
|
Calibration file read error |
Verify file format, check for corruption |
|
Calibration file format error |
Re-export calibration from headset |
|
Binary calibration file corrupted |
Use backup calibration file |
|
Invalid calibration file format |
Check file header, use correct format |
|
Invalid format specifier |
Use “DEC”, “HEX”, or “BIN” |
Detection Pattern:
const char* calFile = "calibration.bin";
if (!readCalibration(h, calFile)) {
fprintf(stderr, "Calibration read failed: %s\n", DSI_ClearError());
// Try alternative formats
const char* formats[] = {"calibration.dec", "calibration.hex", NULL};
for (int i = 0; formats[i]; i++) {
if (readCalibration(h, formats[i])) {
fprintf(stderr, "Loaded from %s\n", formats[i]);
break;
}
DSI_ClearError();
}
}
Index/Range Errors#
Array bounds and lookup errors when accessing channels, sources, or processing stages.
Error Message |
Cause |
Recovery |
|---|---|---|
|
Channel index exceeds count |
Use valid index 0 to M-1 |
|
Source index exceeds count |
Use valid index 0 to M-1 |
|
Stage index exceeds count |
Verify stage count before access |
|
Stage-specific channel index error |
Check channel count for specific stage |
|
Stage name not found |
Use correct stage name from creation |
|
Duplicate stage name |
Use unique stage names |
Detection Pattern:
int nChannels = DSI_Headset_GetNumberOfChannels(h);
printf("Available channels: %d\n", nChannels);
for (int i = 0; i < nChannels; i++) {
DSI_Channel ch = DSI_Headset_GetChannelByIndex(h, i);
if (!ch) {
fprintf(stderr, "Invalid channel index %d: %s\n",
i, DSI_ClearError());
break;
}
printf("Channel %d: %s\n", i, DSI_Channel_GetName(ch));
}
Error Detection Patterns#
Proven code patterns for detecting and handling errors in DSI API applications. These patterns demonstrate the best practices used in demo.c and recommended for production code.
Pattern 1: Check After Critical Operations#
The most basic pattern: check errors immediately after operations that could fail.
DSI_Headset h = DSI_Headset_New(NULL);
if (!h) {
fprintf(stderr, "Failed to create headset: %s\n", DSI_ClearError());
return -1;
}
DSI_Headset_Connect(h, "COM3");
if (DSI_Error()) {
fprintf(stderr, "Connection failed: %s\n", DSI_ClearError());
DSI_Headset_Delete(h);
return -1;
}
DSI_Headset_ChooseChannels(h, "P3,Pz,P4,O1,O2", "A1+A2", 1);
if (DSI_Error()) {
fprintf(stderr, "Montage error: %s\n", DSI_ClearError());
// Try alternative montage
}
Pattern 2: Callback for Automatic Logging#
Register a callback to receive all errors automatically, useful for comprehensive logging.
int errorLogger(const char* msg, int level) {
const char* levelStr[] = {"CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"};
fprintf(stderr, "[%s] %s\n",
level < 5 ? levelStr[level] : "UNKNOWN",
msg);
// Log to file
FILE* f = fopen("dsi_errors.log", "a");
if (f) {
time_t now = time(NULL);
fprintf(f, "%s [%s] %s\n",
ctime(&now),
levelStr[level],
msg);
fclose(f);
}
return 1; // Continue execution
}
DSI_SetErrorCallback(errorLogger);
Pattern 3: Validate Return Values#
Always verify pointer returns before dereferencing, as NULL indicates failure.
DSI_Channel ch = DSI_Headset_GetChannelByName(h, "Pz");
if (!ch) {
const char* err = DSI_Error();
if (err) {
fprintf(stderr, "Channel error: %s\n", err);
DSI_ClearError();
} else {
fprintf(stderr, "Channel 'Pz' not found (no error set)\n");
}
}
Pattern 4: Monitor Buffer Overflow#
Proactively monitor and respond to buffer overflow conditions during acquisition.
void monitorBuffers(DSI_Headset h) {
size_t overflow = DSI_Headset_GetNumberOfOverflowedSamples(h);
if (overflow > 0) {
fprintf(stderr, "WARNING: Lost %zu samples!\n", overflow);
// Calculate time lost
double fs = DSI_Headset_GetSamplingRate(h);
double timeLost = overflow / fs;
fprintf(stderr, "Time lost: %.3f seconds\n", timeLost);
// Increase buffer size
DSI_Headset_StopBackgroundAcquisition(h);
DSI_Headset_ReallocateBuffers(h, 20.0, 0.0); // 20 seconds
DSI_Headset_FlushBuffers(h);
DSI_Headset_StartBackgroundAcquisition(h);
fprintf(stderr, "Buffer increased to 20 seconds\n");
}
}
// Call periodically during acquisition
while (acquiring) {
DSI_Sleep(5.0);
monitorBuffers(h);
}
Pattern 5: Monitor Buffer Overflow#
void checkForProblems(DSI_Headset h) {
// Check for API errors
const char* err = DSI_Error();
if (err) {
fprintf(stderr, "API Error: %s\n", err);
DSI_ClearError();
}
// Check for buffer overflow
size_t overflow = DSI_Headset_GetNumberOfOverflowedSamples(h);
if (overflow > 0) {
fprintf(stderr, "Buffer overflow: %zu samples lost\n", overflow);
// Increase buffer size
DSI_Headset_StopBackgroundAcquisition(h);
DSI_Headset_ReallocateBuffers(h, 20.0, 0.0);
DSI_Headset_FlushBuffers(h);
DSI_Headset_StartBackgroundAcquisition(h);
}
}
Best Practices#
Essential guidelines for robust error handling in production DSI applications. Following these practices will prevent most common errors and make debugging easier when issues occur.
1. Always Check Critical Operations#
Never assume operations succeed—verify every critical function call.
// BAD - No error checking
DSI_Headset h = DSI_Headset_New(NULL);
DSI_Headset_Connect(h, "COM3");
DSI_Headset_ChooseChannels(h, "P3,Pz,P4", "A1+A2", 1);
// GOOD - Comprehensive error checking
DSI_Headset h = DSI_Headset_New(NULL);
if (!h) {
fprintf(stderr, "Failed: %s\n", DSI_ClearError());
return -1;
}
DSI_Headset_Connect(h, "COM3");
if (DSI_Error()) {
fprintf(stderr, "Connection failed: %s\n", DSI_ClearError());
DSI_Headset_Delete(h);
return -1;
}
DSI_Headset_ChooseChannels(h, "P3,Pz,P4", "A1+A2", 1);
if (DSI_Error()) {
fprintf(stderr, "Montage error: %s\n", DSI_ClearError());
DSI_Headset_Delete(h);
return -1;
}
2. Use Error Callback for Real-Time Monitoring#
Set up callbacks to catch errors in background threads and asynchronous operations.
int errorHandler(const char* msg, int level) {
if (level <= 1) { // Critical and errors only
fprintf(stderr, "[ERROR] %s\n", msg);
// Set flag for main loop to check
extern volatile int errorOccurred;
errorOccurred = 1;
}
return 1; // Continue execution
}
DSI_SetErrorCallback(errorHandler);
3. Validate Pointers Before Use#
Check for NULL pointers before dereferencing to avoid crashes.
DSI_Channel ch = DSI_Headset_GetChannelByName(h, "Pz");
if (ch) {
double val = DSI_Channel_GetSignal(ch);
// Use val safely
} else {
fprintf(stderr, "Channel 'Pz' not found\n");
}
4. Monitor System Health#
Track buffer status, lost samples, and system alarms to detect degradation early.
typedef struct {
size_t samplesReceived;
size_t samplesLost;
size_t alarmsReceived;
time_t lastCheck;
} HealthStats;
void updateHealth(DSI_Headset h, HealthStats* stats) {
size_t buffered = DSI_Headset_GetNumberOfBufferedSamples(h);
size_t overflow = DSI_Headset_GetNumberOfOverflowedSamples(h);
size_t alarms = DSI_Headset_GetNumberOfAlarms(h);
stats->samplesReceived = buffered;
stats->samplesLost += overflow;
stats->alarmsReceived += alarms;
stats->lastCheck = time(NULL);
// Log if problems detected
if (overflow > 0) {
fprintf(stderr, "Health: Lost %zu samples (total: %zu)\n",
overflow, stats->samplesLost);
}
if (alarms > 0) {
fprintf(stderr, "Health: %zu new alarms (total: %zu)\n",
alarms, stats->alarmsReceived);
}
}
5. Implement Graceful Degradation#
Retry failed operations and provide fallback options when possible.
int connectWithRetry(DSI_Headset h, const char* port, int maxRetries) {
for (int i = 0; i < maxRetries; i++) {
DSI_Headset_Connect(h, port);
if (!DSI_Error()) {
printf("Connected successfully\n");
return 1;
}
fprintf(stderr, "Attempt %d failed: %s\n",
i + 1, DSI_ClearError());
if (i < maxRetries - 1) {
fprintf(stderr, "Retrying in 2 seconds...\n");
DSI_Sleep(2.0);
}
}
fprintf(stderr, "Failed to connect after %d attempts\n", maxRetries);
return 0;
}
Common Error Scenarios#
Real-world error situations with complete diagnostic and recovery code. These scenarios demonstrate how to handle the most frequently encountered problems.
Scenario 1: Port Already in Use#
Error: "Port in use"
Cause: Another application is using the serial port
Solution:
// Try environment variable first (DSISerialPort)
DSI_Headset_Connect(h, NULL);
if (!DSI_Error()) {
printf("Connected using DSISerialPort environment variable\n");
return;
}
fprintf(stderr, "Env variable failed: %s\n", DSI_ClearError());
// Try specific ports
const char* ports[] = {"COM3", "COM4", "COM5", "COM6", NULL};
for (int i = 0; ports[i]; i++) {
printf("Trying %s...\n", ports[i]);
DSI_Headset_Connect(h, ports[i]);
if (!DSI_Error()) {
printf("Connected to %s\n", ports[i]);
return;
}
fprintf(stderr, "Failed: %s\n", DSI_ClearError());
}
fprintf(stderr, "No available ports found\n");
Scenario 2: Unsupported Sampling Rate#
Handling hardware-specific sampling rate limitations and feature locks.
Error: "Invalid sampling rate"
Cause: Requested sampling rate not supported by hardware model, or feature not unlocked
Solution:
// Check if custom sampling rates are available
if (!DSI_Headset_GetFeatureAvailability(h, "SampleRate")) {
fprintf(stderr, "Custom sampling rates not available (feature locked)\n");
// Use default rate (300 Hz)
DSI_Headset_ConfigureADC(h, 300, 0);
return;
}
const char* info = DSI_Headset_GetInfoString(h);
if (strstr(info, "DSI-7")) {
// DSI-7 supports 300 Hz only
DSI_Headset_ConfigureADC(h, 300, 0);
} else if (strstr(info, "DSI-24")) {
// DSI-24 supports up to 1200 Hz
DSI_Headset_ConfigureADC(h, 600, 0);
} else if (strstr(info, "VR300")) {
// VR300 supports 300 Hz
DSI_Headset_ConfigureADC(h, 300, 0);
}
if (DSI_Error()) {
fprintf(stderr, "ADC config failed: %s\n", DSI_ClearError());
}
Scenario 3: Invalid Montage#
Recovering from electrode name mismatches and montage specification errors.
Error: "Cannot construct channel" or "Source name not found"
Cause: Electrode names don’t match available sources
Solution:
// List available sources using iteration pattern (matches demo.c)
int n = DSI_Headset_GetNumberOfSources(h);
printf("Available sources (%d):\n", n);
for (int i = 0; i < n; i++) {
DSI_Source src = DSI_Headset_GetSourceByIndex(h, i);
printf(" %s\n", DSI_Source_GetName(src));
}
// Try requested montage
DSI_Headset_ChooseChannels(h, "P3,Pz,P4", "A1+A2", 1);
if (DSI_Error()) {
fprintf(stderr, "Montage error: %s\n", DSI_ClearError());
// Use numbered sources as fallback
DSI_Headset_ChooseChannels(h, "@1,@2,@3", "@A1+@A2", 1);
if (!DSI_Error()) {
printf("Using numbered source montage\n");
}
}
Scenario 4: Buffer Overflow#
Dynamically adjusting buffer size when data processing can’t keep pace.
Problem: Buffer overflow during acquisition
Cause: Data arriving faster than application can process
Solution:
void handleBufferOverflow(DSI_Headset h) {
size_t overflow = DSI_Headset_GetNumberOfOverflowedSamples(h);
if (overflow == 0) return;
fprintf(stderr, "Buffer overflow: %zu samples lost\n", overflow);
// Stop acquisition temporarily
DSI_Headset_StopBackgroundAcquisition(h);
// Double buffer size
double currentSize = DSI_Headset_GetNumberOfBufferedSamples(h) /
DSI_Headset_GetSamplingRate(h);
double newSize = currentSize * 2.0;
fprintf(stderr, "Increasing buffer: %.1f → %.1f seconds\n",
currentSize, newSize);
DSI_Headset_ReallocateBuffers(h, newSize, 0.0);
DSI_Headset_FlushBuffers(h);
// Resume acquisition
DSI_Headset_StartBackgroundAcquisition(h);
printf("Acquisition resumed with larger buffer\n");
}
Scenario 5: Data Corruption#
Detecting and responding to signal integrity issues and hardware problems.
Error: "Data corruption (CRC failure)" or "Block failed consistency check"
Cause: EMI, poor cable connection, or hardware issues
Solution:
int corruptionCount = 0;
void monitorDataQuality(DSI_Headset h) {
const char* err = DSI_Error();
if (err && (strstr(err, "CRC") || strstr(err, "consistency"))) {
corruptionCount++;
fprintf(stderr, "Data corruption #%d: %s\n", corruptionCount, err);
DSI_ClearError();
if (corruptionCount > 10) {
fprintf(stderr, "Excessive corruption detected!\n");
fprintf(stderr, "Check: cables, grounding, EMI sources\n");
// Consider stopping acquisition for inspection
DSI_Headset_StopDataAcquisition(h);
}
}
}