/// <summary> /// /// Constructor. Sets the class GUID, product & vendor id. /// Predefined values are in DeviceManagerProp.cs. /// </summary> public EPdeviceManager(UInt16 vendor_id, UInt16 product_id) { UsbNotifications = new UsbDevice(); WinUsbNotifications = new WinUsbDevice(); EPdevicesVM = new ObservableCollection<GENdeviceVM>(); _EPdevices = new Collection<GENdevice>(); if (vendor_id != 0) VENDOR_ID = vendor_id; if (product_id != 0) PRODUCT_ID = product_id; }
/// <summary> /// Reads data from the ADS1298 device and produces data frames to be sent live to clients. /// </summary> internal void ReadDataLive() { const UInt32 maxBufferSize = 62208; // Optimal buffer value const UInt32 maxBufferDelay = 15; // Maximum buffer delay in milliseconds UInt32 bufferSize; UInt32 bytesRead = 0; UInt32 sampleFreq; UInt32 frameCounter = 0; // frame sequence number relative to the beginning of the data acquisition UInt32 frameDiff; // Difference to calculate the frames in the current package UInt32 nPackets = 0; //Debug variable to show the numbers of frames generated Byte[] readBuffer; Byte[] writeBuffer = new Byte[USB_PACKET_SIZE]; Boolean success = false, sendSuccess = true; // Select a optimal buffer size (not extending the consts above) WinUsbDevice myWinUsb = new WinUsbDevice(); Stopwatch myStopwatch = new Stopwatch(); long ticksBegin, ticksEnd; double timeStamp, timeDelta; sampleFreq = (UInt32)(HR ? DR_VALUE_HR : DR_VALUE_LP); //bufferSize = (UInt32)((sampleFreq * DATALENGTH * (UInt32)((myWinUsb.pipeTimeout<maxBufferDelay) ? myWinUsb.pipeTimeout : maxBufferDelay )* 0.75) / 1000); //The buffer size is solely determined by the maximum buffer delay that we choose to allow. bufferSize = (UInt32) (DATALENGTH * sampleFreq * maxBufferDelay / 1000); bufferSize = bufferSize > maxBufferSize ? maxBufferSize : bufferSize; readBuffer = new Byte[bufferSize]; _packetQueue = new System.Collections.Concurrent.ConcurrentQueue<RawDataPacket>(); RawDataPacket finalPacket; try { winUsbDev.FlushPipe(PIPE_DATA_IN); // Send start-command to ADS device. writeBuffer[0] = CMD_START; success = winUsbDev.SendBulkData(PIPE_COMMAND_OUT, ref writeBuffer, (UInt32)writeBuffer.Length); // Send start-command to ADS device. if (success) { myStopwatch.Reset(); myStopwatch.Start(); do { // Read some data. ticksBegin = myStopwatch.ElapsedTicks; winUsbDev.ReadBulkData(PIPE_DATA_IN, bufferSize, ref readBuffer, ref bytesRead, ref success); ticksEnd = myStopwatch.ElapsedTicks; timeStamp = (double)ticksBegin / (double)Stopwatch.Frequency; timeDelta = (double)(ticksEnd - ticksBegin) / (double)Stopwatch.Frequency; // Get a proper frame index for our newly read frames // This frame index is 24-bit wide, so at 2000 samples/sec it will // overflow and get back to 0 every 8388 seconds frameDiff=0; for (UInt32 i = 0; i < bytesRead; i += DATALENGTH) { frameCounter = frameCounter & 0x00ffffff; readBuffer[i] = (Byte) ((frameCounter & 0x00ff0000) >> 16); readBuffer[i+1] = (Byte) ((frameCounter & 0x0000ff00) >> 8); readBuffer[i+2] = (Byte) (frameCounter & 0x000000ff); frameCounter++; frameDiff++; } //Here we can create a packet and add it to the frame collection _packetQueue.Enqueue(new RawDataPacket(readBuffer, (Int32)bytesRead, sampleFreq, NumberOfChannels, DATALENGTH, frameDiff, timeStamp, timeDelta)); nPackets++; //We have read a new packet, so we make our listeners aware of it OnNewPacket(EventArgs.Empty); sendSuccess &= success; } while (processingData && bytesRead != 0); //Now we send a special duplicate packet indicating there will be no more packets coming finalPacket=new RawDataPacket(readBuffer, (Int32)bytesRead, sampleFreq, NumberOfChannels, DATALENGTH, frameDiff,timeStamp,timeDelta); finalPacket.lastPacket = true; _packetQueue.Enqueue(finalPacket); OnNewPacket(EventArgs.Empty); //DEBUG Console.Out.WriteLine("{0} packets processed.", nPackets); //DEBUG/ } if (sendSuccess) { writeBuffer[0] = CMD_STOP; success = winUsbDev.SendBulkData(PIPE_COMMAND_OUT, ref writeBuffer, (UInt32)writeBuffer.Length); // Send stop-command to ADS device. } } catch (ThreadAbortException) { throw; } finally { writeBuffer[0] = CMD_STOP; winUsbDev.SendBulkData(PIPE_COMMAND_OUT, ref writeBuffer, (UInt32)writeBuffer.Length); // Send stop-command to ADS device. winUsbDev.ReadBulkData(PIPE_DATA_IN, bufferSize, ref readBuffer, ref bytesRead, ref success); // Read the samples after we stopped the reading process. } }
/* /// <summary> /// Save data from EP device. /// </summary> internal override void SaveData(HDF5group hdf5device) { Int32 rec, data; float[] fWriteBuffer; byte[] readBuffer = new byte[DATALENGTH]; Int32[] iWriteBuffer; UInt64 counter = 0; UInt64[] counterBuffer = new UInt64[1]; // Write raw data to file. if (hdf5device != null) rec = hdf5device.addRecord("EMG RAW", NumberOfChannels, SamplesPerSecond, HDF5group.DataType.INT32, HDF5group.CompressionType.GZIP, 9); else rec = 0; if (memStream != null) { memStream.Position = 0; while (memStream.Read(readBuffer, 0, DATALENGTH) == DATALENGTH) { iWriteBuffer = new Int32[8]; for (UInt32 i = SampleLength, j = 0; i < DATALENGTH; i += SampleLength, j++) { iWriteBuffer[j] = readBuffer[i] << 24 | readBuffer[i + 1] << 16 | readBuffer[i + 2] << 8; iWriteBuffer[j] /= 256; } if (hdf5device != null) hdf5device.getRecord(rec).writeData<Int32>(iWriteBuffer); } } // Write attributes if (hdf5device != null) { hdf5device.getRecord(rec).writeAttribute("Manufacturer", winUsbDev.GetUsbStringDescriptor(winUsbDev.usbDevDescriptor.iManufacturer)); hdf5device.getRecord(rec).writeAttribute("Device name", winUsbDev.GetUsbStringDescriptor(winUsbDev.usbDevDescriptor.iProduct)); hdf5device.getRecord(rec).writeAttribute("Serial number", winUsbDev.GetUsbStringDescriptor(winUsbDev.usbDevDescriptor.iSerialNumber)); hdf5device.getRecord(rec).writeAttribute("Number of channels", NumberOfChannels); hdf5device.getRecord(rec).writeAttribute("Samples / second", SamplesPerSecond); hdf5device.getRecord(rec).writeAttribute("Resolution [Bit]", ResolutionBits); hdf5device.getRecord(rec).writeAttribute("+Vref [mV]", (InputDifferantialVoltagePositive).ToString("R")); hdf5device.getRecord(rec).writeAttribute("-Vref [mV]", (InputDifferantialVoltageNegative).ToString("R")); } // Write data + time to file counter = 0; if (hdf5device != null) rec = hdf5device.addRecord("EMG + timing", NumberOfChannels + 1, SamplesPerSecond, HDF5group.DataType.FLOAT, HDF5group.CompressionType.GZIP, 9); if (memStream != null) { memStream.Position = 0; while (memStream.Read(readBuffer, 0, DATALENGTH) == DATALENGTH) { fWriteBuffer = new float[9]; fWriteBuffer[0] = counter / (float)SamplesPerSecond; for (UInt32 i = SampleLength, j = 1; i < DATALENGTH; i += SampleLength, j++) { data = readBuffer[i] << 24 | readBuffer[i + 1] << 16 | readBuffer[i + 2] << 8; data /= 256; // Analog inputs are full differential if (data > 0) fWriteBuffer[j] = (data * (InputDifferantialVoltagePositive - InputDifferantialVoltageNegative)) / (float)Math.Pow(2, ResolutionBits-1); else if (data < 0) fWriteBuffer[j] = (data * (InputDifferantialVoltagePositive - InputDifferantialVoltageNegative)) / (float)Math.Pow(2, ResolutionBits-1); else fWriteBuffer[j] = 0; switch (j) { case 0: fWriteBuffer[j] /= CH1_GAIN_VALUE; break; case 1: fWriteBuffer[j] /= CH2_GAIN_VALUE; break; case 2: fWriteBuffer[j] /= CH3_GAIN_VALUE; break; case 3: fWriteBuffer[j] /= CH4_GAIN_VALUE; break; case 4: fWriteBuffer[j] /= CH5_GAIN_VALUE; break; case 5: fWriteBuffer[j] /= CH6_GAIN_VALUE; break; case 6: fWriteBuffer[j] /= CH7_GAIN_VALUE; break; case 7: fWriteBuffer[j] /= CH8_GAIN_VALUE; break; default: break; } } if (hdf5device != null) hdf5device.getRecord(rec).writeData<float>(fWriteBuffer); counter++; } } // Write attributes if (hdf5device != null) { hdf5device.getRecord(rec).writeAttribute("Manufacturer", winUsbDev.GetUsbStringDescriptor(winUsbDev.usbDevDescriptor.iManufacturer)); hdf5device.getRecord(rec).writeAttribute("Device name", winUsbDev.GetUsbStringDescriptor(winUsbDev.usbDevDescriptor.iProduct)); hdf5device.getRecord(rec).writeAttribute("Serial number", winUsbDev.GetUsbStringDescriptor(winUsbDev.usbDevDescriptor.iSerialNumber)); hdf5device.getRecord(rec).writeAttribute("Number of channels", NumberOfChannels); hdf5device.getRecord(rec).writeAttribute("Samples / second", SamplesPerSecond); hdf5device.getRecord(rec).writeAttribute("Resolution [Bit]", ResolutionBits); hdf5device.getRecord(rec).writeAttribute("+Vref [mV]", (InputDifferantialVoltagePositive).ToString("R")); hdf5device.getRecord(rec).writeAttribute("-Vref [mV]", (InputDifferantialVoltageNegative).ToString("R")); } // Write sample counter to extra hdf5 record counter = 0; if (hdf5device != null) rec = hdf5device.addRecord("Sample counter", 1, SamplesPerSecond, HDF5group.DataType.UINT64, HDF5group.CompressionType.GZIP, 9); if (memStream != null) { memStream.Position = 0; while (memStream.Read(readBuffer, 0, DATALENGTH) == DATALENGTH) { counterBuffer[0] = (UInt64)(readBuffer[1] << 8 | readBuffer[2]); for (UInt32 i=0; i<(UInt32)(counter/(256*256)); i++) // overflows counterBuffer[0] += (256*256); if (hdf5device != null) hdf5device.getRecord(rec).writeData<UInt64>(counterBuffer); counter++; } } } */ /// <summary> /// Reads data from the ADS1298 device. /// </summary> internal void ReadData() { const UInt32 maxBufferSize = 62208; // Optimal buffer value UInt32 bufferSize; UInt32 bytesRead = 0; Byte[] readBuffer; Byte[] writeBuffer = new Byte[USB_PACKET_SIZE]; Boolean success = false, sendSuccess = true; // Select a optimal buffer size (not extending the consts above) WinUsbDevice myWinUsb = new WinUsbDevice(); bufferSize = (UInt32)((HR ? DR_VALUE_HR : DR_VALUE_LP) * DATALENGTH * (UInt32)(myWinUsb.pipeTimeout * 0.75) / 1000); bufferSize = bufferSize > maxBufferSize ? maxBufferSize : bufferSize; readBuffer = new Byte[bufferSize]; memStream = new MemoryStream(); try { winUsbDev.FlushPipe(PIPE_DATA_IN); // Send start-command to ADS device. writeBuffer[0] = CMD_START; success = winUsbDev.SendBulkData(PIPE_COMMAND_OUT, ref writeBuffer, (UInt32)writeBuffer.Length); // Send start-command to ADS device. if (success) { do { // Read some data. winUsbDev.ReadBulkData(PIPE_DATA_IN, bufferSize, ref readBuffer, ref bytesRead, ref success); memStream.Write(readBuffer, 0, (Int32)bytesRead); sendSuccess &= success; } while (processingData && bytesRead != 0); } if (sendSuccess) { writeBuffer[0] = CMD_STOP; success = winUsbDev.SendBulkData(PIPE_COMMAND_OUT, ref writeBuffer, (UInt32)writeBuffer.Length); // Send stop-command to ADS device. } } catch (ThreadAbortException) { throw; } finally { writeBuffer[0] = CMD_STOP; winUsbDev.SendBulkData(PIPE_COMMAND_OUT, ref writeBuffer, (UInt32)writeBuffer.Length); // Send stop-command to ADS device. winUsbDev.ReadBulkData(PIPE_DATA_IN, bufferSize, ref readBuffer, ref bytesRead, ref success); // Read the samples after we stopped the reading process. } }