Commit e78ab7bd711f736588ad56112b71c8c6af7ed3cb
1 parent
5c0400d5
Samplerate values are calculated now, so every samplerate supported by the hardware is possible
Showing
9 changed files
with
177 additions
and
87 deletions
openhantek/AUTHORS
openhantek/ChangeLog
| ... | ... | @@ -51,3 +51,13 @@ |
| 51 | 51 | * Added zoomed scope and markers to exports |
| 52 | 52 | * Darker default colors for channels in print mode |
| 53 | 53 | * Added enum values for DSO-5200 bulk commands |
| 54 | + | |
| 55 | +2010-08-24 Oliver Haag <oliver.haag@gmail.com> | |
| 56 | +* Documentation of Hantek::Device corrected | |
| 57 | +* Hantek::Device::bulkReadMulti improved | |
| 58 | + | |
| 59 | +2010-08-26 Oliver Haag <oliver.haag@gmail.com> | |
| 60 | +* Samplerate values sent to device are calculated now, only limited by hardware | |
| 61 | +* Added the samplerate formula to the documentation | |
| 62 | +* Documentation updated with additional information from Oleg | |
| 63 | +* Removed Oleg from AUTHORS | ... | ... |
openhantek/mainpage.dox
| ... | ... | @@ -20,7 +20,7 @@ After installing these you can build it by running: |
| 20 | 20 | <pre> |
| 21 | 21 | $ qmake |
| 22 | 22 | $ make |
| 23 | - $ make install | |
| 23 | + $ sudo make install | |
| 24 | 24 | </pre> |
| 25 | 25 | |
| 26 | 26 | \subsection ssec_options Build options |
| ... | ... | @@ -38,7 +38,7 @@ You can set environment variables to set various build options (Done best by pre |
| 38 | 38 | |
| 39 | 39 | \section sec_firmware Installation of the firmware |
| 40 | 40 | \subsection ssec_drivers Gettings the Windows drivers |
| 41 | -Before using OpenHantek you have to extract the firmware from the official Windows drivers. You can get them from the <a href="http://www.hantek.ru/download.html">Hantek website</a> (<a href="http://translate.google.com/translate?sl=ru&tl=en&u=http%3A%2F%2Fwww.hantek.ru%2F">English translation</a>). | |
| 41 | +Before using OpenHantek you have to extract the firmware from the official Windows drivers. You can get them from the <a href="http://www.hantek.ru/download.html">Hantek website</a> (<a href="http://translate.google.com/translate?sl=ru&tl=en&u=http%3A%2F%2Fwww.hantek.ru%2Fdownload.html">English translation</a>). | |
| 42 | 42 | \subsection ssec_dsoextractfw The firmware extraction tool |
| 43 | 43 | You need the tool dsoextractfw from the sourceforge page too extract the firmware. You have to install libbfd development files and build it by typing: |
| 44 | 44 | <pre> | ... | ... |
openhantek/src/hantek/control.cpp
| ... | ... | @@ -42,9 +42,7 @@ namespace Hantek { |
| 42 | 42 | // Values for the Gain and Timebase enums |
| 43 | 43 | this->gainSteps << 0.08 << 0.16 << 0.40 << 0.80 << 1.60 << 4.00 |
| 44 | 44 | << 8.0 << 16.0 << 40.0; |
| 45 | - this->samplerateSteps << 1e8 << 5e7 << 25e6 << 1e7 | |
| 46 | - << 5e6 << 25e5 << 1e6 << 5e5 << 25e4 << 1e5 << 5e4 << 25e3 << 1e4 | |
| 47 | - << 5e3 << 25e2 << 1e3; | |
| 45 | + this->samplerateChannelMax = 50e6; | |
| 48 | 46 | |
| 49 | 47 | // Special trigger sources |
| 50 | 48 | this->specialTriggerSources << tr("EXT") << tr("EXT/10"); |
| ... | ... | @@ -83,10 +81,10 @@ namespace Hantek { |
| 83 | 81 | this->setOffset(channel, 0.5); |
| 84 | 82 | this->setTriggerLevel(channel, 0.0); |
| 85 | 83 | } |
| 86 | - this->setSamplerate(1e6); | |
| 87 | 84 | this->setBufferSize(BUFFER_SMALL); |
| 85 | + this->setSamplerate(1e6); | |
| 88 | 86 | this->setTriggerMode(Dso::TRIGGERMODE_NORMAL); |
| 89 | - this->setTriggerPosition(5e3 / this->samplerateSteps[this->samplerate]); | |
| 87 | + this->setTriggerPosition(5e3 / (this->samplerateMax / this->samplerateDivider)); | |
| 90 | 88 | this->setTriggerSlope(Dso::SLOPE_POSITIVE); |
| 91 | 89 | this->setTriggerSource(false, 0); |
| 92 | 90 | |
| ... | ... | @@ -135,7 +133,26 @@ namespace Hantek { |
| 135 | 133 | for(int control = 0; control < CONTROLINDEX_COUNT; control++) |
| 136 | 134 | this->controlPending[control] = true; |
| 137 | 135 | |
| 138 | - // Get calibration data | |
| 136 | + // Maximum possible samplerate for a single channel | |
| 137 | + switch(this->device->getModel()) { | |
| 138 | + case MODEL_DSO2090: | |
| 139 | + case MODEL_DSO2100: | |
| 140 | + this->samplerateChannelMax = 50e6; | |
| 141 | + break; | |
| 142 | + case MODEL_DSO2150: | |
| 143 | + this->samplerateChannelMax = 75e6; | |
| 144 | + break; | |
| 145 | + case MODEL_DSO2250: | |
| 146 | + case MODEL_DSO5200: | |
| 147 | + case MODEL_DSO5200A: | |
| 148 | + this->samplerateChannelMax = 125e6; | |
| 149 | + break; | |
| 150 | + default: | |
| 151 | + this->samplerateChannelMax = 50e6; | |
| 152 | + break; | |
| 153 | + } | |
| 154 | + | |
| 155 | + // Get channel level data | |
| 139 | 156 | errorCode = this->device->controlRead(CONTROL_VALUE, (unsigned char*) &(this->channelLevels), sizeof(this->channelLevels), (int) VALUE_CHANNELLEVEL); |
| 140 | 157 | if(errorCode < 0) { |
| 141 | 158 | this->device->disconnect(); |
| ... | ... | @@ -146,6 +163,8 @@ namespace Hantek { |
| 146 | 163 | // Adapt offsets |
| 147 | 164 | for(unsigned int channel = 0; channel < HANTEK_CHANNELS; channel++) |
| 148 | 165 | this->setOffset(channel, this->offset[channel]); |
| 166 | + this->setSamplerate(this->samplerateMax / this->samplerateDivider); | |
| 167 | + this->setTriggerPosition(this->triggerPosition); | |
| 149 | 168 | |
| 150 | 169 | // The control loop is running until the device is disconnected |
| 151 | 170 | int captureState = CAPTURE_WAITING; |
| ... | ... | @@ -405,7 +424,7 @@ namespace Hantek { |
| 405 | 424 | } |
| 406 | 425 | |
| 407 | 426 | this->samplesMutex.unlock(); |
| 408 | - emit samplesAvailable(&(this->samples), &(this->samplesSize), this->samplerateSteps[this->samplerate], &(this->samplesMutex)); | |
| 427 | + emit samplesAvailable(&(this->samples), &(this->samplesSize), (double) this->samplerateMax / this->samplerateDivider, &(this->samplesMutex)); | |
| 409 | 428 | } |
| 410 | 429 | |
| 411 | 430 | return 0; |
| ... | ... | @@ -415,13 +434,13 @@ namespace Hantek { |
| 415 | 434 | /// \param size The buffer size that should be met (S). |
| 416 | 435 | /// \return The buffer size that has been set. |
| 417 | 436 | unsigned long int Control::updateBufferSize(unsigned long int size) { |
| 418 | - unsigned int sizeId = (size <= BUFFER_SMALL) ? 1 : 2; | |
| 437 | + BufferSizeId sizeId = (size <= BUFFER_SMALL) ? BUFFERID_SMALL : BUFFERID_LARGE; | |
| 419 | 438 | |
| 420 | 439 | // SetTriggerAndSamplerate bulk command for samplerate |
| 421 | - ((CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE])->setSampleSize(sizeId); | |
| 440 | + ((CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE])->setBufferSize(sizeId); | |
| 422 | 441 | this->commandPending[COMMAND_SETTRIGGERANDSAMPLERATE] = true; |
| 423 | 442 | |
| 424 | - this->bufferSize = (sizeId == 1) ? BUFFER_SMALL : BUFFER_LARGE; | |
| 443 | + this->bufferSize = (sizeId == BUFFERID_SMALL) ? BUFFER_SMALL : BUFFER_LARGE; | |
| 425 | 444 | |
| 426 | 445 | return this->bufferSize; |
| 427 | 446 | } |
| ... | ... | @@ -433,7 +452,7 @@ namespace Hantek { |
| 433 | 452 | this->updateBufferSize(size); |
| 434 | 453 | |
| 435 | 454 | this->setTriggerPosition(this->triggerPosition); |
| 436 | - this->setSamplerate(this->samplerateSteps[this->samplerate]); | |
| 455 | + this->setSamplerate(this->samplerateMax / this->samplerateDivider); | |
| 437 | 456 | this->setTriggerSlope(this->triggerSlope); |
| 438 | 457 | |
| 439 | 458 | return this->bufferSize; |
| ... | ... | @@ -443,47 +462,59 @@ namespace Hantek { |
| 443 | 462 | /// \param samplerate The samplerate that should be met (S/s). |
| 444 | 463 | /// \return The samplerate that has been set. |
| 445 | 464 | unsigned long int Control::setSamplerate(unsigned long int samplerate) { |
| 446 | - // Find lowest supported samplerate thats at least as high as the requested | |
| 447 | - int samplerateId; | |
| 448 | - for(samplerateId = SAMPLERATE_COUNT - 1; samplerateId > 0; samplerateId--) | |
| 449 | - if(this->samplerateSteps[samplerateId] >= samplerate) | |
| 450 | - break; | |
| 451 | - // Fastrate is only possible if we're not using both channels | |
| 452 | - if(samplerateId == SAMPLERATE_100MS && ((CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE])->getUsedChannel() == USED_CH1CH2) | |
| 453 | - samplerateId = SAMPLERATE_50MS; | |
| 454 | - | |
| 455 | - // The values that are understood by the oscilloscope | |
| 456 | - /// \todo Check large buffer values, seem to be crap | |
| 457 | - static const unsigned char valueFastSmall[5] = {0, 1, 2, 3, 4}; | |
| 458 | - static const unsigned char valueFastLarge[5] = {0, 0, 0, 2, 3}; | |
| 459 | - static const unsigned short int valueSlowSmall[13] = {0xfffe, 0xfffc, 0xfff7, 0xffe8, 0xffce, 0xff9c, 0xff07, 0xfe0d, 0xfc19, 0xf63d, 0xec79, 0xd8f1, 0xffed}; | |
| 460 | - static const unsigned short int valueSlowLarge[13] = {0xffff, 0x0000, 0xfffc, 0xfff7, 0xffe8, 0xffce, 0xff9d, 0xff07, 0xfe0d, 0xfc19, 0xf63d, 0xec79, 0xffed}; | |
| 465 | + if(samplerate == 0) | |
| 466 | + return 0; | |
| 461 | 467 | |
| 462 | 468 | // SetTriggerAndSamplerate bulk command for samplerate |
| 463 | 469 | CommandSetTriggerAndSamplerate *commandSetTriggerAndSamplerate = (CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE]; |
| 464 | 470 | |
| 465 | - // Set SamplerateFast bits for high sampling rates | |
| 466 | - if(samplerateId <= SAMPLERATE_5MS) | |
| 467 | - commandSetTriggerAndSamplerate->setSamplerateFast(this->bufferSize == BUFFER_SMALL ? valueFastSmall[samplerateId - SAMPLERATE_100MS] : valueFastLarge[samplerateId - SAMPLERATE_100MS]); | |
| 468 | - else | |
| 469 | - commandSetTriggerAndSamplerate->setSamplerateFast(4); | |
| 471 | + // Calculate with fast rate first if only one channel is used | |
| 472 | + bool fastRate = false; | |
| 473 | + this->samplerateMax = this->samplerateChannelMax; | |
| 474 | + if(((CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE])->getUsedChannel() != USED_CH1CH2) { | |
| 475 | + fastRate = true; | |
| 476 | + this->samplerateMax *= HANTEK_CHANNELS; | |
| 477 | + } | |
| 470 | 478 | |
| 471 | - // Set normal Samplerate value for lower sampling rates | |
| 472 | - if(samplerateId >= SAMPLERATE_10MS) | |
| 473 | - commandSetTriggerAndSamplerate->setSamplerate(this->bufferSize == BUFFER_SMALL ? valueSlowSmall[samplerateId - SAMPLERATE_10MS] : valueSlowLarge[samplerateId - SAMPLERATE_10MS]); | |
| 474 | - else | |
| 475 | - commandSetTriggerAndSamplerate->setSamplerate(0x0000); | |
| 479 | + // The maximum sample rate depends on the buffer size | |
| 480 | + switch(commandSetTriggerAndSamplerate->getBufferSize()) { | |
| 481 | + case BUFFERID_ROLL: | |
| 482 | + this->samplerateMax /= 1000; | |
| 483 | + break; | |
| 484 | + case BUFFERID_LARGE: | |
| 485 | + this->samplerateMax /= 2; | |
| 486 | + break; | |
| 487 | + default: | |
| 488 | + break; | |
| 489 | + } | |
| 490 | + | |
| 491 | + // Get divider that would provide the requested rate, can't be zero | |
| 492 | + this->samplerateDivider = qMax(this->samplerateMax / samplerate, (long unsigned int) 1); | |
| 476 | 493 | |
| 494 | + // Use normal mode if it would meet the rate as exactly as fast rate mode | |
| 495 | + if(fastRate && this->samplerateDivider % HANTEK_CHANNELS == 0) { | |
| 496 | + fastRate = false; | |
| 497 | + this->samplerateMax /= 2; | |
| 498 | + this->samplerateDivider /= HANTEK_CHANNELS; | |
| 499 | + } | |
| 500 | + | |
| 501 | + // Split the resulting divider into the values understood by the device | |
| 502 | + // The fast value is kept at 4 (or 3) for slow sample rates | |
| 503 | + long int valueSlow = qMax(((long int) this->samplerateDivider - 3) / 2, (long int) 0); | |
| 504 | + unsigned char valueFast = this->samplerateDivider - valueSlow * 2; | |
| 505 | + | |
| 506 | + // Store samplerate fast value | |
| 507 | + commandSetTriggerAndSamplerate->setSamplerateFast(valueFast); | |
| 508 | + // Store samplerate slow value (two's complement) | |
| 509 | + commandSetTriggerAndSamplerate->setSamplerateSlow(valueSlow == 0 ? 0 : 0xffff - valueSlow); | |
| 477 | 510 | // Set fast rate when used |
| 478 | - commandSetTriggerAndSamplerate->setFastRate(samplerateId == SAMPLERATE_100MS); | |
| 511 | + commandSetTriggerAndSamplerate->setFastRate(fastRate); | |
| 479 | 512 | |
| 480 | 513 | this->commandPending[COMMAND_SETTRIGGERANDSAMPLERATE] = true; |
| 481 | 514 | |
| 482 | - this->samplerate = (Samplerate) samplerateId; | |
| 483 | - | |
| 484 | 515 | this->updateBufferSize(this->bufferSize); |
| 485 | 516 | this->setTriggerSlope(this->triggerSlope); |
| 486 | - return this->samplerateSteps[samplerateId]; | |
| 517 | + return this->samplerateMax / this->samplerateDivider; | |
| 487 | 518 | } |
| 488 | 519 | |
| 489 | 520 | /// \brief Enables/disables filtering of the given channel. |
| ... | ... | @@ -664,9 +695,12 @@ namespace Hantek { |
| 664 | 695 | return -1; |
| 665 | 696 | |
| 666 | 697 | // SetTriggerAndSamplerate bulk command for trigger position |
| 667 | - ((CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE])->setTriggerSlope((this->bufferSize != BUFFER_SMALL || this->samplerate > SAMPLERATE_10MS || (SAMPLERATE_10MS - this->samplerate) % 2) ? slope : Dso::SLOPE_NEGATIVE - slope); | |
| 698 | + CommandSetTriggerAndSamplerate *commandSetTriggerAndSamplerate = (CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE]; | |
| 699 | + | |
| 700 | + commandSetTriggerAndSamplerate->setTriggerSlope((/*this->bufferSize != BUFFER_SMALL ||*/ commandSetTriggerAndSamplerate->getSamplerateFast() % 2 == 0) ? slope : Dso::SLOPE_NEGATIVE - slope); | |
| 668 | 701 | this->commandPending[COMMAND_SETTRIGGERANDSAMPLERATE] = true; |
| 669 | 702 | |
| 703 | + this->triggerSlope = slope; | |
| 670 | 704 | return 0; |
| 671 | 705 | } |
| 672 | 706 | |
| ... | ... | @@ -677,13 +711,13 @@ namespace Hantek { |
| 677 | 711 | // Calculate the position value (Varying start point, measured in samples) |
| 678 | 712 | //unsigned long int positionRange = (this->bufferSize == BUFFER_SMALL) ? 10000 : 32768; |
| 679 | 713 | unsigned long int positionStart = (this->bufferSize == BUFFER_SMALL) ? 0x77660 : 0x78000; |
| 680 | - unsigned long int positionValue = position * this->samplerateSteps[this->samplerate] + positionStart; | |
| 714 | + unsigned long int positionValue = position * this->samplerateMax / this->samplerateDivider + positionStart; | |
| 681 | 715 | |
| 682 | 716 | // SetTriggerAndSamplerate bulk command for trigger position |
| 683 | 717 | ((CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE])->setTriggerPosition(positionValue); |
| 684 | 718 | this->commandPending[COMMAND_SETTRIGGERANDSAMPLERATE] = true; |
| 685 | 719 | |
| 686 | 720 | this->triggerPosition = position; |
| 687 | - return (double) (positionValue - positionStart) / this->samplerateSteps[this->samplerate]; | |
| 721 | + return (double) (positionValue - positionStart) / this->samplerateMax * this->samplerateDivider; | |
| 688 | 722 | } |
| 689 | 723 | } | ... | ... |
openhantek/src/hantek/control.h
| ... | ... | @@ -81,10 +81,12 @@ namespace Hantek { |
| 81 | 81 | bool controlPending[CONTROLINDEX_COUNT]; ///< true, when the control command should be executed |
| 82 | 82 | |
| 83 | 83 | /// Calibration data for the channel offsets |
| 84 | - unsigned short channelLevels[HANTEK_CHANNELS][GAIN_COUNT][OFFSET_COUNT]; | |
| 84 | + unsigned short int channelLevels[HANTEK_CHANNELS][GAIN_COUNT][OFFSET_COUNT]; | |
| 85 | 85 | |
| 86 | 86 | // Various cached settings |
| 87 | - Samplerate samplerate; ///< The samplerate id | |
| 87 | + unsigned long int samplerateDivider; ///< The samplerate divider | |
| 88 | + unsigned long int samplerateMax; ///< The maximum sample rate for the current setup | |
| 89 | + unsigned long int samplerateChannelMax; ///< The maximum sample rate for a single channel | |
| 88 | 90 | Gain gain[HANTEK_CHANNELS]; ///< The gain id |
| 89 | 91 | double offset[HANTEK_CHANNELS]; ///< The current screen offset for each channel |
| 90 | 92 | double offsetReal[HANTEK_CHANNELS]; ///< The real offset for each channel (Due to quantization) |
| ... | ... | @@ -103,8 +105,6 @@ namespace Hantek { |
| 103 | 105 | |
| 104 | 106 | // Lists for enums |
| 105 | 107 | QList<double> gainSteps; ///< Voltage steps in V/screenheight |
| 106 | - QList<unsigned long int> samplerateSteps; ///< Samplerate steps in S/s | |
| 107 | - QList<unsigned short int> samplerateValues; ///< Values sent to the oscilloscope | |
| 108 | 108 | |
| 109 | 109 | public slots: |
| 110 | 110 | unsigned long int setSamplerate(unsigned long int samplerate); | ... | ... |
openhantek/src/hantek/device.cpp
| ... | ... | @@ -44,6 +44,7 @@ namespace Hantek { |
| 44 | 44 | << 0x5200 << 0x520A; |
| 45 | 45 | this->modelStrings << "DSO-2090" << "DSO-2100" << "DSO-2150" << "DSO-2250" |
| 46 | 46 | << "DSO-5200" << "DSO-5200A"; |
| 47 | + this->model = MODEL_UNKNOWN; | |
| 47 | 48 | |
| 48 | 49 | this->beginCommandControl = new ControlBeginCommand(); |
| 49 | 50 | |
| ... | ... | @@ -283,7 +284,7 @@ namespace Hantek { |
| 283 | 284 | /// \param data Buffer for the sent/recieved data. |
| 284 | 285 | /// \param length The length of the packet. |
| 285 | 286 | /// \param attempts The number of attempts, that are done on timeouts. |
| 286 | - /// \return 0 on success, libusb error code on error. | |
| 287 | + /// \return Number of transferred bytes on success, libusb error code on error. | |
| 287 | 288 | int Device::bulkTransfer(unsigned char endpoint, unsigned char *data, unsigned int length, int attempts) { |
| 288 | 289 | if(!this->handle) |
| 289 | 290 | return LIBUSB_ERROR_NO_DEVICE; |
| ... | ... | @@ -306,7 +307,7 @@ namespace Hantek { |
| 306 | 307 | /// \param data Buffer for the sent/recieved data. |
| 307 | 308 | /// \param length The length of the packet. |
| 308 | 309 | /// \param attempts The number of attempts, that are done on timeouts. |
| 309 | - /// \return 0 on success, libusb error code on error. | |
| 310 | + /// \return Number of sent bytes on success, libusb error code on error. | |
| 310 | 311 | int Device::bulkWrite(unsigned char *data, unsigned int length, int attempts) { |
| 311 | 312 | if(!this->handle) |
| 312 | 313 | return LIBUSB_ERROR_NO_DEVICE; |
| ... | ... | @@ -333,7 +334,7 @@ namespace Hantek { |
| 333 | 334 | /// \param data Buffer for the sent/recieved data. |
| 334 | 335 | /// \param length The length of the packet. |
| 335 | 336 | /// \param attempts The number of attempts, that are done on timeouts. |
| 336 | - /// \return 0 on success, libusb error code on error. | |
| 337 | + /// \return Number of received bytes on success, libusb error code on error. | |
| 337 | 338 | int Device::bulkRead(unsigned char *data, unsigned int length, int attempts) { |
| 338 | 339 | if(!this->handle) |
| 339 | 340 | return LIBUSB_ERROR_NO_DEVICE; |
| ... | ... | @@ -359,7 +360,7 @@ namespace Hantek { |
| 359 | 360 | /// \brief Send a bulk command to the oscilloscope. |
| 360 | 361 | /// \param command The command, that should be sent. |
| 361 | 362 | /// \param attempts The number of attempts, that are done on timeouts. |
| 362 | - /// \return 0 on success, libusb error code on error. | |
| 363 | + /// \return Number of sent bytes on success, libusb error code on error. | |
| 363 | 364 | int Device::bulkCommand(Helper::DataArray<unsigned char> *command, int attempts) { |
| 364 | 365 | if(!this->handle) |
| 365 | 366 | return LIBUSB_ERROR_NO_DEVICE; |
| ... | ... | @@ -377,7 +378,7 @@ namespace Hantek { |
| 377 | 378 | /// \param data Buffer for the sent/recieved data. |
| 378 | 379 | /// \param length The length of data contained in the packets. |
| 379 | 380 | /// \param attempts The number of attempts, that are done on timeouts. |
| 380 | - /// \return 0 on success, libusb error code on error. | |
| 381 | + /// \return Number of received bytes on success, libusb error code on error. | |
| 381 | 382 | int Device::bulkReadMulti(unsigned char *data, unsigned int length, int attempts) { |
| 382 | 383 | if(!this->handle) |
| 383 | 384 | return LIBUSB_ERROR_NO_DEVICE; |
| ... | ... | @@ -388,24 +389,24 @@ namespace Hantek { |
| 388 | 389 | if(errorCode < 0) |
| 389 | 390 | return errorCode; |
| 390 | 391 | |
| 391 | - int packetCount = length / this->inPacketLength; | |
| 392 | - | |
| 393 | 392 | errorCode = this->inPacketLength; |
| 394 | - int packet; | |
| 395 | - for(packet = 0; packet < packetCount && errorCode == this->inPacketLength; packet++) { | |
| 393 | + unsigned int packet, received = 0; | |
| 394 | + for(packet = 0; received < length && errorCode == this->inPacketLength; packet++) { | |
| 396 | 395 | #if LIBUSB_VERSION == 0 |
| 397 | 396 | errorCode = LIBUSB_ERROR_TIMEOUT; |
| 398 | 397 | for(int attempt = 0; (attempt < attempts || attempts == -1) && errorCode == LIBUSB_ERROR_TIMEOUT; attempt++) |
| 399 | - errorCode = usb_bulk_read(this->handle, HANTEK_EP_IN, (char *) data + packet * this->inPacketLength, this->inPacketLength, HANTEK_TIMEOUT); | |
| 398 | + errorCode = usb_bulk_read(this->handle, HANTEK_EP_IN, (char *) data + packet * this->inPacketLength, qMin(length - received, (unsigned int) this->inPacketLength), HANTEK_TIMEOUT); | |
| 400 | 399 | #else |
| 401 | - errorCode = this->bulkTransfer(HANTEK_EP_IN, data + packet * this->inPacketLength, this->inPacketLength, attempts); | |
| 400 | + errorCode = this->bulkTransfer(HANTEK_EP_IN, data + packet * this->inPacketLength, qMin(length - received, (unsigned int) this->inPacketLength), attempts); | |
| 402 | 401 | #endif |
| 402 | + if(errorCode > 0) | |
| 403 | + received += errorCode; | |
| 403 | 404 | } |
| 404 | 405 | |
| 405 | 406 | if(errorCode < 0) |
| 406 | 407 | return errorCode; |
| 407 | 408 | else |
| 408 | - return (packet - 1) * this->inPacketLength + errorCode; | |
| 409 | + return received; | |
| 409 | 410 | } |
| 410 | 411 | |
| 411 | 412 | /// \brief Control transfer to the oscilloscope. |
| ... | ... | @@ -416,7 +417,7 @@ namespace Hantek { |
| 416 | 417 | /// \param value The value field of the packet. |
| 417 | 418 | /// \param index The index field of the packet. |
| 418 | 419 | /// \param attempts The number of attempts, that are done on timeouts. |
| 419 | - /// \return 0 on success, libusb error code on error. | |
| 420 | + /// \return Number of transferred bytes on success, libusb error code on error. | |
| 420 | 421 | int Device::controlTransfer(unsigned char type, unsigned char request, unsigned char *data, unsigned int length, int value, int index, int attempts) { |
| 421 | 422 | if(!this->handle) |
| 422 | 423 | return LIBUSB_ERROR_NO_DEVICE; |
| ... | ... | @@ -441,7 +442,7 @@ namespace Hantek { |
| 441 | 442 | /// \param value The value field of the packet. |
| 442 | 443 | /// \param index The index field of the packet. |
| 443 | 444 | /// \param attempts The number of attempts, that are done on timeouts. |
| 444 | - /// \return 0 on success, libusb error code on error. | |
| 445 | + /// \return Number of sent bytes on success, libusb error code on error. | |
| 445 | 446 | int Device::controlWrite(unsigned char request, unsigned char *data, unsigned int length, int value, int index, int attempts) { |
| 446 | 447 | if(!this->handle) |
| 447 | 448 | return LIBUSB_ERROR_NO_DEVICE; |
| ... | ... | @@ -456,7 +457,7 @@ namespace Hantek { |
| 456 | 457 | /// \param value The value field of the packet. |
| 457 | 458 | /// \param index The index field of the packet. |
| 458 | 459 | /// \param attempts The number of attempts, that are done on timeouts. |
| 459 | - /// \return 0 on success, libusb error code on error. | |
| 460 | + /// \return Number of received bytes on success, libusb error code on error. | |
| 460 | 461 | int Device::controlRead(unsigned char request, unsigned char *data, unsigned int length, int value, int index, int attempts) { |
| 461 | 462 | if(!this->handle) |
| 462 | 463 | return LIBUSB_ERROR_NO_DEVICE; |
| ... | ... | @@ -476,4 +477,10 @@ namespace Hantek { |
| 476 | 477 | |
| 477 | 478 | return response.getSpeed(); |
| 478 | 479 | } |
| 480 | + | |
| 481 | + /// \brief Get the oscilloscope model. | |
| 482 | + /// \return The #Model of the connected Hantek DSO. | |
| 483 | + Model Device::getModel() { | |
| 484 | + return this->model; | |
| 485 | + } | |
| 479 | 486 | } | ... | ... |
openhantek/src/hantek/device.h
| ... | ... | @@ -75,6 +75,7 @@ namespace Hantek { |
| 75 | 75 | int controlRead(unsigned char request, unsigned char *data, unsigned int length, int value = 0, int index = 0, int attempts = HANTEK_ATTEMPTS_DEFAULT); |
| 76 | 76 | |
| 77 | 77 | int getConnectionSpeed(); |
| 78 | + Model getModel(); | |
| 78 | 79 | |
| 79 | 80 | protected: |
| 80 | 81 | // Lists for enums | ... | ... |
openhantek/src/hantek/types.cpp
| ... | ... | @@ -113,12 +113,12 @@ namespace Hantek { |
| 113 | 113 | this->init(); |
| 114 | 114 | |
| 115 | 115 | this->setTriggerSource(triggerSource); |
| 116 | - this->setSampleSize(sampleSize); | |
| 116 | + this->setBufferSize(sampleSize); | |
| 117 | 117 | this->setSamplerateFast(samplerateFast); |
| 118 | 118 | this->setUsedChannel(usedChannel); |
| 119 | 119 | this->setFastRate(fastRate); |
| 120 | 120 | this->setTriggerSlope(triggerSlope); |
| 121 | - this->setSamplerate(samplerate); | |
| 121 | + this->setSamplerateSlow(samplerate); | |
| 122 | 122 | this->setTriggerPosition(triggerPosition); |
| 123 | 123 | } |
| 124 | 124 | |
| ... | ... | @@ -136,13 +136,13 @@ namespace Hantek { |
| 136 | 136 | |
| 137 | 137 | /// \brief Get the sampleSize value in Tsr1Bits. |
| 138 | 138 | /// \return The sampleSize value. |
| 139 | - unsigned char CommandSetTriggerAndSamplerate::getSampleSize() { | |
| 139 | + unsigned char CommandSetTriggerAndSamplerate::getBufferSize() { | |
| 140 | 140 | return ((Tsr1Bits *) &(this->array[2]))->sampleSize; |
| 141 | 141 | } |
| 142 | 142 | |
| 143 | 143 | /// \brief Set the sampleSize in Tsr1Bits to the given value. |
| 144 | 144 | /// \param value The new sampleSize value. |
| 145 | - void CommandSetTriggerAndSamplerate::setSampleSize(unsigned char value) { | |
| 145 | + void CommandSetTriggerAndSamplerate::setBufferSize(unsigned char value) { | |
| 146 | 146 | ((Tsr1Bits *) &(this->array[2]))->sampleSize = value; |
| 147 | 147 | } |
| 148 | 148 | |
| ... | ... | @@ -202,7 +202,7 @@ namespace Hantek { |
| 202 | 202 | |
| 203 | 203 | /// \brief Set the Samplerate to the given value. |
| 204 | 204 | /// \param samplerate The new samplerate value. |
| 205 | - void CommandSetTriggerAndSamplerate::setSamplerate(unsigned short int samplerate) { | |
| 205 | + void CommandSetTriggerAndSamplerate::setSamplerateSlow(unsigned short int samplerate) { | |
| 206 | 206 | this->array[4] = (unsigned char) samplerate; |
| 207 | 207 | this->array[5] = (unsigned char) (samplerate >> 8); |
| 208 | 208 | } | ... | ... |
openhantek/src/hantek/types.h
| ... | ... | @@ -73,8 +73,12 @@ namespace Hantek { |
| 73 | 73 | /// <td>0x00</td> |
| 74 | 74 | /// <td>Tsr1Bits</td> |
| 75 | 75 | /// <td>Tsr2Bits</td> |
| 76 | - /// <td>Samplerate[0]</td> | |
| 77 | - /// <td>Samplerate[1]</td> | |
| 76 | + /// <td>SamplerateValue[0]</td> | |
| 77 | + /// <td>SamplerateValue[1]</td> | |
| 78 | + /// </tr> | |
| 79 | + /// </table> | |
| 80 | + /// <table> | |
| 81 | + /// <tr> | |
| 78 | 82 | /// <td>TriggerPosition[0]</td> |
| 79 | 83 | /// <td>TriggerPosition[1]</td> |
| 80 | 84 | /// <td>0x00</td> |
| ... | ... | @@ -83,6 +87,11 @@ namespace Hantek { |
| 83 | 87 | /// <td>0x00</td> |
| 84 | 88 | /// </tr> |
| 85 | 89 | /// </table> |
| 90 | + /// The samplerate is set relative to the maximum sample rate by a divider that is set in Tsr1Bits.samplerateFast and the 16-bit value in the two SamplerateValue bytes.<br /> | |
| 91 | + /// Without using fast rate mode, the samplerate is:<br /> | |
| 92 | + /// <i>Samplerate = SamplerateMax / (2comp(SamplerateValue) * 2 + Tsr1Bits.samplerateFast)</i><br /> | |
| 93 | + /// SamplerateMax is 50 MHz for the DSO-2090.<br /> | |
| 94 | + /// When using fast rate mode the resulting samplerate is twice as fast, when using the large buffer it is half as fast. When Tsr1Bits.sampleSize is 0 (Roll mode) the sampling rate is divided by 1000. Setting Tsr1Bits.samplerateFast to 0 doesn't work, the result will be the same as Tsr1Bits.samplerateFast = 1. | |
| 86 | 95 | COMMAND_SETTRIGGERANDSAMPLERATE, |
| 87 | 96 | |
| 88 | 97 | /// This command forces triggering: |
| ... | ... | @@ -180,7 +189,7 @@ namespace Hantek { |
| 180 | 189 | /// <tr> |
| 181 | 190 | /// <td>0x08</td> |
| 182 | 191 | /// <td>0x0f</td> |
| 183 | - /// <td>Data</td> | |
| 192 | + /// <td>Data | 0x01</td> | |
| 184 | 193 | /// <td>0x00</td> |
| 185 | 194 | /// <td>0x00</td> |
| 186 | 195 | /// <td>0x00</td> |
| ... | ... | @@ -197,7 +206,7 @@ namespace Hantek { |
| 197 | 206 | /// <td>0x00</td> |
| 198 | 207 | /// </tr> |
| 199 | 208 | /// </table> |
| 200 | - /// The oscilloscope returns the logical data: | |
| 209 | + /// The oscilloscope returns the logical data, which is 64 or 512 bytes long: | |
| 201 | 210 | /// <table> |
| 202 | 211 | /// <tr> |
| 203 | 212 | /// <td>?</td> |
| ... | ... | @@ -233,11 +242,11 @@ namespace Hantek { |
| 233 | 242 | /// <td>0x00</td> |
| 234 | 243 | /// <td>Samplerate[0] (?)</td> |
| 235 | 244 | /// <td>Samplerate[1] (?)</td> |
| 236 | - /// <td>Unknown</td> | |
| 245 | + /// <td>Tsr1.samplerateFast replacement (?)</td> | |
| 237 | 246 | /// <td>0x00</td> |
| 238 | 247 | /// </tr> |
| 239 | 248 | /// </table> |
| 240 | - COMMAND_DSO5200_0C, | |
| 249 | + COMMAND_SETSAMPLERATE5200, | |
| 241 | 250 | |
| 242 | 251 | /// This command seems to set trigger settings for the DSO-5200: |
| 243 | 252 | /// <table> |
| ... | ... | @@ -324,6 +333,10 @@ namespace Hantek { |
| 324 | 333 | /// <td>Ch2Offset[0]</td> |
| 325 | 334 | /// <td>TriggerOffset[1] | 0x20</td> |
| 326 | 335 | /// <td>TriggerOffset[0]</td> |
| 336 | + /// </tr> | |
| 337 | + /// </table> | |
| 338 | + /// <table> | |
| 339 | + /// <tr> | |
| 327 | 340 | /// <td>0x00</td> |
| 328 | 341 | /// <td>0x00</td> |
| 329 | 342 | /// <td>0x00</td> |
| ... | ... | @@ -346,10 +359,18 @@ namespace Hantek { |
| 346 | 359 | /// <td>0x04 ^ (Ch1Gain < 1 V)</td> |
| 347 | 360 | /// <td>0x08 ^ (Ch1Gain < 100 mV)</td> |
| 348 | 361 | /// <td>0x02 ^ (Ch1Coupling == DC)</td> |
| 362 | + /// </tr> | |
| 363 | + /// </table> | |
| 364 | + /// <table> | |
| 365 | + /// <tr> | |
| 349 | 366 | /// <td>0x20 ^ (Ch2Gain < 1 V)</td> |
| 350 | 367 | /// <td>0x40 ^ (Ch2Gain < 100 mV)</td> |
| 351 | 368 | /// <td>0x10 ^ (Ch2Coupling == DC)</td> |
| 352 | 369 | /// <td>0x01 ^ (Trigger == EXT)</td> |
| 370 | + /// </tr> | |
| 371 | + /// </table> | |
| 372 | + /// <table> | |
| 373 | + /// <tr> | |
| 353 | 374 | /// <td>0x00</td> |
| 354 | 375 | /// <td>0x00</td> |
| 355 | 376 | /// <td>0x00</td> |
| ... | ... | @@ -368,9 +389,18 @@ namespace Hantek { |
| 368 | 389 | /// \enum ControlValue hantek/types.h |
| 369 | 390 | /// \brief All supported values for control commands. |
| 370 | 391 | enum ControlValue { |
| 392 | + /// Value 0x08 is the calibration data for the channels offsets. It holds the offset value for the top and bottom of the scope screen for every gain step on every channel. The data is stored as a three-dimensional array:<br /> | |
| 393 | + /// <i>channelLevels[channel][#Gain][#LevelOffset]</i> | |
| 371 | 394 | VALUE_CHANNELLEVEL = 0x08, |
| 372 | - VALUE_DEVICEADDRESS = 0x0A, | |
| 373 | - VALUE_CALIBRATIONDATA = 0x60 | |
| 395 | + | |
| 396 | + /// Value 0x0a is the address of the device. It has a length of one byte. | |
| 397 | + VALUE_DEVICEADDRESS = 0x0a, | |
| 398 | + | |
| 399 | + /// Value 0x60 seems to be some calibration data with a length of four bytes. What it is good for is unknown so far. | |
| 400 | + VALUE_CALIBRATIONDATA = 0x60, | |
| 401 | + | |
| 402 | + /// Value 0x70 is an additional data that is used on the DSO-5200, it's six bytes long. | |
| 403 | + VALUE_UNKNOWN_70 = 0x70 | |
| 374 | 404 | }; |
| 375 | 405 | |
| 376 | 406 | ////////////////////////////////////////////////////////////////////////////// |
| ... | ... | @@ -387,8 +417,8 @@ namespace Hantek { |
| 387 | 417 | /// \enum ConnectionSpeed hantek/types.h |
| 388 | 418 | /// \brief The speed level of the USB connection. |
| 389 | 419 | enum ConnectionSpeed { |
| 390 | - CONNECTION_FULLSPEED = 0, | |
| 391 | - CONNECTION_HIGHSPEED = 1 | |
| 420 | + CONNECTION_FULLSPEED = 0, ///< FullSpeed USB, 64 byte bulk transfers | |
| 421 | + CONNECTION_HIGHSPEED = 1 ///< HighSpeed USB, 512 byte bulk transfers | |
| 392 | 422 | }; |
| 393 | 423 | |
| 394 | 424 | ////////////////////////////////////////////////////////////////////////////// |
| ... | ... | @@ -440,6 +470,15 @@ namespace Hantek { |
| 440 | 470 | }; |
| 441 | 471 | |
| 442 | 472 | ////////////////////////////////////////////////////////////////////////////// |
| 473 | + /// \enum BufferSizeId hantek/types.h | |
| 474 | + /// \brief The size id for CommandSetTriggerAndSamplerate. | |
| 475 | + enum BufferSizeId { | |
| 476 | + BUFFERID_ROLL = 0, | |
| 477 | + BUFFERID_SMALL, | |
| 478 | + BUFFERID_LARGE | |
| 479 | + }; | |
| 480 | + | |
| 481 | + ////////////////////////////////////////////////////////////////////////////// | |
| 443 | 482 | /// \enum CaptureState hantek/types.h |
| 444 | 483 | /// \brief The different capture states which the oscilloscope returns. |
| 445 | 484 | enum CaptureState { |
| ... | ... | @@ -453,10 +492,10 @@ namespace Hantek { |
| 453 | 492 | /// \enum CommandIndex hantek/types.h |
| 454 | 493 | /// \brief Can be set by CONTROL_BEGINCOMMAND, maybe it allows multiple commands at the same time? |
| 455 | 494 | enum CommandIndex { |
| 456 | - COMMANDINDEX_0 = 0x03, | |
| 495 | + COMMANDINDEX_0 = 0x03, ///< Used most of the time | |
| 457 | 496 | COMMANDINDEX_1 = 0x0a, |
| 458 | 497 | COMMANDINDEX_2 = 0x09, |
| 459 | - COMMANDINDEX_3 = 0x01, | |
| 498 | + COMMANDINDEX_3 = 0x01, ///< Used for #COMMAND_SETTRIGGERANDSAMPLERATE sometimes | |
| 460 | 499 | COMMANDINDEX_4 = 0x02, |
| 461 | 500 | COMMANDINDEX_5 = 0x08 |
| 462 | 501 | }; |
| ... | ... | @@ -511,7 +550,7 @@ namespace Hantek { |
| 511 | 550 | struct Tsr1Bits { |
| 512 | 551 | unsigned char triggerSource:2; ///< The trigger source, see Hantek::TriggerSource |
| 513 | 552 | unsigned char sampleSize:3; ///< Buffer size, 0 = Roll, 1 = 10240 S, 2 = 32768 S |
| 514 | - unsigned char samplerateFast:3; ///< samplerate id for fast sampling rates | |
| 553 | + unsigned char samplerateFast:3; ///< samplerate value for fast sampling rates | |
| 515 | 554 | }; |
| 516 | 555 | |
| 517 | 556 | ////////////////////////////////////////////////////////////////////////////// |
| ... | ... | @@ -528,7 +567,7 @@ namespace Hantek { |
| 528 | 567 | struct Tsr2Bits { |
| 529 | 568 | unsigned char usedChannel:2; ///< Used channels, see Hantek::UsedChannels |
| 530 | 569 | unsigned char fastRate:1; ///< true, if one channels uses all buffers |
| 531 | - unsigned char triggerSlope:1; ///< The trigger slope, see Dso::Slope | |
| 570 | + unsigned char triggerSlope:1; ///< The trigger slope, see Dso::Slope, inverted when Tsr1Bits.samplerateFast is uneven | |
| 532 | 571 | unsigned char reserved:4; ///< Unused bits |
| 533 | 572 | }; |
| 534 | 573 | |
| ... | ... | @@ -567,8 +606,8 @@ namespace Hantek { |
| 567 | 606 | |
| 568 | 607 | unsigned char getTriggerSource(); |
| 569 | 608 | void setTriggerSource(unsigned char value); |
| 570 | - unsigned char getSampleSize(); | |
| 571 | - void setSampleSize(unsigned char value); | |
| 609 | + unsigned char getBufferSize(); | |
| 610 | + void setBufferSize(unsigned char value); | |
| 572 | 611 | unsigned char getSamplerateFast(); |
| 573 | 612 | void setSamplerateFast(unsigned char value); |
| 574 | 613 | unsigned char getUsedChannel(); |
| ... | ... | @@ -578,7 +617,7 @@ namespace Hantek { |
| 578 | 617 | unsigned char getTriggerSlope(); |
| 579 | 618 | void setTriggerSlope(unsigned char slope); |
| 580 | 619 | unsigned short int getSamplerate(); |
| 581 | - void setSamplerate(unsigned short int samplerate); | |
| 620 | + void setSamplerateSlow(unsigned short int samplerate); | |
| 582 | 621 | unsigned long int getTriggerPosition(); |
| 583 | 622 | void setTriggerPosition(unsigned long int position); |
| 584 | 623 | ... | ... |