├── run_cli.sh ├── run_gui.sh ├── cmake ├── modules │ ├── FindGtkmm.cmake │ ├── FindPThread.cmake │ └── FindLiquidSdr.cmake ├── uninstall.cmake ├── resources.cmake └── uninstall.uninstall_target.cmake.in ├── capture_wifi.pcapng ├── lib ├── connection │ ├── CMakeLists.txt │ ├── Connector.cxx │ ├── TCPConnector.cxx │ └── USBConnector.cxx ├── packets │ ├── CMakeLists.txt │ ├── Sample.cxx │ ├── Packet.cxx │ ├── Command.cxx │ ├── Response.cxx │ └── CommandFactory.cxx ├── config.h.in ├── idso1070.pc.in ├── CMakeLists.txt ├── util.cxx ├── README.md ├── ProtocolWorker.cxx ├── IDSO1070.cxx └── Protocol.cxx ├── include ├── util.h ├── base.h ├── packets │ ├── Sample.h │ ├── SampleBuffer.h │ ├── Response.h │ ├── Packet.h │ ├── Command.h │ └── CommandFactory.h ├── connection │ ├── TCPConnector.h │ ├── USBConnector.h │ └── Connector.h ├── ProtocolWorker.h ├── enums.h ├── IDSO1070.h └── Protocol.h ├── cli ├── CMakeLists.txt └── main.cxx ├── gui ├── resources │ ├── CMakeLists.txt │ └── gui.glade ├── CMakeLists.txt ├── TransmissionLogDialog.h ├── main.cxx ├── AppWindow.h ├── ScopeWidget.h ├── AppWindow.cxx ├── TransmissionLogDialog.cxx ├── SettingsWidget.h ├── ScopeWidget.cxx └── SettingsWidget.cxx ├── .vscode ├── tasks.json ├── launch.json └── c_cpp_properties.json ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md └── capture_wifi2.hexdump /run_cli.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd build/cli 4 | ./idso1070-cli -------------------------------------------------------------------------------- /run_gui.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd build/gui 4 | ./idso1070-gui -------------------------------------------------------------------------------- /cmake/modules/FindGtkmm.cmake: -------------------------------------------------------------------------------- 1 | find_package(PkgConfig) 2 | 3 | pkg_check_modules(GTKMM gtkmm-3.0) -------------------------------------------------------------------------------- /capture_wifi.pcapng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhornbacher/idso1070-protocol/HEAD/capture_wifi.pcapng -------------------------------------------------------------------------------- /lib/connection/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(connection Connector.cxx TCPConnector.cxx USBConnector.cxx) 2 | target_link_libraries (connection) -------------------------------------------------------------------------------- /lib/packets/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(packets Command.cxx CommandFactory.cxx Packet.cxx Sample.cxx Response.cxx) 2 | target_link_libraries (packets) -------------------------------------------------------------------------------- /lib/config.h.in: -------------------------------------------------------------------------------- 1 | // the configured options and settings for libidso1070 2 | #define libidso1070_VERSION_MAJOR @libidso1070_VERSION_MAJOR@ 3 | #define libidso1070_VERSION_MINOR @libidso1070_VERSION_MINOR@ -------------------------------------------------------------------------------- /lib/packets/Sample.cxx: -------------------------------------------------------------------------------- 1 | #include "packets/Sample.h" 2 | 3 | Sample::Sample(uint8_t *data) : Packet(data) 4 | { 5 | } 6 | 7 | Sample::Sample(Response *response) : Packet(response->getHeader()) 8 | { 9 | } 10 | 11 | size_t Sample::getPayloadLength() 12 | { 13 | return IDSO1070::SamplesCountPerPacket; 14 | } -------------------------------------------------------------------------------- /include/util.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_H_ 2 | #define _UTIL_H_ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | float mapValue(int i, float f, float f2, float f3, float f4); 9 | float mapValue(float f, float f2, float f3, float f4, float f5); 10 | string hexdump(uint8_t *data, size_t length, int cols); 11 | 12 | #endif // _UTIL_H_ -------------------------------------------------------------------------------- /cli/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project (idso1070-cli) 2 | 3 | # add liquidsdr 4 | find_package(LiquidSdr REQUIRED) 5 | include_directories(${LIQUIDDSP_INCLUDE_DIRS}) 6 | 7 | add_executable(idso1070-cli main.cxx) 8 | target_link_libraries (idso1070-cli idso1070 ${LIQUIDDSP_LIBRARIES}) 9 | 10 | install (TARGETS idso1070-cli DESTINATION ${CMAKE_INSTALL_BINDIR}) -------------------------------------------------------------------------------- /include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef _BASE_H_ 2 | #define _BASE_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "enums.h" 15 | 16 | using namespace std; 17 | 18 | #endif // _BASE_H_ -------------------------------------------------------------------------------- /gui/resources/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Include resources helper 2 | include("${CMAKE_SOURCE_DIR}/cmake/resources.cmake") 3 | 4 | add_custom_target(gui-resources) 5 | 6 | add_resource(glade_data gui.glade gui-resources) 7 | 8 | add_library(resources ${RESOURCES_OBJECTS}) 9 | set_target_properties(resources PROPERTIES LINKER_LANGUAGE CXX) 10 | add_dependencies(resources gui-resources) -------------------------------------------------------------------------------- /lib/packets/Packet.cxx: -------------------------------------------------------------------------------- 1 | #include "packets/Packet.h" 2 | 3 | Packet::Packet(uint8_t *data) 4 | { 5 | memcpy(&rawPacket, data, PacketSize); 6 | } 7 | 8 | uint8_t *Packet::getHeader() 9 | { 10 | return rawPacket; 11 | } 12 | 13 | uint8_t *Packet::getPayload() 14 | { 15 | return &rawPacket[HeaderSize]; 16 | } 17 | 18 | uint8_t Packet::getCounter() 19 | { 20 | return rawPacket[2]; 21 | } -------------------------------------------------------------------------------- /lib/idso1070.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=@CMAKE_INSTALL_PREFIX@ 3 | libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ 4 | includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ 5 | 6 | Name: @PROJECT_NAME@ 7 | Description: library to communicate with hantek idso1070 digital oscilloscope 8 | Version: @PROJECT_VERSION@ 9 | 10 | Requires: 11 | Libs: -L${libdir} -lidso1070 12 | Cflags: -I${includedir} -------------------------------------------------------------------------------- /include/packets/Sample.h: -------------------------------------------------------------------------------- 1 | #ifndef _SAMPLE_H_ 2 | #define _SAMPLE_H_ 3 | 4 | #include "base.h" 5 | #include "IDSO1070.h" 6 | #include "Packet.h" 7 | #include "Response.h" 8 | 9 | class Sample : public Packet 10 | { 11 | public: 12 | Sample(uint8_t *data); 13 | Sample(Response *response); 14 | 15 | size_t getPayloadLength(); 16 | 17 | private: 18 | uint8_t rawPacket[PacketSize]; 19 | }; 20 | 21 | #endif // _SAMPLE_H_ -------------------------------------------------------------------------------- /cmake/uninstall.cmake: -------------------------------------------------------------------------------- 1 | # uninstall target 2 | # https://cmake.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F 3 | 4 | configure_file( 5 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/uninstall.uninstall_target.cmake.in" 6 | "${CMAKE_CURRENT_BINARY_DIR}/uninstall_target.cmake" 7 | IMMEDIATE @ONLY) 8 | 9 | add_custom_target(uninstall 10 | ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/uninstall_target.cmake 11 | ) -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Build", 8 | "type": "shell", 9 | "command": "${workspaceFolder}/build.sh", 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /include/packets/SampleBuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef _SAMPLE_BUFFER_H_ 2 | #define _SAMPLE_BUFFER_H_ 3 | 4 | #include "base.h" 5 | 6 | #include 7 | 8 | struct SampleBuffer 9 | { 10 | static const int SampleBufferSize = 1024 * 16; 11 | boost::circular_buffer channel1; 12 | boost::circular_buffer channel2; 13 | 14 | SampleBuffer() : channel1(SampleBufferSize), channel2(SampleBufferSize) {} 15 | }; 16 | 17 | #endif // _SAMPLE_BUFFER_H_ -------------------------------------------------------------------------------- /include/packets/Response.h: -------------------------------------------------------------------------------- 1 | #ifndef _RESPONSE_H_ 2 | #define _RESPONSE_H_ 3 | 4 | #include "base.h" 5 | #include "IDSO1070.h" 6 | #include "Packet.h" 7 | 8 | class Response : public Packet 9 | { 10 | public: 11 | Response(uint8_t *data); 12 | 13 | // Copy assignment operator 14 | Response &operator=(Response obj); 15 | 16 | uint8_t getCommandCode(); 17 | CommandType getCommandType(); 18 | 19 | size_t getPayloadLength(); 20 | 21 | private: 22 | uint8_t rawPacket[PacketSize]; 23 | }; 24 | 25 | #endif // _RESPONSE_H_ -------------------------------------------------------------------------------- /include/packets/Packet.h: -------------------------------------------------------------------------------- 1 | #ifndef _PACKET_H_ 2 | #define _PACKET_H_ 3 | 4 | #include "base.h" 5 | 6 | class Packet 7 | { 8 | public: 9 | static const size_t PacketSize = 509; 10 | static const size_t HeaderSize = 7; 11 | static const size_t PayloadSize = PacketSize - HeaderSize; 12 | 13 | Packet(uint8_t *data); 14 | 15 | uint8_t getCounter(); 16 | 17 | uint8_t *getHeader(); 18 | uint8_t *getPayload(); 19 | virtual size_t getPayloadLength() = 0; 20 | 21 | private: 22 | uint8_t rawPacket[PacketSize]; 23 | }; 24 | 25 | #endif // _PACKET_H_ -------------------------------------------------------------------------------- /gui/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project (idso1070-gui) 2 | 3 | add_subdirectory(resources) 4 | 5 | # add gtkmm 6 | find_package(Gtkmm REQUIRED) 7 | include_directories(${GTKMM_INCLUDE_DIRS}) 8 | 9 | # add liquidsdr 10 | find_package(LiquidSdr REQUIRED) 11 | include_directories(${LIQUIDDSP_INCLUDE_DIRS}) 12 | 13 | add_executable(idso1070-gui main.cxx ScopeWidget.cxx SettingsWidget.cxx AppWindow.cxx TransmissionLogDialog.cxx) 14 | target_link_libraries (idso1070-gui idso1070 resources ${GTKMM_LIBRARIES} ${LIQUIDDSP_LIBRARIES}) 15 | 16 | install (TARGETS idso1070-gui DESTINATION ${CMAKE_INSTALL_BINDIR}) -------------------------------------------------------------------------------- /lib/packets/Command.cxx: -------------------------------------------------------------------------------- 1 | #include "packets/Command.h" 2 | 3 | Command::Command(CommandCode cmd, uint8_t param1, uint8_t param2) 4 | { 5 | payload[0] = 0x55; 6 | payload[1] = (uint8_t)cmd; 7 | payload[2] = param1; 8 | payload[3] = param2; 9 | } 10 | 11 | Command::Command(uint8_t *payload) 12 | { 13 | memcpy(this->payload, payload, 4); 14 | } 15 | 16 | uint8_t *Command::getPayload() 17 | { 18 | return payload; 19 | } 20 | 21 | void Command::callResponseHandler() 22 | { 23 | if (responseHandler) 24 | responseHandler(); 25 | } 26 | 27 | void Command::setResponseHandler(ResponseHandler responseHandler) 28 | { 29 | this->responseHandler = responseHandler; 30 | } -------------------------------------------------------------------------------- /include/connection/TCPConnector.h: -------------------------------------------------------------------------------- 1 | #ifndef _TCP_CONNECTOR_H_ 2 | #define _TCP_CONNECTOR_H_ 3 | 4 | #include "Connector.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class TCPConnector : public Connector 14 | { 15 | public: 16 | TCPConnector(string host, int port); 17 | ~TCPConnector(); 18 | 19 | void transmit(uint8_t *data, size_t length); 20 | void receive(); 21 | 22 | void start(); 23 | void stop(); 24 | 25 | ConnectorType getType(); 26 | 27 | private: 28 | int socketHandle; 29 | sockaddr_in serverAddress; 30 | 31 | string host; 32 | int port; 33 | }; 34 | 35 | #endif // _TCP_CONNECTOR_H_ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/c++,cmake 3 | 4 | ### C++ ### 5 | # Prerequisites 6 | *.d 7 | 8 | # Compiled Object files 9 | *.slo 10 | *.lo 11 | *.o 12 | *.obj 13 | 14 | # Precompiled Headers 15 | *.gch 16 | *.pch 17 | 18 | # Compiled Dynamic libraries 19 | *.so 20 | *.dylib 21 | *.dll 22 | 23 | # Fortran module files 24 | *.mod 25 | *.smod 26 | 27 | # Compiled Static libraries 28 | *.lai 29 | *.la 30 | *.a 31 | *.lib 32 | 33 | # Executables 34 | *.exe 35 | *.out 36 | *.app 37 | 38 | ### CMake ### 39 | CMakeCache.txt 40 | CMakeFiles 41 | CMakeScripts 42 | Testing 43 | Makefile 44 | cmake_install.cmake 45 | install_manifest.txt 46 | compile_commands.json 47 | CTestTestfile.cmake 48 | build 49 | 50 | # End of https://www.gitignore.io/api/c++,cmake 51 | 52 | *~ 53 | settings.json -------------------------------------------------------------------------------- /include/connection/USBConnector.h: -------------------------------------------------------------------------------- 1 | #ifndef _USB_CONNECTOR_H_ 2 | #define _USB_CONNECTOR_H_ 3 | 4 | #include "Connector.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class USBConnector : public Connector 14 | { 15 | public: 16 | static const int USBSerialSpeed = B4000000; 17 | 18 | typedef list USBDeviceList; 19 | 20 | USBConnector(string device); 21 | ~USBConnector(); 22 | 23 | void transmit(uint8_t *data, size_t length); 24 | void receive(); 25 | 26 | static void enumerateDevices(USBDeviceList &list); 27 | 28 | void start(); 29 | void stop(); 30 | 31 | ConnectorType getType(); 32 | 33 | private: 34 | string device; 35 | int handle; 36 | }; 37 | 38 | #endif // _USB_CONNECTOR_H_ -------------------------------------------------------------------------------- /cmake/modules/FindPThread.cmake: -------------------------------------------------------------------------------- 1 | find_path(PTHREAD_INCLUDE_DIR 2 | NAMES pthread.h 3 | HINTS $ENV{PTHREAD_DIR}/include 4 | PATHS /usr/local/include 5 | /usr/include ) 6 | 7 | find_library(PTHREAD_LIBRARY 8 | NAMES pthread 9 | HINTS $ENV{PTHREAD_DIR}/lib 10 | PATHS /usr/local/lib 11 | /usr/lib) 12 | 13 | set(PTHREAD_LIBRARIES ${PTHREAD_LIBRARY} ) 14 | set(PTHREAD_INCLUDE_DIRS ${PTHREAD_INCLUDE_DIR} ) 15 | 16 | include(FindPackageHandleStandardArgs) 17 | # handle the QUIETLY and REQUIRED arguments and set PTHREAD_FOUND to TRUE 18 | # if all listed variables are TRUE 19 | find_package_handle_standard_args(pthread DEFAULT_MSG 20 | PTHREAD_LIBRARY PTHREAD_INCLUDE_DIR) 21 | 22 | mark_as_advanced(PTHREAD_INCLUDE_DIR PTHREAD_LIBRARY ) 23 | -------------------------------------------------------------------------------- /lib/packets/Response.cxx: -------------------------------------------------------------------------------- 1 | #include "packets/Response.h" 2 | 3 | Response::Response(uint8_t *data) : Packet(data) 4 | { 5 | memcpy(&rawPacket, data, PacketSize); 6 | } 7 | size_t Response::getPayloadLength() 8 | { 9 | switch (getCommandType()) 10 | { 11 | case TYPE_CONTROL: 12 | return 0x0e; 13 | case TYPE_EEPROM: 14 | return 0x64; 15 | case TYPE_FPGA: 16 | return 0x0e; 17 | case TYPE_STATE: 18 | break; 19 | default: 20 | return 0; 21 | } 22 | size_t pos = PayloadSize - 2; 23 | uint8_t filter = 0x00; 24 | while (getPayload()[pos] == filter) 25 | { 26 | pos--; 27 | } 28 | 29 | return pos + 1; 30 | } 31 | 32 | uint8_t Response::getCommandCode() 33 | { 34 | return rawPacket[4]; 35 | } 36 | 37 | CommandType Response::getCommandType() 38 | { 39 | return (CommandType)rawPacket[3]; 40 | } -------------------------------------------------------------------------------- /include/packets/Command.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMMAND_H_ 2 | #define _COMMAND_H_ 3 | 4 | #include "base.h" 5 | 6 | #include "Response.h" 7 | 8 | class Command 9 | { 10 | public: 11 | static const size_t CommandSize = 4; 12 | typedef function ResponseHandler; 13 | 14 | Command(CommandCode cmd, uint8_t param1 = 0, uint8_t param2 = 0); 15 | Command(uint8_t *payload); 16 | 17 | // Copy assignment operator 18 | Command &operator=(Command obj); 19 | 20 | uint8_t *getPayload(); 21 | 22 | void callResponseHandler(); 23 | 24 | void setResponseHandler(ResponseHandler responseHandler); 25 | 26 | template 27 | void setResponseHandler(S *self, F &&f) 28 | { 29 | setResponseHandler(bind(f, self, placeholders::_1)); 30 | } 31 | 32 | private: 33 | uint8_t payload[CommandSize]; 34 | 35 | ResponseHandler responseHandler; 36 | }; 37 | 38 | #endif // _COMMAND_H_ -------------------------------------------------------------------------------- /lib/connection/Connector.cxx: -------------------------------------------------------------------------------- 1 | #include "connection/Connector.h" 2 | 3 | Connector::Connector() : rawBuffer(RawBufferLength) 4 | { 5 | } 6 | 7 | Response *Connector::getLatestResponse() 8 | { 9 | Response *response = responseBuffer.front(); 10 | responseBuffer.pop(); 11 | return response; 12 | } 13 | 14 | size_t Connector::getResponseBufferSize() 15 | { 16 | return responseBuffer.size(); 17 | } 18 | 19 | void Connector::grabPacket() 20 | { 21 | while (rawBuffer.size() > Response::PacketSize) 22 | { 23 | if (rawBuffer[0] == 0xff && rawBuffer[1] == 0x01) 24 | { 25 | rawBuffer.linearize(); 26 | Response *response = new Response(rawBuffer.array_one().first); 27 | rawBuffer.erase_begin(Response::PacketSize); 28 | responseBuffer.push(response); 29 | } 30 | else 31 | { 32 | rawBuffer.pop_front(); 33 | } 34 | } 35 | } 36 | 37 | bool Connector::isConnected() 38 | { 39 | return connected; 40 | } -------------------------------------------------------------------------------- /gui/TransmissionLogDialog.h: -------------------------------------------------------------------------------- 1 | #ifndef _TRANSMISSION_LOG_DIALOG_H_ 2 | #define _TRANSMISSION_LOG_DIALOG_H_ 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace Gtk; 9 | using namespace Glib; 10 | 11 | class TransmissionLogDialog : public Window 12 | { 13 | public: 14 | TransmissionLogDialog(BaseObjectType *cobject, const RefPtr &refGlade); 15 | virtual ~TransmissionLogDialog(); 16 | 17 | void updateLog(Protocol::TransmissionLog &log); 18 | 19 | protected: 20 | // Signal handlers 21 | 22 | // Internal UI methods 23 | 24 | // Protected Members - Gtk 25 | Glib::RefPtr refGlade; 26 | 27 | TextView *pTransmissionLogView; 28 | RefPtr pTransmissionLogBuffer; 29 | 30 | private: 31 | ustring hexdump(uint8_t *data, size_t length, int cols = 32); 32 | 33 | Protocol::TransmissionLog transmissionLog; 34 | int transmissionCounter; 35 | }; 36 | 37 | #endif // _TRANSMISSION_LOG_DIALOG_H_ -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # version numbers 2 | set (libidso1070_VERSION_MAJOR 1) 3 | set (libidso1070_VERSION_MINOR 0) 4 | 5 | project (libidso1070 VERSION "${libidso1070_VERSION_MAJOR}.${libidso1070_VERSION_MINOR}") 6 | 7 | # create config.h 8 | configure_file ( 9 | "config.h.in" 10 | "${PROJECT_BINARY_DIR}/config.h" 11 | ) 12 | 13 | # create idso1070.pc 14 | configure_file(idso1070.pc.in idso1070.pc @ONLY) 15 | 16 | # add binary dir as include directory, to be able to include config.h 17 | include_directories("${PROJECT_BINARY_DIR}") 18 | 19 | 20 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 21 | 22 | add_subdirectory(connection) 23 | add_subdirectory(packets) 24 | 25 | add_library(idso1070 SHARED Protocol.cxx ProtocolWorker.cxx IDSO1070.cxx util.cxx) 26 | target_link_libraries (idso1070 connection packets ${Boost_LIBRARIES} ${PTHREAD_LIBRARIES}) 27 | 28 | set_target_properties(idso1070 PROPERTIES VERSION ${PROJECT_VERSION}) 29 | 30 | install (TARGETS idso1070 31 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) 32 | -------------------------------------------------------------------------------- /cli/main.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | ProtocolWorker worker; 7 | bool run = true; 8 | 9 | void signalHandler(int signal) 10 | { 11 | if (signal == SIGINT) 12 | { 13 | cout << endl 14 | << endl; 15 | run = false; 16 | } 17 | } 18 | 19 | void notify() 20 | { 21 | if (worker.isConnecting()) 22 | { 23 | cout << "Connecting: " << worker.getProgress() * 100 << "%" << endl; 24 | } 25 | 26 | if (worker.isConnected()) 27 | { 28 | } 29 | else 30 | { 31 | if (worker.isConnectionLost()) 32 | { 33 | cout << "Connection error: " << worker.getConnectionLostReason() << endl; 34 | } 35 | } 36 | } 37 | 38 | int main(int argc, char *argv[]) 39 | { 40 | signal(SIGINT, signalHandler); 41 | 42 | worker.setNotifyHandler(notify); 43 | worker.start(); 44 | worker.connect("/dev/ttyACM0"); 45 | 46 | while (run) 47 | { 48 | } 49 | worker.stop(); 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /gui/main.cxx: -------------------------------------------------------------------------------- 1 | #include "AppWindow.h" 2 | 3 | #include 4 | 5 | extern char resource_glade_data_start[]; 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | auto app = 10 | Gtk::Application::create(argc, argv, 11 | "org.hhornbacher.idso1070.gui"); 12 | 13 | // Load the GtkBuilder file and instantiate its widgets: 14 | auto refBuilder = Gtk::Builder::create(); 15 | try 16 | { 17 | ustring gladeData = (char *)resource_glade_data_start; 18 | refBuilder->add_from_string(gladeData); 19 | } 20 | catch (const Glib::FileError &ex) 21 | { 22 | std::cerr << "FileError: " << ex.what() << std::endl; 23 | return 1; 24 | } 25 | catch (const Glib::MarkupError &ex) 26 | { 27 | std::cerr << "MarkupError: " << ex.what() << std::endl; 28 | return 1; 29 | } 30 | catch (const Gtk::BuilderError &ex) 31 | { 32 | std::cerr << "BuilderError: " << ex.what() << std::endl; 33 | return 1; 34 | } 35 | 36 | AppWindow appWindow(refBuilder); 37 | 38 | return app->run(appWindow); 39 | } 40 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.5) 2 | 3 | # default GNU install directories 4 | include(GNUInstallDirs) 5 | 6 | # set buil to debug 7 | set(CMAKE_BUILD_TYPE Debug) 8 | 9 | # set C++ standard to C++11 10 | set (CMAKE_CXX_STANDARD 11) 11 | 12 | # add local cmake dir to module path 13 | list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules) 14 | 15 | # add Boost 16 | find_package(Boost 1.58.0 REQUIRED) 17 | include_directories(${Boost_INCLUDE_DIR}) 18 | 19 | # add PThread 20 | find_package(PThread REQUIRED) 21 | include_directories(${PTHREAD_INCLUDE_DIRS}) 22 | 23 | # add include directory 24 | include_directories(include) 25 | 26 | # source directories 27 | add_subdirectory(lib) 28 | add_subdirectory(gui) 29 | add_subdirectory(cli) 30 | 31 | # install idso1070.pc 32 | install(FILES ${CMAKE_BINARY_DIR}/idso1070.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) 33 | 34 | # install include directory 35 | install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/idso1070) 36 | 37 | # Include uninstall target helper 38 | include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/uninstall.cmake") -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2018 Harry Hornbacher 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/util.cxx: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | #include 4 | #include 5 | 6 | float mapValue(int i, float f, float f2, float f3, float f4) 7 | { 8 | return (((((float)i) - f) / (f2 - f)) * (f4 - f3)) + f3; 9 | } 10 | 11 | float mapValue(float f, float f2, float f3, float f4, float f5) 12 | { 13 | return (((f - f2) / (f3 - f2)) * (f5 - f4)) + f4; 14 | } 15 | 16 | string hexdump(uint8_t *data, size_t length, int cols) 17 | { 18 | stringstream ss; 19 | int rowCount = (length / cols) + (length % cols != 0 ? 1 : 0); 20 | for (int row = 0; row < rowCount; row++) 21 | { 22 | int colCount = row == (length / cols) ? length % cols : cols; 23 | 24 | ss << "0x" << setfill('0') << setw(8) << hex << (row * cols) << " | "; 25 | 26 | for (int col = 0; col < colCount; col++) 27 | { 28 | unsigned int x = (unsigned int)data[(row * cols) + col] & 0xff; 29 | 30 | ss << setfill('0') << setw(2) << hex << x << " "; 31 | if ((col + 1) % 8 == 0) 32 | ss << "| "; 33 | } 34 | ss << endl; 35 | } 36 | ss << endl; 37 | return ss.str(); 38 | } -------------------------------------------------------------------------------- /gui/AppWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef _APP_WINDOW_H_ 2 | #define _APP_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "ScopeWidget.h" 10 | #include "SettingsWidget.h" 11 | #include "ProtocolWorker.h" 12 | 13 | using namespace Gtk; 14 | using namespace Glib; 15 | 16 | class AppWindow : public Window 17 | { 18 | public: 19 | AppWindow(const Glib::RefPtr &refGlade); 20 | virtual ~AppWindow(); 21 | 22 | // Called by WorkerThread to notify the UI, that there's an update to do 23 | void notify(); 24 | 25 | protected: 26 | // Signal handlers 27 | void onNotificationFromWorker(); 28 | bool onUpdateBatteryLevel(); 29 | bool onUpdateScope(); 30 | 31 | // Protected Members - Gtk 32 | Glib::RefPtr refGlade; 33 | 34 | // Protected Members - WorkerThread 35 | Glib::Dispatcher dispatcher; 36 | ProtocolWorker worker; 37 | 38 | // Protected Members - Timers 39 | sigc::connection updateBatteryTimer; 40 | sigc::connection updateScopeTimer; 41 | 42 | // Protected Members - Child widgets 43 | Box boxHorizontal; 44 | ScopeWidget scopeWidget; 45 | SettingsWidget *pSettingsWidget; 46 | }; 47 | 48 | #endif // _APP_WINDOW_H_ -------------------------------------------------------------------------------- /gui/ScopeWidget.h: -------------------------------------------------------------------------------- 1 | #ifndef _GRAPH_WIDGET_H_ 2 | #define _GRAPH_WIDGET_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "ProtocolWorker.h" 9 | 10 | class ScopeWidget : public Gtk::Widget 11 | { 12 | public: 13 | static const int DivColumns = 10; 14 | static const int DivRows = 8; 15 | static const int ScopePadding = 30; 16 | 17 | ScopeWidget(ProtocolWorker *worker); 18 | virtual ~ScopeWidget(); 19 | 20 | void update(); 21 | 22 | protected: 23 | // Overrides: 24 | void on_size_allocate(Gtk::Allocation &allocation) override; 25 | void on_realize() override; 26 | void on_unrealize() override; 27 | bool on_draw(const Cairo::RefPtr &cr) override; 28 | 29 | // Internal draw methods 30 | void drawGrid(const Cairo::RefPtr &cr); 31 | void drawChannel1(const Cairo::RefPtr &cr); 32 | void drawChannel2(const Cairo::RefPtr &cr); 33 | 34 | Glib::RefPtr refGdkWindow; 35 | 36 | // Protocol worker thread reference 37 | ProtocolWorker *worker; 38 | 39 | IDSO1070 device; 40 | SampleBuffer sampleBuffer; 41 | }; 42 | 43 | #endif // _GRAPH_WIDGET_H_ -------------------------------------------------------------------------------- /cmake/resources.cmake: -------------------------------------------------------------------------------- 1 | macro(add_resource RES_NAME RES_FILE RES_TARGET) 2 | set(RES_OBJECT_FILE ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${RES_TARGET}.dir/${RES_NAME}.o) 3 | set(RES_OBJCOPY_OPTS --input binary --output elf64-x86-64 --binary-architecture i386:x86-64 --rename-section .data=.rodata,CONTENTS,ALLOC,LOAD,READONLY,DATA) 4 | set(RES_RENAME_SYMBOLS --redefine-sym _binary_${RES_NAME}_start=resource_${RES_NAME}_start --redefine-sym _binary_${RES_NAME}_end=resource_${RES_NAME}_end --redefine-sym _binary_${RES_NAME}_size=resource_${RES_NAME}_size) 5 | 6 | add_custom_command( 7 | TARGET ${RES_TARGET} 8 | PRE_BUILD 9 | COMMAND cp ${RES_FILE} ${RES_NAME} 10 | COMMAND dd if=/dev/zero of=zero_pad bs=1 count=1 2> /dev/null >> ${RES_NAME} 11 | COMMAND objcopy ${RES_OBJCOPY_OPTS} ${RES_RENAME_SYMBOLS} ${RES_NAME} ${RES_OBJECT_FILE} 12 | COMMAND rm zero_pad ${RES_NAME} 13 | BYPRODUCTS ${RES_OBJECT_FILE} 14 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) 15 | 16 | set(RESOURCES_OBJECTS ${RESOURCES_OBJECTS} ${RES_OBJECT_FILE}) 17 | 18 | unset(RES_OBJECT_FILE) 19 | unset(RES_OBJCOPY_OPTS) 20 | unset(RES_RENAME_SYMBOLS) 21 | endmacro(add_resource) 22 | -------------------------------------------------------------------------------- /include/connection/Connector.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONNECTOR_H_ 2 | #define _CONNECTOR_H_ 3 | 4 | #include "base.h" 5 | #include "packets/Response.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | class Connector 12 | { 13 | public: 14 | static const int RawBufferLength = 1024 * 64; 15 | 16 | class Exception : public runtime_error 17 | { 18 | public: 19 | Exception(string reason) 20 | : runtime_error("connection error"), reason(reason) 21 | { 22 | } 23 | 24 | virtual const char *what() const throw() 25 | { 26 | return reason.c_str(); 27 | } 28 | 29 | private: 30 | string reason; 31 | }; 32 | 33 | Connector(); 34 | 35 | Response *getLatestResponse(); 36 | size_t getResponseBufferSize(); 37 | 38 | virtual void transmit(uint8_t *data, size_t length) = 0; 39 | virtual void receive() = 0; 40 | 41 | virtual void start() = 0; 42 | virtual void stop() = 0; 43 | 44 | virtual ConnectorType getType() = 0; 45 | 46 | bool isConnected(); 47 | 48 | protected: 49 | void grabPacket(); 50 | 51 | boost::circular_buffer rawBuffer; 52 | queue responseBuffer; 53 | bool connected = false; 54 | }; 55 | 56 | #endif // _CONNECTOR_H_ -------------------------------------------------------------------------------- /cmake/uninstall.uninstall_target.cmake.in: -------------------------------------------------------------------------------- 1 | # http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F 2 | 3 | IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") 5 | ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 6 | 7 | FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 8 | STRING(REGEX REPLACE "\n" ";" files "${files}") 9 | FOREACH(file ${files}) 10 | MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") 11 | IF(EXISTS "$ENV{DESTDIR}${file}") 12 | EXEC_PROGRAM( 13 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 14 | OUTPUT_VARIABLE rm_out 15 | RETURN_VALUE rm_retval 16 | ) 17 | IF(NOT "${rm_retval}" STREQUAL 0) 18 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 19 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 20 | ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}") 21 | EXEC_PROGRAM( 22 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 23 | OUTPUT_VARIABLE rm_out 24 | RETURN_VALUE rm_retval 25 | ) 26 | IF(NOT "${rm_retval}" STREQUAL 0) 27 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 28 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 29 | ELSE(EXISTS "$ENV{DESTDIR}${file}") 30 | MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") 31 | ENDIF(EXISTS "$ENV{DESTDIR}${file}") 32 | ENDFOREACH(file) -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Verwendet IntelliSense zum Ermitteln möglicher Attribute. 3 | // Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen. 4 | // Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "(gdb) Launch GUI", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/build/gui/idso1070-gui", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${workspaceFolder}/build/gui", 15 | "environment": [], 16 | "externalConsole": false, 17 | "MIMode": "gdb", 18 | "setupCommands": [ 19 | { 20 | "description": "Enable pretty-printing for gdb", 21 | "text": "-enable-pretty-printing", 22 | "ignoreFailures": true 23 | } 24 | ] 25 | }, 26 | { 27 | "name": "(gdb) Launch CLI", 28 | "type": "cppdbg", 29 | "request": "launch", 30 | "program": "${workspaceFolder}/build/cli/idso1070-cli", 31 | "args": [], 32 | "stopAtEntry": false, 33 | "cwd": "${workspaceFolder}/build/cli", 34 | "environment": [], 35 | "externalConsole": false, 36 | "MIMode": "gdb", 37 | "setupCommands": [ 38 | { 39 | "description": "Enable pretty-printing for gdb", 40 | "text": "-enable-pretty-printing", 41 | "ignoreFailures": true 42 | } 43 | ] 44 | } 45 | ] 46 | } -------------------------------------------------------------------------------- /gui/AppWindow.cxx: -------------------------------------------------------------------------------- 1 | #include "AppWindow.h" 2 | 3 | AppWindow::AppWindow(const Glib::RefPtr &refGlade) : refGlade(refGlade), 4 | scopeWidget(&worker), 5 | pSettingsWidget(nullptr), 6 | boxHorizontal(ORIENTATION_HORIZONTAL) 7 | { 8 | // Create main window 9 | set_title("IDSO1070 GUI"); 10 | set_default_size(1800, 1000); 11 | 12 | add(boxHorizontal); 13 | 14 | boxHorizontal.pack_start(scopeWidget, PACK_EXPAND_WIDGET); 15 | 16 | refGlade->get_widget_derived("SettingsWidget", pSettingsWidget); 17 | pSettingsWidget->setWorker(&worker); 18 | boxHorizontal.pack_start(*pSettingsWidget, PACK_SHRINK); 19 | 20 | show_all_children(); 21 | 22 | // Connect the handler to the dispatcher and start the worker thread ... 23 | worker.setNotifyHandler(bind(&AppWindow::notify, this)); 24 | dispatcher.connect(sigc::mem_fun(*this, &AppWindow::onNotificationFromWorker)); 25 | worker.startThread(); 26 | 27 | // Create battery level update timer 28 | // updateBatteryTimer = signal_timeout().connect(sigc::mem_fun(*this, &AppWindow::onUpdateBatteryLevel), 5000); 29 | 30 | // Create graph update timer 31 | updateScopeTimer = signal_timeout().connect(sigc::mem_fun(*this, &AppWindow::onUpdateScope), 100); 32 | } 33 | 34 | AppWindow::~AppWindow() 35 | { 36 | worker.stopThread(); 37 | updateBatteryTimer.disconnect(); 38 | updateScopeTimer.disconnect(); 39 | } 40 | 41 | void AppWindow::onNotificationFromWorker() 42 | { 43 | pSettingsWidget->update(); 44 | } 45 | 46 | bool AppWindow::onUpdateBatteryLevel() 47 | { 48 | if (worker.isConnected()) 49 | { 50 | worker.readBatteryLevel(); 51 | } 52 | return true; 53 | } 54 | 55 | bool AppWindow::onUpdateScope() 56 | { 57 | // if (worker.isSampling()) 58 | // { 59 | scopeWidget.update(); 60 | // } 61 | return true; 62 | } 63 | 64 | void AppWindow::notify() 65 | { 66 | dispatcher.emit(); 67 | } -------------------------------------------------------------------------------- /cmake/modules/FindLiquidSdr.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012-2013 The Iris Project Developers. See the 3 | # COPYRIGHT file at the top-level directory of this distribution 4 | # and at http://www.softwareradiosystems.com/iris/copyright.html. 5 | # 6 | # This file is part of the Iris Project. 7 | # 8 | # Iris is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU Lesser General Public License as 10 | # published by the Free Software Foundation, either version 3 of 11 | # the License, or (at your option) any later version. 12 | # 13 | # Iris is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # A copy of the GNU Lesser General Public License can be found in 19 | # the LICENSE file in the top-level directory of this distribution 20 | # and at http://www.gnu.org/licenses/. 21 | # 22 | 23 | # - Try to find liquiddsp - https://github.com/jgaeddert/liquid-dsp 24 | # Once done this will define 25 | # LIQUIDDSP_FOUND - System has liquiddsp 26 | # LIQUIDDSP_INCLUDE_DIRS - The liquiddsp include directories 27 | # LIQUIDDSP_LIBRARIES - The libraries needed to use liquiddsp 28 | 29 | find_path(LIQUIDDSP_INCLUDE_DIR 30 | NAMES liquid/liquid.h 31 | HINTS $ENV{LIQUIDDSP_DIR}/include 32 | PATHS /usr/local/include 33 | /usr/include ) 34 | 35 | find_library(LIQUIDDSP_LIBRARY 36 | NAMES liquid 37 | HINTS $ENV{LIQUIDDSP_DIR}/lib 38 | PATHS /usr/local/lib 39 | /usr/lib) 40 | 41 | set(LIQUIDDSP_LIBRARIES ${LIQUIDDSP_LIBRARY} ) 42 | set(LIQUIDDSP_INCLUDE_DIRS ${LIQUIDDSP_INCLUDE_DIR} ) 43 | 44 | include(FindPackageHandleStandardArgs) 45 | # handle the QUIETLY and REQUIRED arguments and set LIQUIDDSP_FOUND to TRUE 46 | # if all listed variables are TRUE 47 | find_package_handle_standard_args(liquiddsp DEFAULT_MSG 48 | LIQUIDDSP_LIBRARY LIQUIDDSP_INCLUDE_DIR) 49 | 50 | mark_as_advanced(LIQUIDDSP_INCLUDE_DIR LIQUIDDSP_LIBRARY ) 51 | -------------------------------------------------------------------------------- /include/packets/CommandFactory.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMMANDS_GENERATOR_H_ 2 | #define _COMMANDS_GENERATOR_H_ 3 | 4 | #include "base.h" 5 | #include "util.h" 6 | #include "IDSO1070.h" 7 | #include "Command.h" 8 | 9 | class CommandFactory 10 | { 11 | public: 12 | Command *readEEPROMPage(uint8_t address); 13 | Command *readARMVersion(); 14 | Command *readFPGAVersion(); 15 | Command *readBatteryLevel(); 16 | Command *readRamCount(int enabledChannels, uint16_t samplesNumberOfOneFrame, 17 | double triggerXPosition, 18 | uint8_t packetsNumber); 19 | 20 | Command *startSampling(); 21 | 22 | Command *updateSampleRate(TimeBase timeBase, int enabledChannels); 23 | Command *updateFreqDivLowBytes(uint32_t freqDiv); 24 | Command *updateFreqDivHighBytes(uint32_t freqDiv); 25 | Command *updateRAMChannelSelection(bool channel1Enabled, bool channel2Enabled); 26 | Command *updateChannelVolts125(VoltageDiv channel1VerticalDiv, VoltageDiv channel2VerticalDiv); 27 | Command *updateRelay1(VoltageDiv channel1VerticalDiv); 28 | Command *updateRelay2(VoltageDiv channel1VerticalDiv); 29 | Command *updateRelay3(VoltageDiv channel2VerticalDiv); 30 | Command *updateRelay4(VoltageDiv channel2VerticalDiv); 31 | Command *updateChannel1Coupling(InputCoupling channel1Coupling); 32 | Command *updateChannel2Coupling(InputCoupling channel2Coupling); 33 | Command *updateTriggerMode(CaptureMode capMode, TriggerMode trigMode, ScopeMode scoMode); 34 | Command *updateChannel1Level(VoltageDiv channel1VerticalDiv, int16_t channel1VerticalPosition, float channel1PWM0, float channel1PWM1); 35 | Command *updateChannel2Level(VoltageDiv channel2VerticalDiv, int16_t channel2VerticalPosition, float channel2PWM0, float channel2PWM1); 36 | Command *updateTriggerSourceAndSlope(TriggerChannel triggerChanel, ScopeMode scoMode, TriggerSlope triggerSlope); 37 | Command *updateTriggerLevel(uint16_t triggerLevel, float triggerTopPWM, float triggerBottomPWM); 38 | Command *updateChannelSelection(bool channel1Enabled, bool channel2Enabled); 39 | Command *updatePreTriggerLength(uint16_t samplesNumberOfOneFrame, double triggerXPosition); 40 | Command *updatePostTriggerLength(uint16_t samplesNumberOfOneFrame, double triggerXPosition); 41 | }; 42 | 43 | #endif // _COMMANDS_GENERATOR_H_ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IDSO1070 Protocol Library (for Linux) 2 | 3 | This is a reverse engineered implementation of the protocol used to communicate with the 2 channel digital storage oscilloscope IDSO1070 from Hantek. 4 | It's possible to communicate with the device over WiFi (TCP) as well as USB. 5 | 6 | USB ID: ```0483:5740 [STMicroelectronics STM32F407]``` 7 | 8 | ## Current state of development 9 | 10 | **Attention:** This is not a production ready version, there's still a lot of stuff to do. If you're interested to support this library, just contact me. 11 | 12 | ### Features 13 | 14 | * Connection to device with WiFi (TCP) or USB 15 | * Send command packets ([Packet Format](lib/README.md#request-command-packet)) 16 | * Receive and parse command response and sample data packets ([Packet Format](lib/README.md#response-packet)) 17 | 18 | ### Next steps 19 | 20 | #### Library 21 | 22 | * Handling for interrupted connections 23 | * Better overall exception handling 24 | 25 | #### GUI 26 | 27 | * Implement sample streaming and visualization 28 | * Add controls for device settings 29 | * Add controls to display device infos 30 | 31 | ## Dependencies 32 | 33 | * GCC 34 | * CMake: >= 3.5 35 | * Boost: >= 1.58.0 36 | * gtkmm: >= 3.18.0 37 | * [liquid-dsp: >= 1.3.0](https://github.com/jgaeddert/liquid-dsp/tree/v1.3.0) 38 | 39 | On Ubuntu/Mint you can run ```apt install libboost-all-dev libgtkmm-3.0-dev cmake gcc``` to install the dependencies. 40 | You have to compile and install liquid-dsp manually, for instructions follow the link above. 41 | 42 | ## Build instructions 43 | 44 | Just run the ```build.sh``` or execute following commands in your shell: 45 | 46 | ```bash 47 | mkdir build 48 | cd build 49 | cmake .. 50 | make 51 | sudo make install 52 | ``` 53 | 54 | To run the GUI without installing, you can execute the ```run.sh``` 55 | 56 | There is also a pre configured task for building (CTRL-SHIFT-B) in vscode and a launch.json to debug(F5). 57 | 58 | ## Directories 59 | 60 | * gui: Simple Gtk GUI 61 | * lib: Implementation of the protocol itself 62 | * include: Library headers 63 | * cmake: Helper scripts for cmake 64 | 65 | ## Links 66 | 67 | * Product page: http://www.hantek.com/en/ProductDetail_2_10165.html 68 | * [sigrok: Hardware photos & information only, not supported by the library](https://sigrok.org/wiki/Hantek_iDSO1070) -------------------------------------------------------------------------------- /lib/connection/TCPConnector.cxx: -------------------------------------------------------------------------------- 1 | #include "connection/TCPConnector.h" 2 | 3 | TCPConnector::TCPConnector(string host, int port) : host(host), port(port), socketHandle(-1) 4 | { 5 | } 6 | 7 | TCPConnector::~TCPConnector() 8 | { 9 | if (socketHandle > 0) 10 | close(socketHandle); 11 | } 12 | 13 | void TCPConnector::start() 14 | { 15 | if (socketHandle != -1) 16 | return; 17 | if ((socketHandle = socket(AF_INET, SOCK_STREAM, 0)) < 0) 18 | { 19 | throw Exception("Cannot create socket"); 20 | } 21 | 22 | serverAddress.sin_family = AF_INET; 23 | serverAddress.sin_port = htons(port); 24 | serverAddress.sin_addr.s_addr = inet_addr(host.c_str()); 25 | 26 | int res = 0; 27 | if ((res = connect(socketHandle, 28 | (struct sockaddr *)&serverAddress, 29 | sizeof(serverAddress))) != 0) 30 | { 31 | throw Exception(strerror(res)); 32 | } 33 | 34 | if ((res = fcntl(socketHandle, F_SETFL, fcntl(socketHandle, F_GETFL) | O_NONBLOCK)) < 0) 35 | { 36 | throw Exception("Unabled to put socket in non-blocking mode"); 37 | } 38 | connected = true; 39 | } 40 | 41 | void TCPConnector::stop() 42 | { 43 | if (socketHandle != -1) 44 | close(socketHandle); 45 | connected = false; 46 | socketHandle = -1; 47 | } 48 | 49 | ConnectorType TCPConnector::getType() 50 | { 51 | return CONNECTOR_WIFI; 52 | } 53 | 54 | void TCPConnector::transmit(uint8_t *data, size_t length) 55 | { 56 | if (socketHandle == -1) 57 | return; 58 | int res = 0; 59 | if ((res = send(socketHandle, data, length, 0)) < 0) 60 | { 61 | stop(); 62 | throw Exception("Connection lost"); 63 | } 64 | } 65 | 66 | void TCPConnector::receive() 67 | { 68 | if (!rawBuffer.full()) 69 | { 70 | size_t size = RawBufferLength - rawBuffer.size(); 71 | uint8_t localBuffer[size]; 72 | if (socketHandle == -1) 73 | return; 74 | ssize_t receivedSize = recv(socketHandle, localBuffer, size, 0); 75 | if (receivedSize < 0) 76 | { 77 | stop(); 78 | throw Exception("Connection lost"); 79 | } 80 | else if (receivedSize > 0) 81 | { 82 | for (ssize_t i = 0; i < receivedSize; i++) 83 | rawBuffer.push_back(localBuffer[i]); 84 | } 85 | } 86 | grabPacket(); 87 | } -------------------------------------------------------------------------------- /gui/TransmissionLogDialog.cxx: -------------------------------------------------------------------------------- 1 | #include "TransmissionLogDialog.h" 2 | #include 3 | 4 | TransmissionLogDialog::TransmissionLogDialog(BaseObjectType *cobject, const RefPtr &refGlade) 5 | : Window(cobject), 6 | refGlade(refGlade), 7 | pTransmissionLogView(nullptr), 8 | pTransmissionLogBuffer(nullptr), 9 | transmissionCounter(1) 10 | { 11 | // Get references to widgets from glade file 12 | refGlade->get_widget("textTransmissionLog", pTransmissionLogView); 13 | pTransmissionLogBuffer = RefPtr::cast_dynamic(refGlade->get_object("TransmissionLogBuffer")); 14 | 15 | // Connect signals with handlers 16 | } 17 | 18 | TransmissionLogDialog::~TransmissionLogDialog() 19 | { 20 | } 21 | 22 | void TransmissionLogDialog::updateLog(Protocol::TransmissionLog &log) 23 | { 24 | ustring logBuffer; 25 | for (auto transmission : log) 26 | { 27 | logBuffer += ustring::compose("Transmission #%1\n", transmissionCounter); 28 | logBuffer += "\nCommand:\n"; 29 | logBuffer += hexdump(transmission->command.getPayload(), Command::CommandSize); 30 | logBuffer += "\nResponse Header:\n"; 31 | logBuffer += hexdump(transmission->response.getHeader(), Packet::HeaderSize); 32 | logBuffer += "\nResponse Payload:\n"; 33 | logBuffer += hexdump(transmission->response.getPayload(), transmission->response.getPayloadLength()); 34 | logBuffer += "\n--------------------------------------------------------------------------------------------------------------------\n\n\n"; 35 | transmissionCounter++; 36 | delete transmission; 37 | } 38 | TextIter begin = pTransmissionLogBuffer->begin(); 39 | pTransmissionLogBuffer->insert_markup(begin, logBuffer); 40 | log.clear(); 41 | } 42 | 43 | ustring TransmissionLogDialog::hexdump(uint8_t *data, size_t length, int cols) 44 | { 45 | ustring hexdump = ""; 46 | int rowCount = (length / cols) + (length % cols != 0 ? 1 : 0); 47 | for (int row = 0; row < rowCount; row++) 48 | { 49 | int colCount = row == (length / cols) ? length % cols : cols; 50 | hexdump += ustring::compose("0x%1 | ", ustring::format(setfill(L'0'), setw(8), std::hex, row * cols)); 51 | for (int col = 0; col < colCount; col++) 52 | { 53 | unsigned int x = (unsigned int)data[(row * cols) + col] & 0xff; 54 | hexdump += ustring::compose("%1 ", ustring::format(setfill(L'0'), setw(2), std::hex, x)); 55 | if ((col + 1) % 8 == 0) 56 | hexdump += "| "; 57 | } 58 | hexdump += "\n"; 59 | } 60 | hexdump += ""; 61 | return hexdump; 62 | } -------------------------------------------------------------------------------- /include/ProtocolWorker.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROTOCOL_WORKER_H_ 2 | #define _PROTOCOL_WORKER_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | class ProtocolWorker : protected Protocol 10 | { 11 | public: 12 | typedef function NotifyHandler; 13 | 14 | ProtocolWorker(); 15 | 16 | void setNotifyHandler(NotifyHandler notifyHandler); 17 | 18 | // Thread main loop 19 | void process(); 20 | 21 | // Thread execution control & status 22 | void startThread(); 23 | void stopThread(); 24 | bool hasStopped() const; 25 | float getProgress() const; 26 | 27 | // Connection status 28 | bool isConnected() const; 29 | bool isConnecting() const; 30 | bool isConnectionLost() const; 31 | ConnectorType getConnectorType(); 32 | string getConnectionLostReason() const; 33 | 34 | // Connection control 35 | void connect(string device); 36 | void connect(string server, int port); 37 | void disconnect(); 38 | 39 | // Sampling control 40 | void startSampling(); 41 | void stopSampling(); 42 | 43 | // Device control 44 | void init(); 45 | void readBatteryLevel(); 46 | void setTimeBase(TimeBase timeBase); 47 | void setScopeMode(ScopeMode scopeMode); 48 | void setCaptureMode(CaptureMode captureMode); 49 | 50 | // Channel control 51 | void enableChannel(ChannelSelector channel); 52 | void disableChannel(ChannelSelector channel); 53 | void setChannelVerticalDiv(ChannelSelector channel, VoltageDiv div); 54 | void setChannelCoupling(ChannelSelector channel, InputCoupling coupling); 55 | void setChannelVerticalPosition(ChannelSelector channel, uint16_t pos); 56 | 57 | // Trigger control 58 | void setTriggerMode(TriggerMode mode); 59 | void setTriggerChannel(TriggerChannel channel); 60 | void setTriggerSlope(TriggerSlope slope); 61 | void setTriggerLevel(uint16_t level); 62 | 63 | // In-Thread callbacks 64 | void onConnectionLost(Connector::Exception &e); 65 | void onUpdateUI(); 66 | void onUpdateProgress(float progress); 67 | void onInitialized(); 68 | 69 | void fetchDevice(IDSO1070 &dev); 70 | void fetchSamples(SampleBuffer &buffer); 71 | void fetchTransmissionLog(Protocol::TransmissionLog &log); 72 | 73 | protected: 74 | // Thread sync mutex 75 | mutable mutex stateMutex; 76 | 77 | // Worker thread 78 | thread *workerThread; 79 | 80 | // Notify main thread 81 | NotifyHandler notifyHandler; 82 | 83 | // Thread execution control & status members 84 | bool shallStop; 85 | bool stopped; 86 | 87 | // Connection status members 88 | string connectionLostReason; 89 | bool connectionLost; 90 | bool connected; 91 | bool connecting; 92 | float progress; 93 | 94 | // Notify UI to update 95 | bool update; 96 | }; 97 | 98 | #endif // _PROTOCOL_WORKER_H_ -------------------------------------------------------------------------------- /lib/README.md: -------------------------------------------------------------------------------- 1 | # IDSO1070 Protocol Library (for Linux) 2 | 3 | This is a reverse engineered implementation of the protocol used to communicate with the 2 channel digital storage IDSO1070 from Hantek. 4 | It's possible to communicate with the device over WiFi (TCP) as well as USB. 5 | 6 | ## About the Protocol 7 | 8 | The protocol itself is based on a simple request-response flow with the packets described here. 9 | 10 | ### Request (Command) packet 11 | 12 | This packet has the fixed size of 4 bytes 13 | 14 | Address|Size (byte)|Description 15 | -|-|- 16 | `0x0000`|1|Command type/category 17 | `0x0001`|1|Command code 18 | `0x0002`|2|Parameters (can be 0-2 bytes, padded with zero) 19 | 20 | #### Commands 21 | 22 | Type|=|Command|=|Parameters 23 | -|-|-|-|- 24 | STATE|`0x57`|Read battery level|`0x03`|`0000` 25 | STATE|`0x57`|Read ARM firmware version|`0x04`|`0000` 26 | CONTROL|`0xaa`|Read FPGA firmware version|`0x02`|`0000` 27 | CONTROL|`0xaa`|Start sampling|`0x04`|`0000` 28 | EEPROM|`0xee`|Read EEPROM page|`0xaa`|first byte: 8bit address of the page to read; second byte: `00` 29 | FPGA|`0x55`|Force trigger|`0x01`|*TBD* 30 | FPGA|`0x55`|Trigger mode|`0x02`|*TBD* 31 | FPGA|`0x55`|Set relay|`0x03`|*TBD* 32 | FPGA|`0x55`|Channel selection|`0x04`|*TBD* 33 | FPGA|`0x55`|Trigger source|`0x05`|*TBD* 34 | FPGA|`0x55`|Channel volts div 125|`0x06`|*TBD* 35 | FPGA|`0x55`|Pre trigger length|`0x07`|*TBD* 36 | FPGA|`0x55`|Post trigger length|`0x08`|*TBD* 37 | FPGA|`0x55`|RAM start position|`0x09`|*TBD* 38 | FPGA|`0x55`|Reserved data output|`0x0a`|*TBD* 39 | FPGA|`0x55`|Channel 1 PWM|`0x0b`|*TBD* 40 | FPGA|`0x55`|Channel 2 PWM|`0x0c`|*TBD* 41 | FPGA|`0x55`|Trigger PWM|`0x0d`|*TBD* 42 | FPGA|`0x55`|Logic analyzer 1|`0x0e`|*TBD* 43 | FPGA|`0x55`|Logic analyzer 2|`0x0f`|*TBD* 44 | FPGA|`0x55`|Logic analyzer 3|`0x10`|*TBD* 45 | FPGA|`0x55`|Sample rate|`0x11`|*TBD* 46 | FPGA|`0x55`|Frequency divider lower 2 bytes|`0x12`|*TBD* 47 | FPGA|`0x55`|Frequency divider higher 2 bytes|`0x13`|*TBD* 48 | FPGA|`0x55`|Serial baud rate|`0x14`|*TBD* 49 | FPGA|`0x55`|RAM channel selection|`0x15`|*TBD* 50 | FPGA|`0x55`|Read RAM count|`0x16`|*TBD* 51 | 52 | ### Response packet 53 | 54 | This packet has the fixed size of 509 bytes. 55 | 56 | Section|Address|Size (byte)|Description 57 | -|-|-|- 58 | HEADER|`0x0000`|2|HEADER: Magic bytes: `0xff 0x01` 59 | ||`0x0002`|1|HEADER: 8bit packet counter 60 | ||`0x0003`|4|HEADER: Bytes of the command packet, this response is addressed to 61 | PAYLOAD|`0x0007`|501|PAYLOAD 62 | END|`0x01FC`|1|Magic byte: `0xce` 63 | 64 | ### Connection 65 | 66 | There are two options connection to the device: 67 | 68 | * USB: Device connects over USB-Serial connection (maximum baud rate not yet known) 69 | * WiFi: When you're connected to the device's access point, there is a TCP server listening on `192.186.1.1:8870` -------------------------------------------------------------------------------- /gui/SettingsWidget.h: -------------------------------------------------------------------------------- 1 | #ifndef _SETTINGS_WIDGET_H_ 2 | #define _SETTINGS_WIDGET_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "TransmissionLogDialog.h" 10 | 11 | using namespace Gtk; 12 | using namespace Glib; 13 | 14 | class SettingsWidget : public Box 15 | { 16 | public: 17 | SettingsWidget(BaseObjectType *cobject, const RefPtr &refGlade); 18 | virtual ~SettingsWidget(); 19 | 20 | void setWorker(ProtocolWorker *worker); 21 | 22 | // Called by WorkerThread to notify the UI, that there's an update to do 23 | void update(); 24 | 25 | protected: 26 | // Signal handlers 27 | void onButtonTransmissionLog(); 28 | void onButtonConnect(); 29 | void onToggleChannel1Enable(); 30 | void onToggleChannel2Enable(); 31 | void onToggleSampling(); 32 | 33 | void onTimeBaseSelected(); 34 | void onScopeModeSelected(); 35 | void onCaptureModeSelected(); 36 | 37 | void onTriggerModeSelected(); 38 | void onTriggerChannelSelected(); 39 | void onTriggerSlopeSelected(); 40 | 41 | // Internal UI update methods 42 | void updateConnectionControls(); 43 | void updateDeviceInfo(); 44 | void updateChannelsInfo(); 45 | void updateTriggerInfo(); 46 | 47 | // Protected Members - Gtk 48 | RefPtr refGlade; 49 | 50 | TransmissionLogDialog *pTransmissionLogDialog; 51 | Button *pButtonTransmissionLog; 52 | Button *pButtonConnect; 53 | ProgressBar *pProgressbarConnection; 54 | Label *pConnectionStatus; 55 | 56 | LevelBar *pBatteryLevel; 57 | Label *pDeviceInfo; 58 | ToggleButton *pToggleSampling; 59 | ComboBox *pTimeBase; 60 | ComboBox *pScopeMode; 61 | ComboBox *pCaptureMode; 62 | RefPtr pTimeBaseStore; 63 | RefPtr pScopeModeStore; 64 | RefPtr pCaptureModeStore; 65 | 66 | ToggleButton *pChannel1Enabled; 67 | ToggleButton *pChannel2Enabled; 68 | 69 | ComboBox *pTriggerMode; 70 | ComboBox *pTriggerChannel; 71 | ComboBox *pTriggerSlope; 72 | RefPtr pTriggerModeStore; 73 | RefPtr pTriggerChannelStore; 74 | RefPtr pTriggerSlopeStore; 75 | 76 | // Protocol worker thread pointer 77 | ProtocolWorker *worker; 78 | 79 | IDSO1070 device; 80 | 81 | private: 82 | class TextComboColumns : public TreeModel::ColumnRecord 83 | { 84 | public: 85 | TextComboColumns() 86 | { 87 | // This order must match the column order in the .glade file 88 | this->add(this->title); 89 | this->add(this->value); 90 | } 91 | 92 | // These types must match those for the model in the .glade file 93 | Gtk::TreeModelColumn title; 94 | Gtk::TreeModelColumn value; 95 | }; 96 | 97 | TextComboColumns textComboColumns; 98 | }; 99 | 100 | #endif // _SETTINGS_WIDGET_H_ -------------------------------------------------------------------------------- /capture_wifi2.hexdump: -------------------------------------------------------------------------------- 1 | ... 2 | 00000034 55 17 00 00 // Unkown command 3 | ... 4 | 0000005C aa 02 00 00 5 | 00000060 57 04 00 00 6 | 00000064 57 03 00 00 7 | 00000068 55 11 00 00 8 | 0000006C 55 12 04 00 9 | 00000070 55 13 00 00 10 | 00000074 55 04 02 00 // Channel selection 11 | 00000078 55 05 91 00 12 | 0000007C 55 0d b5 0a 13 | 00000080 55 07 ed 03 // Pre trigger length 14 | 00000084 55 08 e8 03 // Post trigger length 15 | 00000088 55 16 d0 77 // Read RAM count 16 | 0000008C 55 0e 92 24 17 | 00000090 55 0f 49 92 18 | 00000094 55 10 24 49 19 | 00000098 55 15 00 00 // RAM channel selection 20 | 0000009C 55 03 80 00 // Set relay 21 | 000000A0 55 03 02 00 // Set relay 22 | 000000A4 55 06 00 00 // Channel volts div 125 23 | 000000A8 55 0b 3e 08 // Channel 1 PWM 24 | 000000AC 55 03 ef 00 // Set relay 25 | 000000B0 55 06 00 00 // Channel volts div 125 26 | 000000B4 55 03 40 00 // Set relay 27 | 000000B8 55 03 04 00 // Set relay 28 | 000000BC 55 06 00 00 // Channel volts div 125 29 | 000000C0 55 0c 7d 05 // Channel 2 PWM 30 | 000000C4 55 03 fe 00 // Set relay 31 | 000000C8 55 06 00 00 // Channel volts div 125 32 | 000000CC 55 02 02 00 // Trigger mode 33 | 000000D0 aa 04 00 00 34 | 000000D4 55 02 02 00 // Trigger mode 35 | 000000D8 55 02 02 00 // Trigger mode 36 | 000000DC aa 04 00 00 37 | 000000E0 aa 04 00 00 38 | 000000E4 55 11 00 00 // Set TimeBase 20us 39 | 000000E8 55 11 00 00 40 | 000000EC 55 12 09 00 41 | 000000F0 55 13 00 00 42 | 000000F4 55 04 02 00 // Channel selection 43 | 000000F8 55 07 ed 03 // Pre trigger length 44 | 000000FC 55 08 e8 03 // Post trigger length 45 | 00000100 55 16 d0 77 // Read RAM count 46 | 00000104 55 15 00 00 // RAM channel selection 47 | 00000108 55 11 00 00 // Set TimeBase 50us 48 | 0000010C 55 11 00 00 49 | 00000110 55 12 18 00 50 | 00000114 55 13 00 00 51 | 00000118 55 04 02 00 // Channel selection 52 | 0000011C 55 07 ed 03 // Pre trigger length 53 | 00000120 55 08 e8 03 // Post trigger length 54 | 00000124 55 16 d0 77 // Read RAM count 55 | 00000128 55 15 00 00 // RAM channel selection 56 | 0000012C 55 11 00 00 // Set TimeBase 100us 57 | 00000130 55 12 31 00 58 | 00000134 55 13 00 00 59 | 00000138 55 04 02 00 // Channel selection 60 | 0000013C 55 07 ed 03 // Pre trigger length 61 | 00000140 55 08 e8 03 // Post trigger length 62 | 00000144 55 16 d0 77 // Read RAM count 63 | 00000148 55 15 00 00 // RAM channel selection 64 | 0000014C 55 11 00 00 // Set TimeBase 200us 65 | 00000150 55 12 63 00 66 | 00000154 55 13 00 00 67 | 00000158 55 04 02 00 // Channel selection 68 | 0000015C 55 07 ed 03 // Pre trigger length 69 | 00000160 55 08 e8 03 // Post trigger length 70 | 00000164 55 16 d0 77 // Read RAM count 71 | 00000168 55 15 00 00 // RAM channel selection 72 | 0000016C 55 02 02 00 // Trigger mode 73 | 00000170 aa 04 00 00 74 | 00000174 55 15 00 00 // RAM channel selection 75 | 00000178 55 15 00 00 // RAM channel selection -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Mac", 5 | "includePath": [ 6 | "/usr/include", 7 | "/usr/local/include", 8 | "${workspaceRoot}" 9 | ], 10 | "defines": [], 11 | "intelliSenseMode": "clang-x64", 12 | "browse": { 13 | "path": [ 14 | "/usr/include", 15 | "/usr/local/include", 16 | "${workspaceRoot}" 17 | ], 18 | "limitSymbolsToIncludedHeaders": true, 19 | "databaseFilename": "" 20 | }, 21 | "macFrameworkPath": [ 22 | "/System/Library/Frameworks", 23 | "/Library/Frameworks" 24 | ] 25 | }, 26 | { 27 | "name": "Linux", 28 | "includePath": [ 29 | "/usr/include/c++/5", 30 | "/usr/include/x86_64-linux-gnu/c++/5", 31 | "/usr/include/c++/5/backward", 32 | "/usr/lib/gcc/x86_64-linux-gnu/5/include", 33 | "/usr/local/include", 34 | "/usr/lib/gcc/x86_64-linux-gnu/5/include-fixed", 35 | "/usr/include/x86_64-linux-gnu", 36 | "/usr/include", 37 | "${workspaceRoot}", 38 | "${workspaceRoot}/include", 39 | "/usr/include/gtkmm-3.0", 40 | "/usr/include/gdkmm-3.0", 41 | "/usr/include/gtkmm-plplot-2.0" 42 | ], 43 | "defines": [], 44 | "intelliSenseMode": "clang-x64", 45 | "browse": { 46 | "path": [ 47 | "/usr/include/c++/5", 48 | "/usr/include/x86_64-linux-gnu/c++/5", 49 | "/usr/include/c++/5/backward", 50 | "/usr/lib/gcc/x86_64-linux-gnu/5/include", 51 | "/usr/local/include", 52 | "/usr/lib/gcc/x86_64-linux-gnu/5/include-fixed", 53 | "/usr/include/x86_64-linux-gnu", 54 | "/usr/include", 55 | "${workspaceRoot}" 56 | ], 57 | "limitSymbolsToIncludedHeaders": true, 58 | "databaseFilename": "" 59 | } 60 | }, 61 | { 62 | "name": "Win32", 63 | "includePath": [ 64 | "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include", 65 | "${workspaceRoot}" 66 | ], 67 | "defines": [ 68 | "_DEBUG", 69 | "UNICODE" 70 | ], 71 | "intelliSenseMode": "msvc-x64", 72 | "browse": { 73 | "path": [ 74 | "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include/*", 75 | "${workspaceRoot}" 76 | ], 77 | "limitSymbolsToIncludedHeaders": true, 78 | "databaseFilename": "" 79 | } 80 | } 81 | ], 82 | "version": 3 83 | } -------------------------------------------------------------------------------- /include/enums.h: -------------------------------------------------------------------------------- 1 | #ifndef _ENUMS_H_ 2 | #define _ENUMS_H_ 3 | 4 | enum CommandCode 5 | { 6 | CMDCODE_FORCE_TRIGGER = 0x01, 7 | CMDCODE_TRIGGER_MODE = 0x02, 8 | CMDCODE_SET_RELAY = 0x03, 9 | CMDCODE_CHANNEL_SELECTION = 0x04, 10 | CMDCODE_TRIGGER_SOURCE = 0x05, 11 | CMDCODE_CHANNEL_VOLTS_DIV_125 = 0x06, 12 | CMDCODE_PRE_TRIGGER_LENGTH = 0x07, 13 | CMDCODE_POST_TRIGGER_LENGTH = 0x08, 14 | CMDCODE_RAM_START_POSITION = 0x09, 15 | CMDCODE_RESERVED_DATA_OUTPUT = 0x0a, 16 | CMDCODE_CH1_PWM = 0x0b, 17 | CMDCODE_CH2_PWM = 0x0c, 18 | CMDCODE_TRIGGER_PWM = 0x0d, 19 | CMDCODE_LOGIC_ANALYZER_1 = 0x0e, 20 | CMDCODE_LOGIC_ANALYZER_2 = 0x0f, 21 | CMDCODE_LOGIC_ANALYZER_3 = 0x10, 22 | CMDCODE_SAMPLE_RATE = 0x11, 23 | CMDCODE_FREQ_DIV_LOW = 0x12, 24 | CMDCODE_FREQ_DIV_HIGH = 0x13, 25 | CMDCODE_SERIAL_BAUD_RATE = 0x14, 26 | CMDCODE_RAM_CHANNEL_SELECTION = 0x15, 27 | CMDCODE_READ_RAM_COUNT = 0x16 28 | }; 29 | 30 | enum CommandType 31 | { 32 | TYPE_CONTROL = 0xaa, 33 | TYPE_EEPROM = 0xee, 34 | TYPE_FPGA = 0x55, 35 | TYPE_STATE = 0x57 36 | }; 37 | 38 | enum ConnectorType 39 | { 40 | CONNECTOR_USB, 41 | CONNECTOR_WIFI 42 | }; 43 | 44 | enum ParseChVoltsDivStatus 45 | { 46 | PARSE_CHVOLTSDIV_S0, 47 | PARSE_CHVOLTSDIV_S125, 48 | PARSE_CHVOLTSDIV_SR1, 49 | PARSE_CHVOLTSDIV_SR2, 50 | PARSE_CHVOLTSDIV_S125R1, 51 | PARSE_CHVOLTSDIV_S125R2, 52 | PARSE_CHVOLTSDIV_SR1125, 53 | PARSE_CHVOLTSDIV_SR1R2, 54 | PARSE_CHVOLTSDIV_SR2R1, 55 | PARSE_CHVOLTSDIV_SR2125 56 | }; 57 | 58 | enum TimeBase 59 | { 60 | // HDIV_5nS = 0, 61 | // HDIV_10nS = 1, 62 | // HDIV_20nS = 2, 63 | // HDIV_50nS = 3, 64 | // HDIV_100nS = 4, 65 | // HDIV_200nS = 5, 66 | // HDIV_500nS = 6, 67 | // HDIV_1uS = 7, 68 | HDIV_2uS = 0, 69 | HDIV_5uS = 1, 70 | HDIV_10uS = 4, 71 | HDIV_20uS = 9, 72 | HDIV_50uS = 24, 73 | HDIV_100uS = 49, 74 | HDIV_200uS = 99, 75 | HDIV_500uS = 249, 76 | HDIV_1mS = 499, 77 | HDIV_2mS = 999, 78 | HDIV_5mS = 2499, 79 | HDIV_10mS = 4999, 80 | HDIV_20mS = 9999, 81 | HDIV_50mS = 24999, 82 | HDIV_100mS = 49999, 83 | HDIV_200mS = 99999, 84 | HDIV_500mS = 249999, 85 | HDIV_1S = 499999, 86 | HDIV_2S = 999999, 87 | HDIV_5S = 2499999, 88 | HDIV_10S = 4999999, 89 | HDIV_20S = 9999999, 90 | HDIV_50S = 24999999, 91 | HDIV_100S = 49999999, 92 | HDIV_200S = 99999999, 93 | HDIV_500S = 249999999 94 | }; 95 | 96 | enum VoltageDiv 97 | { 98 | VDIV_10mV, 99 | VDIV_20mV, 100 | VDIV_50mV, 101 | VDIV_100mV, 102 | VDIV_200mV, 103 | VDIV_500mV, 104 | VDIV_1V, 105 | VDIV_2V, 106 | VDIV_5V 107 | }; 108 | 109 | enum InputCoupling 110 | { 111 | COUPLING_AC, 112 | COUPLING_DC, 113 | COUPLING_GND 114 | }; 115 | 116 | enum CaptureMode 117 | { 118 | CAPMODE_ROLL, 119 | CAPMODE_SCAN, 120 | CAPMODE_NORMAL 121 | }; 122 | 123 | enum ScopeMode 124 | { 125 | SCOMODE_ANALOG, 126 | SCOMODE_DIGITAL 127 | }; 128 | 129 | enum ChannelSelector 130 | { 131 | CHANNEL_1, 132 | CHANNEL_2 133 | }; 134 | 135 | enum TriggerChannel 136 | { 137 | TRIGCHAN_CH1, 138 | TRIGCHAN_CH2, 139 | TRIGCHAN_EXT, 140 | TRIGCHAN_EXT10, 141 | TRIGCHAN_ALT 142 | }; 143 | 144 | enum TriggerMode 145 | { 146 | TRIGMODE_AUTO, 147 | TRIGMODE_NORMAL, 148 | TRIGMODE_SINGLE 149 | }; 150 | 151 | enum TriggerSlope 152 | { 153 | TRIGSLOPE_RISING, 154 | TRIGSLOPE_FALLING 155 | }; 156 | 157 | #endif // _ENUMS_H_ -------------------------------------------------------------------------------- /lib/connection/USBConnector.cxx: -------------------------------------------------------------------------------- 1 | #include "connection/USBConnector.h" 2 | 3 | USBConnector::USBConnector(string device) : device(device), handle(-1) 4 | { 5 | } 6 | 7 | USBConnector::~USBConnector() 8 | { 9 | if (handle < 0) 10 | close(handle); 11 | } 12 | 13 | void USBConnector::start() 14 | { 15 | if (handle != -1) 16 | return; 17 | 18 | termios tty; 19 | handle = open(device.c_str(), O_RDWR | O_NOCTTY | O_SYNC); 20 | if (!handle) 21 | { 22 | throw Exception("Cannot open device"); 23 | } 24 | memset(&tty, 0, sizeof tty); 25 | int res = 0; 26 | if ((res = tcgetattr(handle, &tty)) != 0) 27 | { 28 | throw Exception("Cannot read serial port configuration"); 29 | } 30 | 31 | cfsetospeed(&tty, USBSerialSpeed); 32 | cfsetispeed(&tty, USBSerialSpeed); 33 | 34 | tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars 35 | // disable IGNBRK for mismatched speed tests; otherwise receive break 36 | // as \000 chars 37 | tty.c_iflag &= ~IGNBRK; // disable break processing 38 | tty.c_lflag = 0; // no signaling chars, no echo, 39 | // no canonical processing 40 | tty.c_oflag = 0; // no remapping, no delays 41 | tty.c_cc[VMIN] = 0; // read doesn't block 42 | tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout 43 | 44 | tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl 45 | 46 | tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls, 47 | // enable reading 48 | tty.c_cflag &= ~(PARENB | PARODD); // shut off parity 49 | tty.c_cflag &= ~CSTOPB; 50 | tty.c_cflag &= ~CRTSCTS; 51 | 52 | tty.c_cc[VMIN] = 0; // Set non-blocking 53 | tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout 54 | 55 | if ((res = tcsetattr(handle, TCSANOW, &tty)) != 0) 56 | { 57 | throw Exception("Cannot set serial port configuration"); 58 | } 59 | 60 | connected = true; 61 | } 62 | 63 | void USBConnector::stop() 64 | { 65 | if (handle != -1) 66 | close(handle); 67 | connected = false; 68 | handle = -1; 69 | } 70 | 71 | ConnectorType USBConnector::getType() 72 | { 73 | return CONNECTOR_USB; 74 | } 75 | 76 | void USBConnector::transmit(uint8_t *data, size_t length) 77 | { 78 | if (handle == -1) 79 | return; 80 | int res = 0; 81 | if ((res = write(handle, data, length)) < 0) 82 | { 83 | stop(); 84 | throw Exception("Connection lost"); 85 | } 86 | } 87 | 88 | void USBConnector::receive() 89 | { 90 | if (!rawBuffer.full()) 91 | { 92 | size_t size = RawBufferLength - rawBuffer.size(); 93 | uint8_t localBuffer[size]; 94 | if (handle == -1) 95 | return; 96 | ssize_t receivedSize = read(handle, localBuffer, size); 97 | if (receivedSize < 0) 98 | { 99 | stop(); 100 | throw Exception("Connection lost"); 101 | } 102 | else if (receivedSize > 0) 103 | { 104 | for (ssize_t i = 0; i < receivedSize; i++) 105 | rawBuffer.push_back(localBuffer[i]); 106 | } 107 | } 108 | grabPacket(); 109 | } 110 | 111 | void USBConnector::enumerateDevices(USBDeviceList &list) 112 | { 113 | DIR *dp; 114 | dirent *dirp; 115 | const char *path = "/sys/class/tty"; 116 | if ((dp = opendir(path)) == NULL) 117 | { 118 | return; 119 | } 120 | 121 | while ((dirp = readdir(dp)) != NULL) 122 | { 123 | if (dirp->d_type == DT_LNK) 124 | { 125 | string currentPath = path; 126 | currentPath += "/"; 127 | currentPath += dirp->d_name; 128 | currentPath += "/device"; 129 | struct stat buffer; 130 | if (stat(currentPath.c_str(), &buffer) == 0) 131 | { 132 | string infoPath = currentPath; 133 | infoPath += "/modalias"; 134 | int info = open(infoPath.c_str(), O_RDONLY); 135 | if (info != -1) 136 | { 137 | char buffer[15]; 138 | int size = read(info, buffer, 14); 139 | buffer[14] = 0; 140 | close(info); 141 | if (strcmp(buffer, "usb:v0483p5740") == 0) 142 | { 143 | string dev = "/dev/"; 144 | dev += dirp->d_name; 145 | list.push_back(dev); 146 | } 147 | } 148 | } 149 | } 150 | } 151 | closedir(dp); 152 | } -------------------------------------------------------------------------------- /include/IDSO1070.h: -------------------------------------------------------------------------------- 1 | #ifndef _IDSO1070_H_ 2 | #define _IDSO1070_H_ 3 | 4 | #include "base.h" 5 | 6 | class Protocol; 7 | class PacketParser; 8 | 9 | class IDSO1070 10 | { 11 | friend class Protocol; 12 | friend class PacketParser; 13 | 14 | public: 15 | static const int MaxPWM = 4095; 16 | static const int MemoryDepth = 2000; 17 | static const int SamplesCountPerPacket = 500; 18 | static const int MaxSample = 248; 19 | static const int DeviceMemoryDepth = 6 * 1024; 20 | 21 | struct DeviceSettings 22 | { 23 | TimeBase timeBase; 24 | 25 | ScopeMode scopeMode; 26 | CaptureMode captureMode; 27 | 28 | uint8_t batteryLevel; 29 | 30 | string armFirmwareVersion; 31 | string fpgaFirmwareVersion; 32 | string productName; 33 | string userName; 34 | 35 | uint8_t diffFixData[2][256]; 36 | uint16_t caliLevel[100]; 37 | uint8_t fpgaAlert[40]; 38 | }; 39 | struct ChannelSettings 40 | { 41 | bool enabled; 42 | VoltageDiv verticalDiv; 43 | InputCoupling coupling; 44 | int8_t verticalPosition; 45 | uint16_t pwmArray[9][2]; 46 | 47 | double voltage125; 48 | double voltageRL1; 49 | double voltageRL2; 50 | }; 51 | struct TriggerSettings 52 | { 53 | bool isHold = false; 54 | TriggerMode mode; 55 | TriggerChannel channel; 56 | TriggerSlope slope; 57 | uint16_t level; 58 | double xPosition; 59 | uint16_t innerPWM[4]; 60 | uint16_t outerPWM[2]; 61 | }; 62 | 63 | IDSO1070(); 64 | 65 | // Copy assignment operator 66 | IDSO1070 &operator=(IDSO1070 obj); 67 | 68 | // General device settings 69 | TimeBase getTimeBase(); 70 | CaptureMode getCaptureMode(); 71 | ScopeMode getScopeMode(); 72 | string getARMFirmwareVersion(); 73 | string getFPGAFirmwareVersion(); 74 | string getProductName(); 75 | string getUserName(); 76 | uint16_t *getCaliLevel(); 77 | uint8_t *getFPGAAlert(); 78 | uint8_t getBatteryLevel(); 79 | 80 | // Channel data access methods 81 | ChannelSelector getSelectedChannel(); 82 | bool isChannelEnabled(ChannelSelector channel); 83 | VoltageDiv getChannelVerticalDiv(ChannelSelector channel); 84 | InputCoupling getChannelCoupling(ChannelSelector channel); 85 | int8_t getChannelVerticalPosition(ChannelSelector channel); 86 | uint16_t getChannelPWM(ChannelSelector channel, uint8_t a, uint8_t b); 87 | uint16_t *getChannelPWM(ChannelSelector channel, uint8_t a); 88 | double getChannelVoltage125(ChannelSelector channel); 89 | double getChannelVoltageRL1(ChannelSelector channel); 90 | double getChannelVoltageRL2(ChannelSelector channel); 91 | 92 | // Trigger data access methods 93 | uint16_t getTriggerLevel(); 94 | TriggerChannel getTriggerChannel(); 95 | TriggerSlope getTriggerSlope(); 96 | TriggerMode getTriggerMode(); 97 | double getTriggerXPosition(); 98 | uint16_t getTriggerInnerPWM(uint8_t index); 99 | uint16_t *getTriggerInnerPWM(); 100 | uint16_t getTriggerOuterPWM(uint8_t index); 101 | uint16_t *getTriggerOuterPWM(); 102 | uint16_t getTriggerBottomPWM(); 103 | uint16_t getTriggerTopPWM(); 104 | 105 | // Misc 106 | bool isSampling(); 107 | int getLittlePacketStatus(); 108 | size_t getSamplesNumberOfOneFrame(); 109 | uint8_t getEnabledChannelsCount(); 110 | uint8_t getPacketsNumber(); 111 | 112 | protected: 113 | // All setters are protected! 114 | void setTimeBase(TimeBase timeBase); 115 | void setCaptureMode(CaptureMode captureMode); 116 | void setScopeMode(ScopeMode scopeMode); 117 | void setARMFirmwareVersion(string version); 118 | void setFPGAFirmwareVersion(string version); 119 | void setProductName(string productName); 120 | void setUserName(string userName); 121 | void setCaliLevel(uint8_t *data); 122 | void setFPGAAlert(uint8_t *data); 123 | void setDiffFixData(size_t channel, size_t offset, uint8_t *data); 124 | void setBatteryLevel(uint8_t batteryLevel); 125 | void setSelectedChannel(ChannelSelector channel); 126 | void enableChannel(ChannelSelector channel); 127 | void disableChannel(ChannelSelector channel); 128 | void setChannelVerticalDiv(ChannelSelector channel, VoltageDiv verticalDiv); 129 | void setChannelCoupling(ChannelSelector channel, InputCoupling coupling); 130 | void setChannelVerticalPosition(ChannelSelector channel, int16_t verticalPosition); 131 | void setChannelPWM(ChannelSelector channel, uint16_t pwm, uint8_t a, uint8_t b); 132 | void setChannelVoltage125(ChannelSelector channel, double voltage); 133 | void setChannelVoltageRL1(ChannelSelector channel, double voltage); 134 | void setChannelVoltageRL2(ChannelSelector channel, double voltage); 135 | void setTriggerLevel(uint16_t i); 136 | void setTriggerChannel(TriggerChannel channel); 137 | void setTriggerSlope(TriggerSlope slope); 138 | void setTriggerMode(TriggerMode mode); 139 | void setTriggerXPosition(double xPosition); 140 | void setTriggerInnerPWM(uint8_t index, uint16_t pwm); 141 | void setTriggerOuterPWM(uint8_t index, uint16_t pwm); 142 | void setSampling(bool sampling); 143 | void setLittlePacketStatus(int littlePacketStatus); 144 | 145 | private: 146 | // Device members 147 | DeviceSettings deviceSettings; 148 | 149 | // Channel members 150 | ChannelSettings channels[2]; 151 | ChannelSelector selectedChannel; 152 | 153 | // Trigger members 154 | TriggerSettings triggerSettings; 155 | 156 | // Misc 157 | int littlePacketStatus; 158 | bool sampling = false; 159 | }; 160 | 161 | #endif // _IDSO1070_H_ -------------------------------------------------------------------------------- /include/Protocol.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROTOCOL_H_ 2 | #define _PROTOCOL_H_ 3 | 4 | #include "base.h" 5 | #include "IDSO1070.h" 6 | 7 | #include "connection/TCPConnector.h" 8 | #include "connection/USBConnector.h" 9 | 10 | #include "packets/SampleBuffer.h" 11 | #include "packets/Sample.h" 12 | #include "packets/Response.h" 13 | #include "packets/Command.h" 14 | #include "packets/CommandFactory.h" 15 | 16 | #include 17 | 18 | class Protocol 19 | { 20 | public: 21 | // Definition of event handler types 22 | typedef function ProgressHandler; 23 | typedef function ConnectionLostHandler; 24 | 25 | struct Transmission 26 | { 27 | Command command; 28 | Response response; 29 | 30 | Transmission(Command &command, Response &response) : command(command), response(response) {} 31 | }; 32 | typedef vector TransmissionLog; 33 | 34 | Protocol(); 35 | ~Protocol(); 36 | 37 | // Connection control 38 | void connect(string serialDevice); 39 | void connect(string serverHost, int port); 40 | void disconnect(); 41 | 42 | // Called in main loop 43 | void process(); 44 | 45 | void sendCommand(Command *cmd); 46 | void sendCommandBatch(deque cmds, Command::ResponseHandler finishedHandler); 47 | 48 | // Device control 49 | void init(Command::ResponseHandler responseHandler); 50 | void readBatteryLevel(Command::ResponseHandler responseHandler); 51 | void setTimeBase(TimeBase timeBase, Command::ResponseHandler responseHandler); 52 | void setScopeMode(ScopeMode scopeMode, Command::ResponseHandler responseHandler); 53 | void setCaptureMode(CaptureMode captureMode, Command::ResponseHandler responseHandler); 54 | 55 | // Channel control 56 | void enableChannel(ChannelSelector channel, Command::ResponseHandler responseHandler); 57 | void disableChannel(ChannelSelector channel, Command::ResponseHandler responseHandler); 58 | void setChannelVerticalDiv(ChannelSelector channel, VoltageDiv div, Command::ResponseHandler responseHandler); 59 | void setChannelCoupling(ChannelSelector channel, InputCoupling coupling, Command::ResponseHandler responseHandler); 60 | void setChannelVerticalPosition(ChannelSelector channel, uint16_t pos, Command::ResponseHandler responseHandler); 61 | 62 | // Trigger control 63 | void setTriggerMode(TriggerMode mode, Command::ResponseHandler responseHandler); 64 | void setTriggerChannel(TriggerChannel channel, Command::ResponseHandler responseHandler); 65 | void setTriggerSlope(TriggerSlope slope, Command::ResponseHandler responseHandler); 66 | void setTriggerLevel(uint16_t level, Command::ResponseHandler responseHandler); 67 | 68 | // Sampling control 69 | void startSampling(Command::ResponseHandler responseHandler); 70 | void stopSampling(Command::ResponseHandler responseHandler); 71 | 72 | // Set event handlers 73 | void setConnectionLostHandler(ConnectionLostHandler connectionLostHandler); 74 | void setProgressHandler(ProgressHandler progressHandler); 75 | 76 | Connector *getConnector(); 77 | void fetchSamples(SampleBuffer &buffer); 78 | void fetchDevice(IDSO1070 &dev); 79 | 80 | void fetchTransmissionLog(TransmissionLog &log); 81 | void clearTransmissionLog(bool deleteObjects = true); 82 | void clearCommandQueue(); 83 | 84 | private: 85 | static const int MaxCommandRetries = 3; 86 | 87 | // For thread safety 88 | mutable mutex deviceMutex; 89 | // mutable mutex protocolMutex; 90 | mutable mutex sampleMutex; 91 | mutable mutex logMutex; 92 | mutable mutex commandMutex; 93 | 94 | // Device class to store the device's states and resources 95 | IDSO1070 device; 96 | 97 | // Connector abstraction for USB/TCP communication 98 | Connector *connector = NULL; 99 | ConnectionLostHandler connectionLostHandler; 100 | 101 | ProgressHandler progressHandler; 102 | 103 | // Command dispatching related members 104 | CommandFactory cmdFactory; 105 | deque commandQueue; 106 | int retries = 0; 107 | Command *currentCommand = NULL; 108 | 109 | // Response handling related members 110 | Response *currentResponse = NULL; 111 | bool ignoreNextResponse = false; 112 | 113 | // Parser and sample data buffers 114 | SampleBuffer sampleBuffer; 115 | TransmissionLog transmissionLog; 116 | 117 | // Internal methods (called by process()) 118 | void receive(); 119 | void transmit(); 120 | 121 | // Second stage of device initialization 122 | void initStage2(Command::ResponseHandler finishedHandler); 123 | 124 | void parse(Response *packet); 125 | void parse(Sample *packet); 126 | 127 | // Response parsing 128 | void parseAAResponse(Response *packet); 129 | void parseEEResponse(Response *packet); 130 | void parseFPGAResponse(Response *packet); 131 | void parseStateResponse(Response *packet); 132 | void parseFreqDivLowBytes(Response *packet); 133 | void parseFreqDivHighBytes(Response *packet); 134 | void parseRamChannelSelection(Response *packet); 135 | void parseCh1ZeroLevel(Response *packet); 136 | void parseCh2ZeroLevel(Response *packet); 137 | void parseRelay(Response *packet); 138 | void parseVoltsDiv125(Response *packet); 139 | void parseTriggerLevel(Response *packet); 140 | void parseTriggerSourceAndSlope(Response *packet); 141 | void parseTriggerMode(Response *packet); 142 | void parseEEPROMPage00(Response *packet); 143 | void parseCoupling(Response *packet); 144 | 145 | // Sample parsing 146 | void parseSamplePacket(Sample *packet, int index); 147 | void parseBothChannelsData(Sample *packet, int index); 148 | void parseChannel1Data(Sample *packet, int index); 149 | void parseChannel2Data(Sample *packet, int index); 150 | void interpolateSamples(); 151 | }; 152 | 153 | #endif // _PROTOCOL_H_ -------------------------------------------------------------------------------- /gui/ScopeWidget.cxx: -------------------------------------------------------------------------------- 1 | #include "ScopeWidget.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | ScopeWidget::ScopeWidget(ProtocolWorker *worker) : Glib::ObjectBase("scopewidget"), 10 | Gtk::Widget(), 11 | worker(worker) 12 | { 13 | set_has_window(true); 14 | set_name("scope-widget"); 15 | // while (sampleBuffer.channel1.size() < sampleBuffer.channel1.capacity()) 16 | // sampleBuffer.channel1.push_back(0); 17 | // while (sampleBuffer.channel2.size() < sampleBuffer.channel2.capacity()) 18 | // sampleBuffer.channel2.push_back(0); 19 | } 20 | 21 | ScopeWidget::~ScopeWidget() 22 | { 23 | } 24 | 25 | void ScopeWidget::update() 26 | { 27 | worker->fetchDevice(device); 28 | worker->fetchSamples(sampleBuffer); 29 | queue_draw(); 30 | } 31 | 32 | void ScopeWidget::on_size_allocate(Gtk::Allocation &allocation) 33 | { 34 | set_allocation(allocation); 35 | 36 | if (refGdkWindow) 37 | { 38 | refGdkWindow->move_resize(allocation.get_x(), allocation.get_y(), 39 | allocation.get_width(), allocation.get_height()); 40 | } 41 | } 42 | 43 | void ScopeWidget::on_realize() 44 | { 45 | set_realized(); 46 | 47 | // If there is no reference to a GdkWindow, then create one 48 | if (!refGdkWindow) 49 | { 50 | 51 | GdkWindowAttr attributes; 52 | memset(&attributes, 0, sizeof(attributes)); 53 | 54 | Gtk::Allocation allocation = get_allocation(); 55 | 56 | // Set initial position and size of the Gdk::Window: 57 | attributes.x = allocation.get_x(); 58 | attributes.y = allocation.get_y(); 59 | attributes.width = allocation.get_width(); 60 | attributes.height = allocation.get_height(); 61 | 62 | attributes.event_mask = get_events() | Gdk::EXPOSURE_MASK; 63 | attributes.window_type = GDK_WINDOW_CHILD; 64 | attributes.wclass = GDK_INPUT_OUTPUT; 65 | 66 | refGdkWindow = Gdk::Window::create(get_parent_window(), &attributes, 67 | GDK_WA_X | GDK_WA_Y); 68 | set_window(refGdkWindow); 69 | 70 | // Make the widget receive expose events 71 | refGdkWindow->set_user_data(gobj()); 72 | } 73 | } 74 | 75 | void ScopeWidget::on_unrealize() 76 | { 77 | refGdkWindow.reset(); 78 | 79 | Gtk::Widget::on_unrealize(); 80 | } 81 | 82 | bool ScopeWidget::on_draw(const Cairo::RefPtr &cr) 83 | { 84 | const Gtk::Allocation allocation = get_allocation(); 85 | double width = (double)(allocation.get_width() - (ScopePadding * 2)); 86 | double height = (double)(allocation.get_height() - (ScopePadding * 2)); 87 | 88 | double xScale = (width - (double)((int)width % DivColumns)) / (double)DivColumns; 89 | double yScale = (height - (double)((int)height % DivRows)) / (double)DivRows; 90 | 91 | double xTranslate; 92 | double yTranslate; 93 | 94 | if (xScale > yScale) 95 | { 96 | xTranslate = ((width - yScale * DivColumns) / 2) + (double)ScopePadding; 97 | yTranslate = ((height - yScale * DivRows) / 2) + (double)ScopePadding; 98 | cr->translate(xTranslate, yTranslate); 99 | cr->scale(yScale, yScale); 100 | cr->set_line_width(1.0 / yScale); 101 | } 102 | else if (yScale > xScale) 103 | { 104 | xTranslate = ((width - xScale * DivColumns) / 2) + (double)ScopePadding; 105 | yTranslate = ((height - xScale * DivRows) / 2) + (double)ScopePadding; 106 | cr->translate(xTranslate, yTranslate); 107 | cr->scale(xScale, xScale); 108 | cr->set_line_width(1.0 / xScale); 109 | } 110 | else 111 | { 112 | xTranslate = ((width - yScale * DivColumns) / 2) + (double)ScopePadding; 113 | yTranslate = ((height - yScale * DivRows) / 2) + (double)ScopePadding; 114 | cr->translate(xTranslate, yTranslate); 115 | cr->scale(yScale, yScale); 116 | cr->set_line_width(1.0 / yScale); 117 | } 118 | 119 | // Fill background 120 | Gdk::Cairo::set_source_rgba(cr, Gdk::RGBA("rgb(0, 0, 0)")); 121 | cr->paint(); 122 | 123 | drawGrid(cr); 124 | 125 | drawChannel1(cr); 126 | drawChannel2(cr); 127 | 128 | return true; 129 | } 130 | 131 | void ScopeWidget::drawGrid(const Cairo::RefPtr &cr) 132 | { 133 | const double width = (double)DivColumns; 134 | const double height = (double)DivRows; 135 | 136 | // Draw scope background 137 | Gdk::Cairo::set_source_rgba(cr, Gdk::RGBA("rgb(71, 71, 71)")); 138 | cr->rectangle(0.0, 0.0, width, height); 139 | cr->fill(); 140 | 141 | // Draw column divs 142 | Gdk::Cairo::set_source_rgba(cr, Gdk::RGBA("rgb(50, 50, 50)")); 143 | for (int c = 0; c < (DivColumns - 1); c++) 144 | { 145 | if ((c + 1) != (DivColumns / 2)) 146 | { 147 | double xOffset = (width / (double)DivColumns) * ((double)c + 1); 148 | cr->move_to(xOffset, 0.0); 149 | cr->line_to(xOffset, height); 150 | cr->stroke(); 151 | } 152 | } 153 | 154 | // Draw row divs 155 | for (int r = 0; r < (DivRows - 1); r++) 156 | { 157 | if ((r + 1) != (DivRows / 2)) 158 | { 159 | double yOffset = (height / (double)DivRows) * ((double)r + 1); 160 | cr->move_to(0.0, yOffset); 161 | cr->line_to(width, yOffset); 162 | cr->stroke(); 163 | cr->stroke(); 164 | } 165 | } 166 | 167 | // Draw center cross 168 | Gdk::Cairo::set_source_rgba(cr, Gdk::RGBA("rgb(200, 200, 200)")); 169 | cr->move_to(width / 2, 0.0); 170 | cr->line_to(width / 2, height); 171 | cr->move_to(0.0, height / 2); 172 | cr->line_to(width, height / 2); 173 | cr->stroke(); 174 | 175 | // Draw frame 176 | Gdk::Cairo::set_source_rgba(cr, Gdk::RGBA("rgb(200, 200, 200)")); 177 | cr->move_to(0.0, 0.0); 178 | cr->line_to(width, 0.0); 179 | cr->line_to(width, height); 180 | cr->line_to(0.0, height); 181 | cr->line_to(0.0, 0.0); 182 | cr->stroke(); 183 | } 184 | 185 | void ScopeWidget::drawChannel1(const Cairo::RefPtr &cr) 186 | { 187 | Gdk::Cairo::set_source_rgba(cr, Gdk::RGBA("rgb(135, 180, 255)")); 188 | 189 | // Draw level 190 | double xOffset = -0.5; 191 | double yOffset = (8.0 / 256.0) * (256 - (uint8_t)device.getChannelVerticalPosition(CHANNEL_1)); 192 | cr->rectangle(xOffset, yOffset - 0.05, 0.3, 0.1); 193 | cr->fill(); 194 | 195 | // Draw samples 196 | for (int i = 0; i < sampleBuffer.channel1.size(); i++) 197 | { 198 | double ySampleOffset = (8.0 / 256.0) * (256 - ((uint8_t)device.getChannelVerticalPosition(CHANNEL_1) + (uint8_t)sampleBuffer.channel1[i])); 199 | if (i > 0) 200 | cr->line_to((10.0 / sampleBuffer.channel1.capacity()) * i, ySampleOffset); 201 | else 202 | cr->move_to(0.0, ySampleOffset); 203 | } 204 | cr->stroke(); 205 | } 206 | 207 | void ScopeWidget::drawChannel2(const Cairo::RefPtr &cr) 208 | { 209 | Gdk::Cairo::set_source_rgba(cr, Gdk::RGBA("rgb(112, 255, 164)")); 210 | 211 | // Draw level 212 | double xOffset = -0.5; 213 | double yOffset = (8.0 / 256.0) * (256 - (uint8_t)device.getChannelVerticalPosition(CHANNEL_2)); 214 | cr->rectangle(xOffset, yOffset - 0.05, 0.3, 0.1); 215 | cr->fill(); 216 | 217 | // Draw samples 218 | for (int i = 0; i < sampleBuffer.channel2.size(); i++) 219 | { 220 | double ySampleOffset = (8.0 / 256.0) * (256 - ((uint8_t)device.getChannelVerticalPosition(CHANNEL_2) + (uint8_t)sampleBuffer.channel2[i])); 221 | if (i > 0) 222 | cr->line_to((10.0 / sampleBuffer.channel2.capacity()) * i, ySampleOffset); 223 | else 224 | cr->move_to(0.0, ySampleOffset); 225 | } 226 | cr->stroke(); 227 | } -------------------------------------------------------------------------------- /lib/ProtocolWorker.cxx: -------------------------------------------------------------------------------- 1 | #include "ProtocolWorker.h" 2 | 3 | ProtocolWorker::ProtocolWorker() : shallStop(false), 4 | stopped(true), connected(false), 5 | update(false), progress(0), 6 | connectionLost(false) 7 | { 8 | Protocol::setConnectionLostHandler(bind(&ProtocolWorker::onConnectionLost, this, placeholders::_1)); 9 | Protocol::setProgressHandler(bind(&ProtocolWorker::onUpdateProgress, this, placeholders::_1)); 10 | } 11 | 12 | void ProtocolWorker::process() 13 | { 14 | { 15 | lock_guard lock(stateMutex); 16 | stopped = false; 17 | } 18 | 19 | while (!shallStop) 20 | { 21 | Protocol::process(); 22 | if (update) 23 | { 24 | notifyHandler(); 25 | { 26 | lock_guard lock(stateMutex); 27 | update = false; 28 | } 29 | } 30 | } 31 | 32 | { 33 | lock_guard lock(stateMutex); 34 | shallStop = false; 35 | stopped = true; 36 | } 37 | 38 | notifyHandler(); 39 | } 40 | 41 | void ProtocolWorker::startThread() 42 | { 43 | workerThread = new thread( 44 | [this] { 45 | this->process(); 46 | }); 47 | } 48 | 49 | void ProtocolWorker::stopThread() 50 | { 51 | { 52 | lock_guard lock(stateMutex); 53 | shallStop = true; 54 | } 55 | while (!stopped) 56 | { 57 | } 58 | if (workerThread->joinable()) 59 | workerThread->join(); 60 | } 61 | 62 | void ProtocolWorker::connect(string device) 63 | { 64 | Protocol::connect(device); 65 | Protocol::init(bind(&ProtocolWorker::onInitialized, this)); 66 | { 67 | lock_guard lock(stateMutex); 68 | connectionLost = false; 69 | connectionLostReason = ""; 70 | connecting = true; 71 | connected = false; 72 | update = true; 73 | } 74 | } 75 | 76 | void ProtocolWorker::connect(string server, int port) 77 | { 78 | { 79 | lock_guard lock(stateMutex); 80 | connectionLost = false; 81 | connectionLostReason = ""; 82 | connecting = true; 83 | connected = false; 84 | update = true; 85 | } 86 | Protocol::connect(server, port); 87 | { 88 | lock_guard lock(stateMutex); 89 | update = true; 90 | } 91 | Protocol::init(bind(&ProtocolWorker::onInitialized, this)); 92 | } 93 | 94 | void ProtocolWorker::disconnect() 95 | { 96 | Protocol::disconnect(); 97 | { 98 | lock_guard lock(stateMutex); 99 | connecting = false; 100 | connected = false; 101 | update = true; 102 | } 103 | } 104 | 105 | bool ProtocolWorker::isConnected() const 106 | { 107 | lock_guard lock(stateMutex); 108 | return connected; 109 | } 110 | 111 | bool ProtocolWorker::isConnecting() const 112 | { 113 | lock_guard lock(stateMutex); 114 | return connecting; 115 | } 116 | 117 | bool ProtocolWorker::isConnectionLost() const 118 | { 119 | lock_guard lock(stateMutex); 120 | return connectionLost; 121 | } 122 | 123 | ConnectorType ProtocolWorker::getConnectorType() 124 | { 125 | Connector *connector = Protocol::getConnector(); 126 | if (connector != NULL) 127 | return connector->getType(); 128 | return (ConnectorType)-1; 129 | } 130 | 131 | string ProtocolWorker::getConnectionLostReason() const 132 | { 133 | lock_guard lock(stateMutex); 134 | return connectionLostReason; 135 | } 136 | 137 | void ProtocolWorker::onInitialized() 138 | { 139 | lock_guard lock(stateMutex); 140 | connecting = false; 141 | connected = true; 142 | update = true; 143 | } 144 | 145 | void ProtocolWorker::onConnectionLost(Connector::Exception &e) 146 | { 147 | lock_guard lock(stateMutex); 148 | connectionLostReason = e.what(); 149 | connectionLost = true; 150 | connected = false; 151 | connecting = false; 152 | update = true; 153 | } 154 | 155 | void ProtocolWorker::onUpdateProgress(float progress) 156 | { 157 | lock_guard lock(stateMutex); 158 | this->progress = progress; 159 | update = true; 160 | } 161 | 162 | void ProtocolWorker::onUpdateUI() 163 | { 164 | lock_guard lock(stateMutex); 165 | update = true; 166 | } 167 | 168 | bool ProtocolWorker::hasStopped() const 169 | { 170 | lock_guard lock(stateMutex); 171 | return stopped; 172 | } 173 | 174 | float ProtocolWorker::getProgress() const 175 | { 176 | lock_guard lock(stateMutex); 177 | return progress; 178 | } 179 | 180 | void ProtocolWorker::setNotifyHandler(NotifyHandler notifyHandler) 181 | { 182 | this->notifyHandler = notifyHandler; 183 | } 184 | 185 | void ProtocolWorker::fetchDevice(IDSO1070 &dev) 186 | { 187 | Protocol::fetchDevice(dev); 188 | } 189 | 190 | void ProtocolWorker::fetchSamples(SampleBuffer &buffer) 191 | { 192 | Protocol::fetchSamples(buffer); 193 | } 194 | 195 | void ProtocolWorker::fetchTransmissionLog(Protocol::TransmissionLog &log) 196 | { 197 | Protocol::fetchTransmissionLog(log); 198 | Protocol::clearTransmissionLog(false); 199 | } 200 | 201 | void ProtocolWorker::startSampling() 202 | { 203 | Protocol::startSampling(bind(&ProtocolWorker::onUpdateUI, this)); 204 | } 205 | 206 | void ProtocolWorker::stopSampling() 207 | { 208 | Protocol::stopSampling(bind(&ProtocolWorker::onUpdateUI, this)); 209 | } 210 | 211 | void ProtocolWorker::readBatteryLevel() 212 | { 213 | Protocol::readBatteryLevel(bind(&ProtocolWorker::onUpdateUI, this)); 214 | } 215 | 216 | void ProtocolWorker::setTimeBase(TimeBase timeBase) 217 | { 218 | Protocol::setTimeBase(timeBase, bind(&ProtocolWorker::onUpdateUI, this)); 219 | } 220 | 221 | void ProtocolWorker::setScopeMode(ScopeMode scopeMode) 222 | { 223 | Protocol::setScopeMode(scopeMode, bind(&ProtocolWorker::onUpdateUI, this)); 224 | } 225 | 226 | void ProtocolWorker::setCaptureMode(CaptureMode captureMode) 227 | { 228 | Protocol::setCaptureMode(captureMode, bind(&ProtocolWorker::onUpdateUI, this)); 229 | } 230 | 231 | void ProtocolWorker::enableChannel(ChannelSelector channel) 232 | { 233 | Protocol::enableChannel(channel, bind(&ProtocolWorker::onUpdateUI, this)); 234 | } 235 | 236 | void ProtocolWorker::disableChannel(ChannelSelector channel) 237 | { 238 | Protocol::disableChannel(channel, bind(&ProtocolWorker::onUpdateUI, this)); 239 | } 240 | 241 | void ProtocolWorker::setChannelVerticalDiv(ChannelSelector channel, VoltageDiv div) 242 | { 243 | Protocol::setChannelVerticalDiv(channel, div, bind(&ProtocolWorker::onUpdateUI, this)); 244 | } 245 | 246 | void ProtocolWorker::setChannelCoupling(ChannelSelector channel, InputCoupling coupling) 247 | { 248 | Protocol::setChannelCoupling(channel, coupling, bind(&ProtocolWorker::onUpdateUI, this)); 249 | } 250 | 251 | void ProtocolWorker::setChannelVerticalPosition(ChannelSelector channel, uint16_t pos) 252 | { 253 | Protocol::setChannelVerticalPosition(channel, pos, bind(&ProtocolWorker::onUpdateUI, this)); 254 | } 255 | 256 | void ProtocolWorker::setTriggerMode(TriggerMode mode) 257 | { 258 | Protocol::setTriggerMode(mode, bind(&ProtocolWorker::onUpdateUI, this)); 259 | } 260 | 261 | void ProtocolWorker::setTriggerChannel(TriggerChannel channel) 262 | { 263 | Protocol::setTriggerChannel(channel, bind(&ProtocolWorker::onUpdateUI, this)); 264 | } 265 | 266 | void ProtocolWorker::setTriggerSlope(TriggerSlope slope) 267 | { 268 | Protocol::setTriggerSlope(slope, bind(&ProtocolWorker::onUpdateUI, this)); 269 | } 270 | 271 | void ProtocolWorker::setTriggerLevel(uint16_t level) 272 | { 273 | Protocol::setTriggerLevel(level, bind(&ProtocolWorker::onUpdateUI, this)); 274 | } -------------------------------------------------------------------------------- /lib/IDSO1070.cxx: -------------------------------------------------------------------------------- 1 | #include "IDSO1070.h" 2 | 3 | IDSO1070::IDSO1070() : selectedChannel(CHANNEL_1), littlePacketStatus(0) 4 | { 5 | setTimeBase(HDIV_10uS); 6 | setScopeMode(SCOMODE_ANALOG); 7 | setCaptureMode(CAPMODE_NORMAL); 8 | setBatteryLevel(0); 9 | 10 | enableChannel(CHANNEL_1); 11 | enableChannel(CHANNEL_2); 12 | setChannelVerticalDiv(CHANNEL_1, VDIV_1V); 13 | setChannelVerticalDiv(CHANNEL_2, VDIV_1V); 14 | setChannelCoupling(CHANNEL_1, COUPLING_AC); 15 | setChannelCoupling(CHANNEL_2, COUPLING_AC); 16 | setChannelVerticalPosition(CHANNEL_1, 136); 17 | setChannelVerticalPosition(CHANNEL_2, 120); 18 | 19 | setTriggerMode(TRIGMODE_AUTO); 20 | setTriggerChannel(TRIGCHAN_CH1); 21 | setTriggerSlope(TRIGSLOPE_RISING); 22 | setTriggerLevel(0); 23 | setTriggerXPosition(0.5); 24 | } 25 | 26 | IDSO1070 &IDSO1070::operator=(IDSO1070 obj) 27 | { 28 | deviceSettings = obj.deviceSettings; 29 | channels[0] = obj.channels[0]; 30 | channels[1] = obj.channels[1]; 31 | triggerSettings = obj.triggerSettings; 32 | 33 | selectedChannel = obj.selectedChannel; 34 | littlePacketStatus = obj.littlePacketStatus; 35 | return *this; 36 | } 37 | 38 | TimeBase IDSO1070::getTimeBase() 39 | { 40 | return deviceSettings.timeBase; 41 | } 42 | void IDSO1070::setTimeBase(TimeBase timeBase) 43 | { 44 | deviceSettings.timeBase = timeBase; 45 | } 46 | 47 | CaptureMode IDSO1070::getCaptureMode() 48 | { 49 | return deviceSettings.captureMode; 50 | } 51 | void IDSO1070::setCaptureMode(CaptureMode captureMode) 52 | { 53 | deviceSettings.captureMode = captureMode; 54 | } 55 | 56 | ScopeMode IDSO1070::getScopeMode() 57 | { 58 | return deviceSettings.scopeMode; 59 | } 60 | void IDSO1070::setScopeMode(ScopeMode scopeMode) 61 | { 62 | deviceSettings.scopeMode = scopeMode; 63 | } 64 | 65 | void IDSO1070::setBatteryLevel(uint8_t batteryLevel) 66 | { 67 | deviceSettings.batteryLevel = batteryLevel; 68 | } 69 | uint8_t IDSO1070::getBatteryLevel() 70 | { 71 | return deviceSettings.batteryLevel; 72 | } 73 | 74 | bool IDSO1070::isSampling() 75 | { 76 | return sampling; 77 | } 78 | void IDSO1070::setSampling(bool sampling) 79 | { 80 | this->sampling = sampling; 81 | } 82 | 83 | void IDSO1070::setLittlePacketStatus(int littlePacketStatus) 84 | { 85 | this->littlePacketStatus = littlePacketStatus; 86 | } 87 | int IDSO1070::getLittlePacketStatus() 88 | { 89 | return littlePacketStatus; 90 | } 91 | 92 | void IDSO1070::setARMFirmwareVersion(string version) 93 | { 94 | deviceSettings.armFirmwareVersion = version; 95 | } 96 | 97 | string IDSO1070::getARMFirmwareVersion() 98 | { 99 | return deviceSettings.armFirmwareVersion; 100 | } 101 | 102 | void IDSO1070::setFPGAFirmwareVersion(string version) 103 | { 104 | deviceSettings.fpgaFirmwareVersion = version; 105 | } 106 | 107 | string IDSO1070::getFPGAFirmwareVersion() 108 | { 109 | return deviceSettings.fpgaFirmwareVersion; 110 | } 111 | 112 | void IDSO1070::setProductName(string productName) 113 | { 114 | deviceSettings.productName = productName; 115 | } 116 | 117 | string IDSO1070::getProductName() 118 | { 119 | return deviceSettings.productName; 120 | } 121 | 122 | void IDSO1070::setUserName(string userName) 123 | { 124 | deviceSettings.userName = userName; 125 | } 126 | 127 | string IDSO1070::getUserName() 128 | { 129 | return deviceSettings.userName; 130 | } 131 | 132 | void IDSO1070::setCaliLevel(uint8_t *data) 133 | { 134 | memcpy(deviceSettings.caliLevel, data, sizeof(deviceSettings.caliLevel)); 135 | } 136 | 137 | uint16_t *IDSO1070::getCaliLevel() 138 | { 139 | return deviceSettings.caliLevel; 140 | } 141 | 142 | void IDSO1070::setFPGAAlert(uint8_t *data) 143 | { 144 | memcpy(deviceSettings.fpgaAlert, data, sizeof(deviceSettings.fpgaAlert)); 145 | } 146 | 147 | uint8_t *IDSO1070::getFPGAAlert() 148 | { 149 | return deviceSettings.fpgaAlert; 150 | } 151 | 152 | void IDSO1070::setDiffFixData(size_t channel, size_t offset, uint8_t *data) 153 | { 154 | if ( 155 | (offset != 0 && offset != 100 && offset != 200) || 156 | channel > 1) 157 | return; 158 | 159 | if (offset < 200) 160 | { 161 | memcpy(&deviceSettings.diffFixData[channel][offset], data, 100); 162 | } 163 | else 164 | memcpy(&deviceSettings.diffFixData[channel][offset], data, 56); 165 | } 166 | 167 | size_t IDSO1070::getSamplesNumberOfOneFrame() 168 | { 169 | return (deviceSettings.timeBase == HDIV_5uS) ? 2500 : MemoryDepth; 170 | } 171 | uint8_t IDSO1070::getEnabledChannelsCount() 172 | { 173 | if (isChannelEnabled(CHANNEL_1) && isChannelEnabled(CHANNEL_2)) 174 | return 2; 175 | else if (isChannelEnabled(CHANNEL_1) || isChannelEnabled(CHANNEL_2)) 176 | return 1; 177 | return 0; 178 | } 179 | uint8_t IDSO1070::getPacketsNumber() 180 | { 181 | return (getEnabledChannelsCount() * getSamplesNumberOfOneFrame()) / SamplesCountPerPacket; 182 | } 183 | 184 | // Trigger methods 185 | 186 | uint16_t IDSO1070::getTriggerBottomPWM() 187 | { 188 | if (triggerSettings.channel == TRIGCHAN_CH1) 189 | return triggerSettings.innerPWM[0]; 190 | else if (triggerSettings.channel == TRIGCHAN_CH2) 191 | return triggerSettings.innerPWM[2]; 192 | return -1; 193 | } 194 | 195 | uint16_t IDSO1070::getTriggerTopPWM() 196 | { 197 | if (triggerSettings.channel == TRIGCHAN_CH1) 198 | return triggerSettings.innerPWM[1]; 199 | else if (triggerSettings.channel == TRIGCHAN_CH2) 200 | return triggerSettings.innerPWM[3]; 201 | return -1; 202 | } 203 | 204 | void IDSO1070::setTriggerLevel(uint16_t i) 205 | { 206 | if (i < 8) 207 | { 208 | i = 8; 209 | } 210 | else if (i > MaxSample) 211 | { 212 | i = MaxSample; 213 | } 214 | triggerSettings.level = i; 215 | } 216 | uint16_t IDSO1070::getTriggerLevel() 217 | { 218 | return triggerSettings.level; 219 | } 220 | 221 | void IDSO1070::setTriggerChannel(TriggerChannel channel) 222 | { 223 | triggerSettings.channel = channel; 224 | } 225 | TriggerChannel IDSO1070::getTriggerChannel() 226 | { 227 | return triggerSettings.channel; 228 | } 229 | 230 | void IDSO1070::setTriggerSlope(TriggerSlope slope) 231 | { 232 | triggerSettings.slope = slope; 233 | } 234 | TriggerSlope IDSO1070::getTriggerSlope() 235 | { 236 | return triggerSettings.slope; 237 | } 238 | 239 | void IDSO1070::setTriggerMode(TriggerMode mode) 240 | { 241 | triggerSettings.mode = mode; 242 | } 243 | TriggerMode IDSO1070::getTriggerMode() 244 | { 245 | return triggerSettings.mode; 246 | } 247 | 248 | double IDSO1070::getTriggerXPosition() 249 | { 250 | return triggerSettings.xPosition; 251 | } 252 | void IDSO1070::setTriggerXPosition(double xPosition) 253 | { 254 | triggerSettings.xPosition = xPosition; 255 | } 256 | 257 | void IDSO1070::setTriggerInnerPWM(uint8_t index, uint16_t pwm) 258 | { 259 | triggerSettings.innerPWM[index] = pwm; 260 | } 261 | uint16_t IDSO1070::getTriggerInnerPWM(uint8_t index) 262 | { 263 | return triggerSettings.innerPWM[index]; 264 | } 265 | uint16_t *IDSO1070::getTriggerInnerPWM() 266 | { 267 | return triggerSettings.innerPWM; 268 | } 269 | 270 | void IDSO1070::setTriggerOuterPWM(uint8_t index, uint16_t pwm) 271 | { 272 | triggerSettings.outerPWM[index] = pwm; 273 | } 274 | uint16_t IDSO1070::getTriggerOuterPWM(uint8_t index) 275 | { 276 | return triggerSettings.outerPWM[index]; 277 | } 278 | uint16_t *IDSO1070::getTriggerOuterPWM() 279 | { 280 | return triggerSettings.outerPWM; 281 | } 282 | 283 | // Channel methods 284 | void IDSO1070::setSelectedChannel(ChannelSelector channel) 285 | { 286 | this->selectedChannel = channel; 287 | } 288 | 289 | ChannelSelector IDSO1070::getSelectedChannel() 290 | { 291 | return selectedChannel; 292 | } 293 | 294 | void IDSO1070::enableChannel(ChannelSelector channel) 295 | { 296 | channels[channel].enabled = true; 297 | } 298 | 299 | void IDSO1070::disableChannel(ChannelSelector channel) 300 | { 301 | channels[channel].enabled = false; 302 | } 303 | 304 | bool IDSO1070::isChannelEnabled(ChannelSelector channel) 305 | { 306 | return channels[channel].enabled; 307 | } 308 | 309 | void IDSO1070::setChannelVerticalDiv(ChannelSelector channel, VoltageDiv verticalDiv) 310 | { 311 | channels[channel].verticalDiv = verticalDiv; 312 | } 313 | 314 | VoltageDiv IDSO1070::getChannelVerticalDiv(ChannelSelector channel) 315 | { 316 | return channels[channel].verticalDiv; 317 | } 318 | 319 | void IDSO1070::setChannelCoupling(ChannelSelector channel, InputCoupling coupling) 320 | { 321 | channels[channel].coupling = coupling; 322 | } 323 | 324 | InputCoupling IDSO1070::getChannelCoupling(ChannelSelector channel) 325 | { 326 | return channels[channel].coupling; 327 | } 328 | 329 | void IDSO1070::setChannelVerticalPosition(ChannelSelector channel, int16_t verticalPosition) 330 | { 331 | if (verticalPosition < 8) 332 | verticalPosition = 8; 333 | else if (verticalPosition > MaxSample) 334 | verticalPosition = MaxSample; 335 | channels[channel].verticalPosition = verticalPosition; 336 | } 337 | 338 | int8_t IDSO1070::getChannelVerticalPosition(ChannelSelector channel) 339 | { 340 | return channels[channel].verticalPosition; 341 | } 342 | 343 | void IDSO1070::setChannelPWM(ChannelSelector channel, uint16_t pwm, uint8_t a, uint8_t b) 344 | { 345 | channels[channel].pwmArray[a][b] = pwm; 346 | } 347 | 348 | uint16_t IDSO1070::getChannelPWM(ChannelSelector channel, uint8_t a, uint8_t b) 349 | { 350 | if (a < 9 && b < 2) 351 | return channels[channel].pwmArray[a][b]; 352 | return -1; 353 | } 354 | 355 | uint16_t *IDSO1070::getChannelPWM(ChannelSelector channel, uint8_t a) 356 | { 357 | if (a < 9) 358 | return channels[channel].pwmArray[a]; 359 | return NULL; 360 | } 361 | 362 | void IDSO1070::setChannelVoltage125(ChannelSelector channel, double voltage) 363 | { 364 | channels[channel].voltage125 = voltage; 365 | } 366 | 367 | double IDSO1070::getChannelVoltage125(ChannelSelector channel) 368 | { 369 | return channels[channel].voltage125; 370 | } 371 | 372 | void IDSO1070::setChannelVoltageRL1(ChannelSelector channel, double voltage) 373 | { 374 | channels[channel].voltageRL1 = voltage; 375 | } 376 | 377 | double IDSO1070::getChannelVoltageRL1(ChannelSelector channel) 378 | { 379 | return channels[channel].voltageRL1; 380 | } 381 | 382 | void IDSO1070::setChannelVoltageRL2(ChannelSelector channel, double voltage) 383 | { 384 | channels[channel].voltageRL2 = voltage; 385 | } 386 | 387 | double IDSO1070::getChannelVoltageRL2(ChannelSelector channel) 388 | { 389 | return channels[channel].voltageRL2; 390 | } 391 | -------------------------------------------------------------------------------- /lib/packets/CommandFactory.cxx: -------------------------------------------------------------------------------- 1 | #include "packets/CommandFactory.h" 2 | 3 | Command *CommandFactory::readEEPROMPage(uint8_t address) 4 | { 5 | uint8_t cmdBuffer[4] = {TYPE_EEPROM, 0xaa, address, 0x00}; 6 | Command *cmd = new Command(cmdBuffer); 7 | return cmd; 8 | } 9 | 10 | Command *CommandFactory::readARMVersion() 11 | { 12 | uint8_t cmdBuffer[4] = {TYPE_STATE, 0x04, 0x00, 0x00}; 13 | Command *cmd = new Command(cmdBuffer); 14 | return cmd; 15 | } 16 | 17 | Command *CommandFactory::readFPGAVersion() 18 | { 19 | uint8_t cmdBuffer[4] = {TYPE_CONTROL, 0x02, 0x00, 0x00}; 20 | Command *cmd = new Command(cmdBuffer); 21 | return cmd; 22 | } 23 | 24 | Command *CommandFactory::readBatteryLevel() 25 | { 26 | uint8_t cmdBuffer[4] = {TYPE_STATE, 0x03, 0x00, 0x00}; 27 | Command *cmd = new Command(cmdBuffer); 28 | return cmd; 29 | } 30 | 31 | Command *CommandFactory::readRamCount(int enabledChannels, uint16_t samplesNumberOfOneFrame, 32 | double triggerXPosition, 33 | uint8_t packetsNumber) 34 | { 35 | uint16_t b = 0; 36 | if (enabledChannels == 2) 37 | { 38 | b = samplesNumberOfOneFrame; 39 | } 40 | else if (enabledChannels == 1) 41 | { 42 | double x = ((double)samplesNumberOfOneFrame * triggerXPosition / 2) + 43 | ((double)samplesNumberOfOneFrame * (1 - triggerXPosition)); 44 | b = (uint16_t)x; 45 | } 46 | Command *cmd = new Command(CMDCODE_READ_RAM_COUNT, 47 | (uint8_t)(b & 0xff), 48 | (uint8_t)((b >> 8) & 0xf + ((packetsNumber - 1) << 4))); 49 | return cmd; 50 | } 51 | 52 | Command *CommandFactory::startSampling() 53 | { 54 | uint8_t cmdPayload[4] = {TYPE_CONTROL, 0x04, 0x00, 0x00}; 55 | Command *cmd = new Command(cmdPayload); 56 | return cmd; 57 | } 58 | 59 | Command *CommandFactory::updateSampleRate(TimeBase timeBase, int enabledChannels) 60 | { 61 | Command *cmd = new Command(CMDCODE_SAMPLE_RATE, 0); 62 | return cmd; 63 | } 64 | 65 | Command *CommandFactory::updateFreqDivLowBytes(uint32_t freqDiv) 66 | { 67 | uint16_t lowBytes = (uint16_t)(freqDiv & 0xffff); 68 | Command *cmd = new Command(CMDCODE_FREQ_DIV_LOW, (uint8_t)(lowBytes & 0xff), (uint8_t)((lowBytes >> 8) & 0xff)); 69 | return cmd; 70 | } 71 | 72 | Command *CommandFactory::updateFreqDivHighBytes(uint32_t freqDiv) 73 | { 74 | uint16_t highBytes = (uint16_t)((freqDiv >> 16) & 0xffff); 75 | Command *cmd = new Command(CMDCODE_FREQ_DIV_HIGH, (uint8_t)(highBytes & 0xff), (uint8_t)((highBytes >> 8) & 0xff)); 76 | return cmd; 77 | } 78 | 79 | Command *CommandFactory::updateRAMChannelSelection(bool channel1Enabled, bool channel2Enabled) 80 | { 81 | uint8_t b = 0x01; 82 | if (channel1Enabled && !channel2Enabled) 83 | { 84 | b = 0x08; 85 | } 86 | else if (channel2Enabled && !channel1Enabled) 87 | { 88 | b = 0x09; 89 | } 90 | else if (channel2Enabled && channel1Enabled) 91 | { 92 | b = 0x00; 93 | } 94 | Command *cmd = new Command(CMDCODE_RAM_CHANNEL_SELECTION, b); 95 | return cmd; 96 | } 97 | 98 | Command *CommandFactory::updateChannelVolts125(VoltageDiv channel1VerticalDiv, VoltageDiv channel2VerticalDiv) 99 | { 100 | uint8_t b = 0; 101 | switch (channel1VerticalDiv) 102 | { 103 | case VDIV_10mV: 104 | case VDIV_100mV: 105 | case VDIV_1V: 106 | b &= ~0x03; 107 | break; 108 | case VDIV_20mV: 109 | case VDIV_200mV: 110 | case VDIV_2V: 111 | b &= ~0x02; 112 | b |= 0x01; 113 | break; 114 | case VDIV_50mV: 115 | case VDIV_500mV: 116 | case VDIV_5V: 117 | b &= ~0x01; 118 | b |= 0x02; 119 | break; 120 | } 121 | 122 | switch (channel2VerticalDiv) 123 | { 124 | case VDIV_10mV: 125 | case VDIV_100mV: 126 | case VDIV_1V: 127 | b &= ~0x0c; 128 | break; 129 | case VDIV_20mV: 130 | case VDIV_200mV: 131 | case VDIV_2V: 132 | b &= ~0x08; 133 | b |= 0x04; 134 | break; 135 | case VDIV_50mV: 136 | case VDIV_500mV: 137 | case VDIV_5V: 138 | b &= ~0x04; 139 | b |= 0x08; 140 | break; 141 | } 142 | b &= ~0x30; 143 | Command *cmd = new Command(CMDCODE_CHANNEL_VOLTS_DIV_125, b); 144 | return cmd; 145 | } 146 | 147 | Command *CommandFactory::updateRelay1(VoltageDiv channel1VerticalDiv) 148 | { 149 | uint8_t b = 0; 150 | 151 | switch (channel1VerticalDiv) 152 | { 153 | case VDIV_10mV: 154 | case VDIV_100mV: 155 | case VDIV_20mV: 156 | case VDIV_200mV: 157 | case VDIV_50mV: 158 | case VDIV_500mV: 159 | b = 0x7f; 160 | break; 161 | case VDIV_1V: 162 | case VDIV_2V: 163 | case VDIV_5V: 164 | b = 0x80; 165 | break; 166 | } 167 | Command *cmd = new Command(CMDCODE_SET_RELAY, b); 168 | return cmd; 169 | } 170 | 171 | Command *CommandFactory::updateRelay2(VoltageDiv channel1VerticalDiv) 172 | { 173 | uint8_t b = 0; 174 | 175 | switch (channel1VerticalDiv) 176 | { 177 | case VDIV_10mV: 178 | case VDIV_100mV: 179 | case VDIV_20mV: 180 | case VDIV_200mV: 181 | case VDIV_50mV: 182 | case VDIV_500mV: 183 | b = 0xfd; 184 | break; 185 | case VDIV_1V: 186 | case VDIV_2V: 187 | case VDIV_5V: 188 | b = 0x02; 189 | break; 190 | } 191 | 192 | Command *cmd = new Command(CMDCODE_SET_RELAY, b); 193 | return cmd; 194 | } 195 | 196 | Command *CommandFactory::updateRelay3(VoltageDiv channel2VerticalDiv) 197 | { 198 | uint8_t b = 0; 199 | 200 | switch (channel2VerticalDiv) 201 | { 202 | case VDIV_10mV: 203 | case VDIV_100mV: 204 | case VDIV_20mV: 205 | case VDIV_200mV: 206 | case VDIV_50mV: 207 | case VDIV_500mV: 208 | b = 0xbf; 209 | break; 210 | case VDIV_1V: 211 | case VDIV_2V: 212 | case VDIV_5V: 213 | b = 0x40; 214 | break; 215 | } 216 | 217 | Command *cmd = new Command(CMDCODE_SET_RELAY, b); 218 | return cmd; 219 | } 220 | 221 | Command *CommandFactory::updateRelay4(VoltageDiv channel2VerticalDiv) 222 | { 223 | uint8_t b = 0; 224 | 225 | switch (channel2VerticalDiv) 226 | { 227 | case VDIV_10mV: 228 | case VDIV_100mV: 229 | case VDIV_20mV: 230 | case VDIV_200mV: 231 | case VDIV_50mV: 232 | case VDIV_500mV: 233 | b = 0xfb; 234 | break; 235 | case VDIV_1V: 236 | case VDIV_2V: 237 | case VDIV_5V: 238 | b = 0x04; 239 | break; 240 | } 241 | 242 | Command *cmd = new Command(CMDCODE_SET_RELAY, b); 243 | return cmd; 244 | } 245 | 246 | Command *CommandFactory::updateChannel1Coupling(InputCoupling channel1Coupling) 247 | { 248 | uint8_t b1 = 0, b2 = 0; 249 | if (channel1Coupling == COUPLING_GND) 250 | { 251 | b1 = 0xff; 252 | b2 = 0x01; 253 | } 254 | else if (channel1Coupling == COUPLING_DC) 255 | { 256 | b1 = 0xef; 257 | } 258 | else 259 | { 260 | b1 = 0x10; 261 | } 262 | Command *cmd = new Command(CMDCODE_SET_RELAY, b1, b2); 263 | return cmd; 264 | } 265 | 266 | Command *CommandFactory::updateChannel2Coupling(InputCoupling channel2Coupling) 267 | { 268 | uint8_t b1 = 0, b2 = 0; 269 | if (channel2Coupling == COUPLING_GND) 270 | { 271 | b1 = 0xff; 272 | b2 = 0x02; 273 | } 274 | else if (channel2Coupling == COUPLING_DC) 275 | { 276 | b1 = 0xfe; 277 | } 278 | else 279 | { 280 | b1 = 0x01; 281 | } 282 | Command *cmd = new Command(CMDCODE_SET_RELAY, b1, b2); 283 | return cmd; 284 | } 285 | 286 | Command *CommandFactory::updateTriggerMode(CaptureMode capMode, TriggerMode trigMode, ScopeMode scoMode) 287 | { 288 | uint8_t b = 0; 289 | if (capMode == CAPMODE_ROLL) 290 | b = (1 << 0); 291 | else if (capMode != CAPMODE_NORMAL) 292 | b |= (1 << 3); 293 | if (trigMode == TRIGMODE_AUTO) 294 | b |= (1 << 1); 295 | else if (trigMode == TRIGMODE_SINGLE) 296 | b |= (1 << 2); 297 | if (scoMode == SCOMODE_DIGITAL) 298 | b |= (1 << 4); 299 | Command *cmd = new Command(CMDCODE_TRIGGER_MODE, b); 300 | return cmd; 301 | } 302 | 303 | Command *CommandFactory::updateChannel1Level(VoltageDiv channel1VerticalDiv, int16_t channel1VerticalPosition, float channel1PWM0, float channel1PWM1) 304 | { 305 | int verticalDiv = (int)channel1VerticalDiv; 306 | uint16_t pwm = (uint16_t)mapValue( 307 | channel1VerticalPosition, 308 | 8.0f, 248.0f, 309 | channel1PWM0, channel1PWM1); 310 | if (pwm > IDSO1070::MaxPWM) 311 | return (Command *)NULL; 312 | return new Command(CMDCODE_CH1_PWM, 313 | (uint8_t)(pwm & 0xff), 314 | (uint8_t)((pwm >> 8) & 0x0f)); 315 | } 316 | 317 | Command *CommandFactory::updateChannel2Level(VoltageDiv channel2VerticalDiv, int16_t channel2VerticalPosition, float channel2PWM0, float channel2PWM1) 318 | { 319 | int verticalDiv = (int)channel2VerticalDiv; 320 | uint16_t pwm = (uint16_t)mapValue( 321 | channel2VerticalPosition, 322 | 8.0f, 248.0f, 323 | channel2PWM0, channel2PWM1); 324 | 325 | if (pwm > IDSO1070::MaxPWM) 326 | return (Command *)NULL; 327 | return new Command(CMDCODE_CH2_PWM, 328 | (uint8_t)(pwm & 0xff), 329 | (uint8_t)((pwm >> 8) & 0x0f)); 330 | } 331 | 332 | Command *CommandFactory::updateTriggerSourceAndSlope(TriggerChannel triggerChanel, ScopeMode scoMode, TriggerSlope triggerSlope) 333 | { 334 | uint8_t b = 335 | triggerChanel == TRIGCHAN_CH1 ? 0x01 : triggerChanel == TRIGCHAN_CH2 ? 0x00 : triggerChanel == TRIGCHAN_EXT ? 0x02 : 0x03; 336 | 337 | b &= ~0x2c; 338 | if (scoMode == SCOMODE_ANALOG) 339 | b |= 0x10; 340 | else 341 | b &= ~0x10; 342 | if (triggerSlope == TRIGSLOPE_RISING) 343 | b |= 0x80; 344 | else 345 | b &= ~0x80; 346 | 347 | return new Command(CMDCODE_TRIGGER_SOURCE, b); 348 | } 349 | 350 | Command *CommandFactory::updateTriggerLevel(uint16_t triggerLevel, float triggerTopPWM, float triggerBottomPWM) 351 | { 352 | uint16_t pwm = mapValue(triggerLevel, 8.0f, 248.0f, triggerBottomPWM, triggerTopPWM); 353 | 354 | if (pwm > IDSO1070::MaxPWM) 355 | return (Command *)NULL; 356 | return new Command(CMDCODE_TRIGGER_PWM, 357 | (uint8_t)(pwm & 0xff), 358 | (uint8_t)((pwm >> 8) & 0x0f)); 359 | } 360 | 361 | Command *CommandFactory::updateChannelSelection(bool channel1Enabled, bool channel2Enabled) 362 | { 363 | uint8_t b = 0; 364 | int channelCount = channel1Enabled && channel2Enabled ? 2 : channel1Enabled || channel2Enabled ? 1 : 0; 365 | if (channelCount == 2) 366 | { 367 | b = 0x02; 368 | } 369 | else 370 | { 371 | b = 0x03; 372 | } 373 | Command *cmd = new Command(CMDCODE_CHANNEL_SELECTION, b); 374 | return cmd; 375 | } 376 | 377 | Command *CommandFactory::updatePreTriggerLength(uint16_t samplesNumberOfOneFrame, double triggerXPosition) 378 | { 379 | uint16_t i = ((uint16_t)(((double)samplesNumberOfOneFrame) * triggerXPosition)) + 5; 380 | return new Command(CMDCODE_PRE_TRIGGER_LENGTH, 381 | (uint8_t)(i & 0xff), 382 | (uint8_t)((i >> 8) & 0xff)); 383 | } 384 | 385 | Command *CommandFactory::updatePostTriggerLength(uint16_t samplesNumberOfOneFrame, double triggerXPosition) 386 | { 387 | uint16_t i = ((uint16_t)(((double)samplesNumberOfOneFrame) * (1 - triggerXPosition))); 388 | return new Command(CMDCODE_POST_TRIGGER_LENGTH, 389 | (uint8_t)(i & 0xff), 390 | (uint8_t)((i >> 8) & 0xff)); 391 | } -------------------------------------------------------------------------------- /gui/SettingsWidget.cxx: -------------------------------------------------------------------------------- 1 | #include "SettingsWidget.h" 2 | 3 | #include 4 | #include 5 | 6 | SettingsWidget::SettingsWidget(BaseObjectType *cobject, const RefPtr &refGlade) 7 | : Box(cobject), 8 | refGlade(refGlade), 9 | pTransmissionLogDialog(nullptr), 10 | pButtonTransmissionLog(nullptr), 11 | pButtonConnect(nullptr), 12 | pProgressbarConnection(nullptr), 13 | pConnectionStatus(nullptr), 14 | pBatteryLevel(nullptr), 15 | pDeviceInfo(nullptr), 16 | pToggleSampling(nullptr), 17 | pTimeBase(nullptr), 18 | pScopeMode(nullptr), 19 | pCaptureMode(nullptr), 20 | pTimeBaseStore(nullptr), 21 | pScopeModeStore(nullptr), 22 | pCaptureModeStore(nullptr), 23 | pChannel1Enabled(nullptr), 24 | pChannel2Enabled(nullptr), 25 | pTriggerMode(nullptr), 26 | pTriggerChannel(nullptr), 27 | pTriggerSlope(nullptr), 28 | pTriggerModeStore(nullptr), 29 | pTriggerChannelStore(nullptr), 30 | pTriggerSlopeStore(nullptr), 31 | worker(nullptr) 32 | { 33 | // Get references to widgets from glade file 34 | refGlade->get_widget_derived("TransmissionLogDialog", pTransmissionLogDialog); 35 | refGlade->get_widget("buttonTransmissionLog", pButtonTransmissionLog); 36 | refGlade->get_widget("buttonConnect", pButtonConnect); 37 | refGlade->get_widget("progressConnection", pProgressbarConnection); 38 | refGlade->get_widget("labelConnectionStatus", pConnectionStatus); 39 | refGlade->get_widget("toggleSampling", pToggleSampling); 40 | refGlade->get_widget("levelBattery", pBatteryLevel); 41 | refGlade->get_widget("labelDeviceInfo", pDeviceInfo); 42 | refGlade->get_widget("comboTimeBase", pTimeBase); 43 | refGlade->get_widget("comboScopeMode", pScopeMode); 44 | refGlade->get_widget("comboCaptureMode", pCaptureMode); 45 | pTimeBaseStore = RefPtr::cast_dynamic(refGlade->get_object("TimeBase")); 46 | pScopeModeStore = RefPtr::cast_dynamic(refGlade->get_object("ScopeMode")); 47 | pCaptureModeStore = RefPtr::cast_dynamic(refGlade->get_object("CaptureMode")); 48 | refGlade->get_widget("toggleChannel1Enabled", pChannel1Enabled); 49 | refGlade->get_widget("toggleChannel2Enabled", pChannel2Enabled); 50 | refGlade->get_widget("comboTriggerMode", pTriggerMode); 51 | refGlade->get_widget("comboTriggerChannel", pTriggerChannel); 52 | refGlade->get_widget("comboTriggerSlope", pTriggerSlope); 53 | pTriggerModeStore = RefPtr::cast_dynamic(refGlade->get_object("TriggerMode")); 54 | pTriggerChannelStore = RefPtr::cast_dynamic(refGlade->get_object("TriggerChannel")); 55 | pTriggerSlopeStore = RefPtr::cast_dynamic(refGlade->get_object("TriggerSlope")); 56 | 57 | // Connect signals with handlers 58 | pButtonTransmissionLog->signal_clicked().connect(sigc::mem_fun(*this, &SettingsWidget::onButtonTransmissionLog)); 59 | pButtonConnect->signal_clicked().connect(sigc::mem_fun(*this, &SettingsWidget::onButtonConnect)); 60 | 61 | pToggleSampling->signal_toggled().connect(sigc::mem_fun(*this, &SettingsWidget::onToggleSampling)); 62 | pChannel1Enabled->signal_toggled().connect(sigc::mem_fun(*this, &SettingsWidget::onToggleChannel1Enable)); 63 | pChannel2Enabled->signal_toggled().connect(sigc::mem_fun(*this, &SettingsWidget::onToggleChannel2Enable)); 64 | 65 | pTimeBase->signal_changed().connect(sigc::mem_fun(*this, &SettingsWidget::onTimeBaseSelected)); 66 | pScopeMode->signal_changed().connect(sigc::mem_fun(*this, &SettingsWidget::onScopeModeSelected)); 67 | pCaptureMode->signal_changed().connect(sigc::mem_fun(*this, &SettingsWidget::onCaptureModeSelected)); 68 | 69 | pTriggerMode->signal_changed().connect(sigc::mem_fun(*this, &SettingsWidget::onTriggerModeSelected)); 70 | pTriggerChannel->signal_changed().connect(sigc::mem_fun(*this, &SettingsWidget::onTriggerChannelSelected)); 71 | pTriggerSlope->signal_changed().connect(sigc::mem_fun(*this, &SettingsWidget::onTriggerSlopeSelected)); 72 | } 73 | 74 | SettingsWidget::~SettingsWidget() 75 | { 76 | } 77 | 78 | void SettingsWidget::setWorker(ProtocolWorker *worker) 79 | { 80 | this->worker = worker; 81 | } 82 | 83 | void SettingsWidget::onToggleChannel1Enable() 84 | { 85 | if (worker->isConnected()) 86 | { 87 | } 88 | } 89 | 90 | void SettingsWidget::onToggleChannel2Enable() 91 | { 92 | if (worker->isConnected()) 93 | { 94 | } 95 | } 96 | 97 | void SettingsWidget::onButtonTransmissionLog() 98 | { 99 | pTransmissionLogDialog->show(); 100 | } 101 | 102 | void SettingsWidget::onButtonConnect() 103 | { 104 | if (worker->isConnected()) 105 | { 106 | worker->disconnect(); 107 | } 108 | else 109 | { 110 | worker->connect("/dev/ttyACM0"); 111 | } 112 | } 113 | 114 | void SettingsWidget::onToggleSampling() 115 | { 116 | if (worker->isConnected()) 117 | { 118 | 119 | IDSO1070 device; 120 | worker->fetchDevice(device); 121 | if (!device.isSampling()) 122 | worker->startSampling(); 123 | else 124 | worker->stopSampling(); 125 | } 126 | } 127 | 128 | void SettingsWidget::onTimeBaseSelected() 129 | { 130 | if (worker->isConnected()) 131 | { 132 | ListStore::iterator iter = pTimeBase->get_active(); 133 | if (iter) 134 | { 135 | TimeBase selected = (TimeBase)((int)(*iter)[textComboColumns.value]); 136 | worker->setTimeBase(selected); 137 | } 138 | } 139 | } 140 | 141 | void SettingsWidget::onScopeModeSelected() 142 | { 143 | if (worker->isConnected()) 144 | { 145 | ListStore::iterator iter = pTimeBase->get_active(); 146 | if (iter) 147 | { 148 | ScopeMode selected = (ScopeMode)((int)(*iter)[textComboColumns.value]); 149 | worker->setScopeMode(selected); 150 | } 151 | } 152 | } 153 | 154 | void SettingsWidget::onCaptureModeSelected() 155 | { 156 | if (worker->isConnected()) 157 | { 158 | ListStore::iterator iter = pTimeBase->get_active(); 159 | if (iter) 160 | { 161 | CaptureMode selected = (CaptureMode)((int)(*iter)[textComboColumns.value]); 162 | worker->setCaptureMode(selected); 163 | } 164 | } 165 | } 166 | 167 | void SettingsWidget::onTriggerModeSelected() 168 | { 169 | if (worker->isConnected()) 170 | { 171 | ListStore::iterator iter = pTimeBase->get_active(); 172 | if (iter) 173 | { 174 | TriggerMode selected = (TriggerMode)((int)(*iter)[textComboColumns.value]); 175 | worker->setTriggerMode(selected); 176 | } 177 | } 178 | } 179 | 180 | void SettingsWidget::onTriggerChannelSelected() 181 | { 182 | if (worker->isConnected()) 183 | { 184 | ListStore::iterator iter = pTriggerChannel->get_active(); 185 | if (iter) 186 | { 187 | TriggerChannel selected = (TriggerChannel)((int)(*iter)[textComboColumns.value]); 188 | worker->setTriggerChannel(selected); 189 | } 190 | } 191 | } 192 | 193 | void SettingsWidget::onTriggerSlopeSelected() 194 | { 195 | if (worker->isConnected()) 196 | { 197 | ListStore::iterator iter = pTriggerSlope->get_active(); 198 | if (iter) 199 | { 200 | TriggerSlope selected = (TriggerSlope)((int)(*iter)[textComboColumns.value]); 201 | worker->setTriggerSlope(selected); 202 | } 203 | } 204 | } 205 | 206 | void SettingsWidget::update() 207 | { 208 | worker->fetchDevice(device); 209 | updateConnectionControls(); 210 | updateDeviceInfo(); 211 | updateChannelsInfo(); 212 | updateTriggerInfo(); 213 | 214 | Protocol::TransmissionLog currentLog; 215 | worker->fetchTransmissionLog(currentLog); 216 | pTransmissionLogDialog->updateLog(currentLog); 217 | } 218 | 219 | void SettingsWidget::updateConnectionControls() 220 | { 221 | if (worker->isConnecting()) 222 | { 223 | pProgressbarConnection->set_fraction((double)worker->getProgress()); 224 | pButtonConnect->set_sensitive(false); 225 | pConnectionStatus->set_label("Status: Connecting..."); 226 | } 227 | else 228 | { 229 | pButtonConnect->set_sensitive(true); 230 | if (worker->isConnected()) 231 | { 232 | pConnectionStatus->set_label("Status: Connected to USB @ /dev/ttyACM0"); 233 | pButtonConnect->set_label("Disconnect"); 234 | pProgressbarConnection->set_fraction(1.0); 235 | } 236 | else 237 | { 238 | if (worker->isConnectionLost()) 239 | { 240 | string label = "Error: "; 241 | label += worker->getConnectionLostReason(); 242 | pConnectionStatus->set_label(label); 243 | } 244 | else 245 | pConnectionStatus->set_label("Status: Not connected"); 246 | pButtonConnect->set_label("Connect"); 247 | pProgressbarConnection->set_fraction(0.0); 248 | } 249 | } 250 | } 251 | 252 | void SettingsWidget::updateDeviceInfo() 253 | { 254 | if (worker->isConnecting() || !worker->isConnected()) 255 | { 256 | pTimeBase->set_sensitive(false); 257 | pScopeMode->set_sensitive(false); 258 | pCaptureMode->set_sensitive(false); 259 | pToggleSampling->set_sensitive(false); 260 | 261 | pToggleSampling->set_label("Start sampling"); 262 | } 263 | else 264 | { 265 | pTimeBase->set_sensitive(true); 266 | pScopeMode->set_sensitive(true); 267 | pCaptureMode->set_sensitive(true); 268 | pToggleSampling->set_sensitive(true); 269 | 270 | // pTimeBase->set_active(pTimeBaseStore->children()[(int)device.getTimeBase()]); 271 | // pScopeMode->set_active(pScopeModeStore->children()[(int)device.getScopeMode()]); 272 | // pCaptureMode->set_active(pCaptureModeStore->children()[(int)device.getCaptureMode()]); 273 | 274 | pBatteryLevel->set_value((double)device.getBatteryLevel() / 100); 275 | 276 | stringstream deviceInfo; 277 | 278 | deviceInfo << "Device Info:" << endl 279 | << "Freq div: 0x" << setfill('0') << setw(8) << hex << (uint32_t)device.getTimeBase(); 280 | 281 | pDeviceInfo->set_label(deviceInfo.str()); 282 | 283 | if (!device.isSampling()) 284 | { 285 | pToggleSampling->set_label("Start sampling"); 286 | // pToggleSampling->set_active(true); 287 | } 288 | else 289 | { 290 | pToggleSampling->set_label("Stop sampling"); 291 | // pToggleSampling->set_active(false); 292 | } 293 | } 294 | } 295 | 296 | void SettingsWidget::updateChannelsInfo() 297 | { 298 | if (worker->isConnecting() || !worker->isConnected()) 299 | { 300 | pChannel1Enabled->set_sensitive(false); 301 | pChannel2Enabled->set_sensitive(false); 302 | } 303 | else 304 | { 305 | pChannel1Enabled->set_sensitive(true); 306 | pChannel2Enabled->set_sensitive(true); 307 | if (device.isChannelEnabled(CHANNEL_1)) 308 | { 309 | pChannel1Enabled->set_active(true); 310 | pChannel1Enabled->set_label("Disable"); 311 | } 312 | else 313 | { 314 | pChannel1Enabled->set_active(false); 315 | pChannel1Enabled->set_label("Enable"); 316 | } 317 | if (device.isChannelEnabled(CHANNEL_2)) 318 | { 319 | pChannel2Enabled->set_active(true); 320 | pChannel2Enabled->set_label("Disable"); 321 | } 322 | else 323 | { 324 | pChannel2Enabled->set_active(false); 325 | pChannel2Enabled->set_label("Enable"); 326 | } 327 | } 328 | } 329 | 330 | void SettingsWidget::updateTriggerInfo() 331 | { 332 | if (worker->isConnecting() || !worker->isConnected()) 333 | { 334 | pTriggerMode->set_sensitive(false); 335 | pTriggerChannel->set_sensitive(false); 336 | pTriggerSlope->set_sensitive(false); 337 | } 338 | else 339 | { 340 | pTriggerMode->set_sensitive(true); 341 | pTriggerChannel->set_sensitive(true); 342 | pTriggerSlope->set_sensitive(true); 343 | 344 | // pTriggerMode->set_active(pTriggerModeStore->children()[(int)device.getTriggerMode()]); 345 | // pTriggerChannel->set_active(pTriggerChannelStore->children()[(int)device.getTriggerChannel()]); 346 | // pTriggerSlope->set_active(pTriggerSlopeStore->children()[(int)device.getTriggerSlope()]); 347 | } 348 | } -------------------------------------------------------------------------------- /gui/resources/gui.glade: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Roll 15 | 0 16 | 17 | 18 | Scan 19 | 1 20 | 21 | 22 | Normal 23 | 2 24 | 25 | 26 | 27 | 28 | True 29 | False 30 | vertical 31 | 32 | 33 | Enable 34 | True 35 | False 36 | True 37 | True 38 | 39 | 40 | False 41 | True 42 | 0 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Analog 62 | 0 63 | 64 | 65 | Digital 66 | 1 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 110 | 111 | 2 µs 112 | 8 113 | 114 | 115 | 5 µs 116 | 9 117 | 118 | 119 | 10 µs 120 | 10 121 | 122 | 123 | 20 µs 124 | 11 125 | 126 | 127 | 50 µs 128 | 12 129 | 130 | 131 | 100 µs 132 | 13 133 | 134 | 135 | 200 µs 136 | 14 137 | 138 | 139 | 500 µs 140 | 15 141 | 142 | 143 | 1 ms 144 | 16 145 | 146 | 147 | 2 ms 148 | 17 149 | 150 | 151 | 5 ms 152 | 18 153 | 154 | 155 | 10 ms 156 | 19 157 | 158 | 159 | 20 ms 160 | 20 161 | 162 | 163 | 50 ms 164 | 21 165 | 166 | 167 | 100 ms 168 | 22 169 | 170 | 171 | 200 ms 172 | 23 173 | 174 | 175 | 500 ms 176 | 24 177 | 178 | 179 | 1 s 180 | 25 181 | 182 | 183 | 2 s 184 | 26 185 | 186 | 187 | 5 s 188 | 27 189 | 190 | 191 | 10 s 192 | 28 193 | 194 | 195 | 20 s 196 | 29 197 | 198 | 199 | 50 s 200 | 30 201 | 202 | 203 | 100 s 204 | 31 205 | 206 | 207 | 200 s 208 | 32 209 | 210 | 211 | 500 s 212 | 33 213 | 214 | 215 | 216 | 217 | 218 | 1000 219 | 800 220 | False 221 | 222 | 223 | True 224 | True 225 | immediate 226 | never 227 | in 228 | 800 229 | False 230 | 231 | 232 | True 233 | True 234 | False 235 | 10 236 | 15 237 | 15 238 | 15 239 | 5 240 | False 241 | TransmissionLogBuffer 242 | True 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | Channel 1 258 | 0 259 | 260 | 261 | Channel 2 262 | 1 263 | 264 | 265 | External source 266 | 2 267 | 268 | 269 | External source (10) 270 | 3 271 | 272 | 273 | Alternative 274 | 4 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | Auto 288 | 0 289 | 290 | 291 | Normal 292 | 1 293 | 294 | 295 | Single 296 | 2 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | Rising 310 | 0 311 | 312 | 313 | Falling 314 | 1 315 | 316 | 317 | 318 | 319 | 280 320 | 800 321 | True 322 | False 323 | vertical 324 | 325 | 326 | True 327 | True 328 | True 329 | True 330 | 331 | 332 | True 333 | False 334 | vertical 335 | 336 | 337 | Connect 338 | True 339 | True 340 | True 341 | 342 | 343 | False 344 | True 345 | 5 346 | 0 347 | 348 | 349 | 350 | 351 | True 352 | False 353 | 354 | 355 | False 356 | True 357 | 5 358 | 1 359 | 360 | 361 | 362 | 363 | True 364 | False 365 | start 366 | Status: ... 367 | 368 | 369 | False 370 | True 371 | 2 372 | 373 | 374 | 375 | 376 | 377 | 378 | True 379 | False 380 | Connection 381 | 382 | 383 | 384 | 385 | False 386 | False 387 | 0 388 | 389 | 390 | 391 | 392 | True 393 | True 394 | True 395 | True 396 | 397 | 398 | True 399 | False 400 | vertical 401 | 402 | 403 | True 404 | False 405 | 8 406 | 407 | 408 | True 409 | False 410 | Battery 411 | 412 | 413 | False 414 | True 415 | 0 416 | 417 | 418 | 419 | 420 | True 421 | False 422 | 423 | 424 | True 425 | True 426 | 1 427 | 428 | 429 | 430 | 431 | False 432 | True 433 | 0 434 | 435 | 436 | 437 | 438 | True 439 | False 440 | start 441 | [Device Info] 442 | 443 | 444 | False 445 | True 446 | 10 447 | 1 448 | 449 | 450 | 451 | 452 | Start sampling 453 | True 454 | False 455 | True 456 | True 457 | 458 | 459 | False 460 | True 461 | 5 462 | 2 463 | 464 | 465 | 466 | 467 | True 468 | False 469 | False 470 | TimeBase 471 | 0 472 | 473 | 474 | 475 | 0 476 | 477 | 478 | 479 | 480 | False 481 | True 482 | 3 483 | 484 | 485 | 486 | 487 | True 488 | False 489 | False 490 | ScopeMode 491 | 0 492 | 493 | 494 | 495 | 0 496 | 497 | 498 | 499 | 500 | False 501 | True 502 | 4 503 | 504 | 505 | 506 | 507 | True 508 | False 509 | False 510 | CaptureMode 511 | 0 512 | 513 | 514 | 515 | 0 516 | 517 | 518 | 519 | 520 | False 521 | True 522 | 5 523 | 524 | 525 | 526 | 527 | 528 | 529 | True 530 | False 531 | Device 532 | 533 | 534 | 535 | 536 | False 537 | False 538 | 1 539 | 540 | 541 | 542 | 543 | True 544 | True 545 | True 546 | True 547 | 548 | 549 | True 550 | False 551 | vertical 552 | 553 | 554 | True 555 | False 556 | 0 557 | none 558 | 559 | 560 | True 561 | False 562 | 12 563 | 564 | 565 | True 566 | False 567 | vertical 568 | 569 | 570 | Enable 571 | True 572 | False 573 | True 574 | True 575 | 576 | 577 | False 578 | True 579 | 0 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | True 595 | False 596 | Channel 1 597 | 598 | 599 | 600 | 601 | False 602 | True 603 | 0 604 | 605 | 606 | 607 | 608 | True 609 | False 610 | 0 611 | none 612 | 613 | 614 | True 615 | False 616 | 12 617 | 618 | 619 | True 620 | False 621 | vertical 622 | 623 | 624 | Enable 625 | True 626 | False 627 | True 628 | True 629 | 630 | 631 | False 632 | True 633 | 0 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | True 649 | False 650 | Channel 2 651 | 652 | 653 | 654 | 655 | False 656 | True 657 | 1 658 | 659 | 660 | 661 | 662 | 663 | 664 | True 665 | False 666 | Channels 667 | 668 | 669 | 670 | 671 | False 672 | False 673 | 2 674 | 675 | 676 | 677 | 678 | True 679 | True 680 | True 681 | True 682 | 683 | 684 | True 685 | False 686 | vertical 687 | 688 | 689 | True 690 | False 691 | start 692 | [Trigger Info] 693 | 694 | 695 | False 696 | True 697 | 10 698 | 0 699 | 700 | 701 | 702 | 703 | True 704 | False 705 | False 706 | TriggerMode 707 | 0 708 | 709 | 710 | 711 | 0 712 | 713 | 714 | 715 | 716 | False 717 | True 718 | 1 719 | 720 | 721 | 722 | 723 | True 724 | False 725 | False 726 | TriggerChannel 727 | 0 728 | 729 | 730 | 731 | 0 732 | 733 | 734 | 735 | 736 | False 737 | True 738 | 2 739 | 740 | 741 | 742 | 743 | True 744 | False 745 | False 746 | TriggerSlope 747 | 0 748 | 749 | 750 | 751 | 0 752 | 753 | 754 | 755 | 756 | False 757 | True 758 | 3 759 | 760 | 761 | 762 | 763 | 764 | 765 | True 766 | False 767 | Trigger 768 | 769 | 770 | 771 | 772 | False 773 | False 774 | 3 775 | 776 | 777 | 778 | 779 | True 780 | False 781 | vertical 782 | expand 783 | 784 | 785 | Show log 786 | True 787 | True 788 | True 789 | 790 | 791 | True 792 | True 793 | 0 794 | 795 | 796 | 797 | 798 | False 799 | True 800 | end 801 | 4 802 | 803 | 804 | 805 | 806 | -------------------------------------------------------------------------------- /lib/Protocol.cxx: -------------------------------------------------------------------------------- 1 | #include "Protocol.h" 2 | 3 | #include 4 | 5 | Protocol::Protocol() 6 | { 7 | } 8 | 9 | Protocol::~Protocol() 10 | { 11 | disconnect(); 12 | clearTransmissionLog(); 13 | clearCommandQueue(); 14 | } 15 | 16 | void Protocol::connect(string serialDevice) 17 | { 18 | if (connector) 19 | disconnect(); 20 | 21 | connector = new USBConnector(serialDevice); 22 | 23 | try 24 | { 25 | connector->start(); 26 | } 27 | catch (Connector::Exception &e) 28 | { 29 | if (connectionLostHandler) 30 | connectionLostHandler(e); 31 | } 32 | } 33 | 34 | void Protocol::connect(string serverHost, int port) 35 | { 36 | if (connector) 37 | disconnect(); 38 | 39 | connector = new TCPConnector(serverHost, port); 40 | 41 | try 42 | { 43 | connector->start(); 44 | } 45 | catch (Connector::Exception &e) 46 | { 47 | if (connectionLostHandler) 48 | connectionLostHandler(e); 49 | } 50 | } 51 | 52 | void Protocol::disconnect() 53 | { 54 | if (connector) 55 | { 56 | clearCommandQueue(); 57 | connector->stop(); 58 | delete connector; 59 | connector = NULL; 60 | } 61 | } 62 | 63 | void Protocol::sendCommand(Command *cmd) 64 | { 65 | lock_guard lock(commandMutex); 66 | commandQueue.push_back(cmd); 67 | } 68 | 69 | void Protocol::sendCommandBatch(deque cmds, Command::ResponseHandler finishedHandler) 70 | { 71 | int i = 0; 72 | int total = cmds.size(); 73 | 74 | for (Command *cmd : cmds) 75 | { 76 | if (cmd) 77 | { 78 | float progress = ((float)i + 1.0f) / (float)total; 79 | if ((i + 1) < total) 80 | { 81 | if (progressHandler) 82 | { 83 | ProgressHandler progressHandlerRef = progressHandler; 84 | cmd->setResponseHandler([progressHandlerRef, progress] { 85 | progressHandlerRef(progress); 86 | }); 87 | } 88 | } 89 | else 90 | { 91 | cmd->setResponseHandler(finishedHandler); 92 | } 93 | sendCommand(cmd); 94 | } 95 | i++; 96 | } 97 | } 98 | 99 | void Protocol::init(Command::ResponseHandler finishedHandler) 100 | { 101 | deque initLoadDataCmds; 102 | 103 | // initLoadDataCmds.push_back(cmdFactory.readARMVersion()); 104 | // initLoadDataCmds.push_back(cmdFactory.readFPGAVersion()); 105 | initLoadDataCmds.push_back(cmdFactory.readEEPROMPage(0x00)); 106 | // initLoadDataCmds.push_back(cmdFactory.readEEPROMPage(0x04)); 107 | // initLoadDataCmds.push_back(cmdFactory.readEEPROMPage(0x05)); 108 | // initLoadDataCmds.push_back(cmdFactory.readEEPROMPage(0x07)); 109 | // initLoadDataCmds.push_back(cmdFactory.readEEPROMPage(0x08)); 110 | // initLoadDataCmds.push_back(cmdFactory.readEEPROMPage(0x09)); 111 | // initLoadDataCmds.push_back(cmdFactory.readEEPROMPage(0x0a)); 112 | // initLoadDataCmds.push_back(cmdFactory.readEEPROMPage(0x0b)); 113 | // initLoadDataCmds.push_back(cmdFactory.readEEPROMPage(0x0c)); 114 | 115 | auto stage2 = bind(&Protocol::initStage2, this, placeholders::_1); 116 | 117 | ProgressHandler progressHandlerRef = progressHandler; 118 | sendCommandBatch(initLoadDataCmds, [stage2, progressHandlerRef, finishedHandler] { 119 | if (progressHandlerRef) 120 | progressHandlerRef(1.0f); 121 | stage2(finishedHandler); 122 | }); 123 | } 124 | 125 | void Protocol::initStage2(Command::ResponseHandler finishedHandler) 126 | { 127 | deque cmds; 128 | 129 | { 130 | lock_guard lock(deviceMutex); 131 | cmds.push_back(cmdFactory.updateSampleRate(device.getTimeBase(), device.getEnabledChannelsCount())); 132 | cmds.push_back(cmdFactory.updateFreqDivLowBytes((uint32_t)device.getTimeBase())); 133 | cmds.push_back(cmdFactory.updateFreqDivHighBytes((uint32_t)device.getTimeBase())); 134 | cmds.push_back(cmdFactory.updateChannelSelection(device.isChannelEnabled(CHANNEL_1), device.isChannelEnabled(CHANNEL_2))); 135 | cmds.push_back(cmdFactory.updateTriggerSourceAndSlope(device.getTriggerChannel(), device.getScopeMode(), device.getTriggerSlope())); 136 | cmds.push_back(cmdFactory.updateTriggerLevel(device.getTriggerLevel(), device.getTriggerTopPWM(), device.getTriggerBottomPWM())); 137 | cmds.push_back(cmdFactory.updatePreTriggerLength(device.getSamplesNumberOfOneFrame(), device.getTriggerXPosition())); 138 | cmds.push_back(cmdFactory.updatePostTriggerLength(device.getSamplesNumberOfOneFrame(), device.getTriggerXPosition())); 139 | cmds.push_back(cmdFactory.readRamCount(device.getEnabledChannelsCount(), device.getSamplesNumberOfOneFrame(), device.getTriggerXPosition(), device.getPacketsNumber())); 140 | cmds.push_back(cmdFactory.updateRAMChannelSelection(device.isChannelEnabled(CHANNEL_1), device.isChannelEnabled(CHANNEL_2))); 141 | cmds.push_back(cmdFactory.updateChannelVolts125(device.getChannelVerticalDiv(CHANNEL_1), device.getChannelVerticalDiv(CHANNEL_2))); 142 | cmds.push_back(cmdFactory.updateRelay1(device.getChannelVerticalDiv(CHANNEL_1))); 143 | cmds.push_back(cmdFactory.updateRelay2(device.getChannelVerticalDiv(CHANNEL_1))); 144 | cmds.push_back(cmdFactory.updateRelay3(device.getChannelVerticalDiv(CHANNEL_2))); 145 | cmds.push_back(cmdFactory.updateRelay4(device.getChannelVerticalDiv(CHANNEL_2))); 146 | cmds.push_back(cmdFactory.updateChannel1Level(device.getChannelVerticalDiv(CHANNEL_1), device.getChannelVerticalPosition(CHANNEL_1), device.getChannelPWM(CHANNEL_1, (uint8_t)device.getChannelVerticalDiv(CHANNEL_1), 0), device.getChannelPWM(CHANNEL_1, (uint8_t)device.getChannelVerticalDiv(CHANNEL_1), 1))); 147 | cmds.push_back(cmdFactory.updateChannel2Level(device.getChannelVerticalDiv(CHANNEL_2), device.getChannelVerticalPosition(CHANNEL_2), device.getChannelPWM(CHANNEL_2, (uint8_t)device.getChannelVerticalDiv(CHANNEL_2), 0), device.getChannelPWM(CHANNEL_2, (uint8_t)device.getChannelVerticalDiv(CHANNEL_2), 1))); 148 | cmds.push_back(cmdFactory.updateChannelVolts125(device.getChannelVerticalDiv(CHANNEL_1), device.getChannelVerticalDiv(CHANNEL_2))); 149 | cmds.push_back(cmdFactory.updateTriggerMode(device.getCaptureMode(), device.getTriggerMode(), device.getScopeMode())); 150 | cmds.push_back(cmdFactory.updateTriggerLevel(device.getTriggerLevel(), device.getTriggerTopPWM(), device.getTriggerBottomPWM())); 151 | cmds.push_back(cmdFactory.updateChannel1Coupling(device.getChannelCoupling(CHANNEL_1))); 152 | cmds.push_back(cmdFactory.updateChannel2Coupling(device.getChannelCoupling(CHANNEL_2))); 153 | } 154 | 155 | ProgressHandler progressHandlerRef = progressHandler; 156 | sendCommandBatch(cmds, [progressHandlerRef, finishedHandler] { 157 | if (progressHandlerRef) 158 | progressHandlerRef(1.0f); 159 | finishedHandler(); 160 | }); 161 | } 162 | 163 | void Protocol::readBatteryLevel(Command::ResponseHandler responseHandler) 164 | { 165 | Command *cmd = cmdFactory.readBatteryLevel(); 166 | cmd->setResponseHandler(responseHandler); 167 | sendCommand(cmd); 168 | } 169 | 170 | void Protocol::setTimeBase(TimeBase timeBase, Command::ResponseHandler responseHandler) 171 | { 172 | deque cmds; 173 | { 174 | lock_guard lock(deviceMutex); 175 | cmds.push_back(cmdFactory.updateSampleRate(timeBase, device.getEnabledChannelsCount())); 176 | cmds.push_back(cmdFactory.updateFreqDivLowBytes((uint32_t)timeBase)); 177 | cmds.push_back(cmdFactory.updateFreqDivHighBytes((uint32_t)timeBase)); 178 | } 179 | ProgressHandler progressHandlerRef = progressHandler; 180 | sendCommandBatch(cmds, [progressHandlerRef, responseHandler] { 181 | if (progressHandlerRef) 182 | progressHandlerRef(1.0f); 183 | responseHandler(); 184 | }); 185 | } 186 | 187 | void Protocol::setScopeMode(ScopeMode scopeMode, Command::ResponseHandler responseHandler) 188 | { 189 | deque cmds; 190 | { 191 | lock_guard lock(deviceMutex); 192 | cmds.push_back(cmdFactory.updateTriggerSourceAndSlope(device.getTriggerChannel(), scopeMode, device.getTriggerSlope())); 193 | cmds.push_back(cmdFactory.updateTriggerMode(device.getCaptureMode(), device.getTriggerMode(), scopeMode)); 194 | } 195 | ProgressHandler progressHandlerRef = progressHandler; 196 | sendCommandBatch(cmds, [progressHandlerRef, responseHandler] { 197 | if (progressHandlerRef) 198 | progressHandlerRef(1.0f); 199 | responseHandler(); 200 | }); 201 | } 202 | 203 | void Protocol::setCaptureMode(CaptureMode captureMode, Command::ResponseHandler responseHandler) 204 | { 205 | lock_guard lock(deviceMutex); 206 | Command *cmd = cmdFactory.updateTriggerMode(captureMode, device.getTriggerMode(), device.getScopeMode()); 207 | cmd->setResponseHandler(responseHandler); 208 | sendCommand(cmd); 209 | } 210 | 211 | void Protocol::enableChannel(ChannelSelector channel, Command::ResponseHandler responseHandler) 212 | { 213 | } 214 | 215 | void Protocol::disableChannel(ChannelSelector channel, Command::ResponseHandler responseHandler) 216 | { 217 | } 218 | 219 | void Protocol::setChannelVerticalDiv(ChannelSelector channel, VoltageDiv div, Command::ResponseHandler responseHandler) 220 | { 221 | } 222 | 223 | void Protocol::setChannelCoupling(ChannelSelector channel, InputCoupling coupling, Command::ResponseHandler responseHandler) 224 | { 225 | } 226 | 227 | void Protocol::setChannelVerticalPosition(ChannelSelector channel, uint16_t pos, Command::ResponseHandler responseHandler) 228 | { 229 | } 230 | 231 | void Protocol::setTriggerMode(TriggerMode mode, Command::ResponseHandler responseHandler) 232 | { 233 | lock_guard lock(deviceMutex); 234 | Command *cmd = cmdFactory.updateTriggerMode(device.getCaptureMode(), mode, device.getScopeMode()); 235 | cmd->setResponseHandler(responseHandler); 236 | sendCommand(cmd); 237 | } 238 | 239 | void Protocol::setTriggerChannel(TriggerChannel channel, Command::ResponseHandler responseHandler) 240 | { 241 | lock_guard lock(deviceMutex); 242 | Command *cmd = cmdFactory.updateTriggerSourceAndSlope(channel, device.getScopeMode(), device.getTriggerSlope()); 243 | cmd->setResponseHandler(responseHandler); 244 | sendCommand(cmd); 245 | } 246 | 247 | void Protocol::setTriggerSlope(TriggerSlope slope, Command::ResponseHandler responseHandler) 248 | { 249 | lock_guard lock(deviceMutex); 250 | Command *cmd = cmdFactory.updateTriggerSourceAndSlope(device.getTriggerChannel(), device.getScopeMode(), slope); 251 | cmd->setResponseHandler(responseHandler); 252 | sendCommand(cmd); 253 | } 254 | 255 | void Protocol::setTriggerLevel(uint16_t level, Command::ResponseHandler responseHandler) 256 | { 257 | lock_guard lock(deviceMutex); 258 | Command *cmd = cmdFactory.updateTriggerLevel(level, device.getTriggerTopPWM(), device.getTriggerBottomPWM()); 259 | cmd->setResponseHandler(responseHandler); 260 | sendCommand(cmd); 261 | } 262 | 263 | void Protocol::startSampling(Command::ResponseHandler responseHandler) 264 | { 265 | lock_guard lock(deviceMutex); 266 | Command *cmd = cmdFactory.startSampling(); 267 | cmd->setResponseHandler(responseHandler); 268 | sendCommand(cmd); 269 | } 270 | 271 | void Protocol::stopSampling(Command::ResponseHandler responseHandler) 272 | { 273 | Command *cmd = cmdFactory.readARMVersion(); 274 | cmd->setResponseHandler(responseHandler); 275 | sendCommand(cmd); 276 | } 277 | 278 | void Protocol::receive() 279 | { 280 | connector->receive(); 281 | while (connector->getResponseBufferSize() > 0) 282 | { 283 | // // This is only for some packets in wifi mode, drops current packet 284 | // if (ignoreNextResponse) 285 | // { 286 | // currentResponse = connector->getLatestResponse(); 287 | // delete currentResponse; 288 | // currentResponse = NULL; 289 | // ignoreNextResponse = false; 290 | // } 291 | // // Default message handling 292 | // else 293 | // { 294 | currentResponse = connector->getLatestResponse(); 295 | 296 | parse(currentResponse); 297 | if (currentCommand) 298 | { 299 | 300 | // // If it's a wifi connector, we get two responses per command 301 | // if (match && connector->getType() == CONNECTOR_WIFI) 302 | // ignoreNextResponse = true; 303 | 304 | if (currentResponse->getCommandCode() == 0x04 && currentResponse->getCommandType() == TYPE_CONTROL) 305 | { 306 | lock_guard lock(deviceMutex); 307 | // Enable sampling flag 308 | device.setSampling(true); 309 | } 310 | 311 | // Check if received packet is response to sent command 312 | bool match = currentCommand->getPayload()[0] == currentResponse->getCommandType() && 313 | currentCommand->getPayload()[1] == currentResponse->getCommandCode(); 314 | 315 | // Call handler of current command 316 | if (!match && retries < MaxCommandRetries) 317 | retries++; 318 | else 319 | { 320 | currentCommand->callResponseHandler(); 321 | 322 | // Put transmission into log 323 | { 324 | lock_guard lock(logMutex); 325 | transmissionLog.push_back(new Transmission(*currentCommand, *currentResponse)); 326 | } 327 | 328 | // Remove current command 329 | { 330 | lock_guard lock(commandMutex); 331 | commandQueue.pop_front(); 332 | } 333 | delete currentCommand; 334 | currentCommand = NULL; 335 | retries = 0; 336 | } 337 | } 338 | delete currentResponse; 339 | currentResponse = NULL; 340 | } 341 | } 342 | 343 | void Protocol::transmit() 344 | { 345 | lock_guard lock(commandMutex); 346 | // Check if there are any commands 347 | if (commandQueue.size() > 0) 348 | { 349 | // Get current command from queue 350 | currentCommand = *(commandQueue.begin()); 351 | 352 | // Transmit current command 353 | connector->transmit(currentCommand->getPayload(), 4); 354 | } 355 | } 356 | 357 | void Protocol::process() 358 | { 359 | if (connector && connector->isConnected()) 360 | { 361 | try 362 | { 363 | transmit(); 364 | receive(); 365 | } 366 | catch (Connector::Exception &e) 367 | { 368 | if (connectionLostHandler) 369 | connectionLostHandler(e); 370 | } 371 | } 372 | } 373 | 374 | void Protocol::setConnectionLostHandler(ConnectionLostHandler connectionLostHandler) 375 | { 376 | this->connectionLostHandler = connectionLostHandler; 377 | } 378 | 379 | void Protocol::setProgressHandler(ProgressHandler progressHandler) 380 | { 381 | this->progressHandler = progressHandler; 382 | } 383 | 384 | void Protocol::fetchSamples(SampleBuffer &buffer) 385 | { 386 | lock_guard lock(sampleMutex); 387 | if (sampleBuffer.channel1.size() > 0) 388 | { 389 | for (auto sample : sampleBuffer.channel1) 390 | { 391 | buffer.channel1.push_back(sample); 392 | } 393 | sampleBuffer.channel1.clear(); 394 | } 395 | if (sampleBuffer.channel2.size() > 0) 396 | { 397 | for (auto sample : sampleBuffer.channel2) 398 | { 399 | buffer.channel2.push_back(sample); 400 | } 401 | sampleBuffer.channel2.clear(); 402 | } 403 | } 404 | 405 | Connector *Protocol::getConnector() 406 | { 407 | return connector; 408 | } 409 | 410 | void Protocol::fetchDevice(IDSO1070 &dev) 411 | { 412 | lock_guard lock(deviceMutex); 413 | dev = device; 414 | } 415 | 416 | void Protocol::fetchTransmissionLog(TransmissionLog &log) 417 | { 418 | lock_guard lock(logMutex); 419 | log = transmissionLog; 420 | } 421 | 422 | void Protocol::clearTransmissionLog(bool deleteObjects) 423 | { 424 | lock_guard lock(logMutex); 425 | if (deleteObjects) 426 | { 427 | for (auto transmission : transmissionLog) 428 | { 429 | delete transmission; 430 | } 431 | } 432 | transmissionLog.clear(); 433 | } 434 | 435 | void Protocol::clearCommandQueue() 436 | { 437 | lock_guard lock(commandMutex); 438 | for (auto command : commandQueue) 439 | { 440 | delete command; 441 | } 442 | commandQueue.clear(); 443 | } 444 | 445 | void Protocol::parse(Response *packet) 446 | { 447 | switch (packet->getCommandType()) 448 | { 449 | case TYPE_CONTROL: 450 | parseAAResponse(packet); 451 | return; 452 | case TYPE_EEPROM: 453 | parseEEResponse(packet); 454 | return; 455 | case TYPE_FPGA: 456 | parseFPGAResponse(packet); 457 | return; 458 | case TYPE_STATE: 459 | parseStateResponse(packet); 460 | return; 461 | default: 462 | return; 463 | } 464 | } 465 | 466 | void Protocol::parseAAResponse(Response *packet) 467 | { 468 | switch (packet->getCommandCode()) 469 | { 470 | case 0x02: 471 | // Parse FPGA version 472 | char version[9]; 473 | for (int i = 0; i < 8; i++) 474 | { 475 | version[i] = 0x30 + packet->getPayload()[6 + i]; 476 | } 477 | version[8] = 0; 478 | { 479 | lock_guard lock(deviceMutex); 480 | device.setFPGAFirmwareVersion(version); 481 | } 482 | return; 483 | case 0x04: 484 | // Parse sample 485 | parse((Sample *)packet); 486 | return; 487 | default: 488 | return; 489 | } 490 | } 491 | 492 | void Protocol::parseEEResponse(Response *packet) 493 | { 494 | if (packet->getCommandCode() == 0xaa) 495 | { 496 | switch (packet->getHeader()[5]) 497 | { 498 | case 0x00: 499 | parseEEPROMPage00(packet); 500 | return; 501 | case 0x04: 502 | { 503 | lock_guard lock(deviceMutex); 504 | device.setFPGAAlert(packet->getPayload()); 505 | } 506 | return; 507 | case 0x05: 508 | { 509 | lock_guard lock(deviceMutex); 510 | device.setUserName((char *)packet->getPayload()); 511 | device.setProductName((char *)&packet->getPayload()[12]); 512 | } 513 | return; 514 | case 0x07: 515 | { 516 | lock_guard lock(deviceMutex); 517 | device.setDiffFixData(0, 0, packet->getPayload()); 518 | } 519 | return; 520 | case 0x08: 521 | { 522 | lock_guard lock(deviceMutex); 523 | device.setDiffFixData(0, 100, packet->getPayload()); 524 | } 525 | return; 526 | case 0x09: 527 | { 528 | lock_guard lock(deviceMutex); 529 | device.setDiffFixData(0, 200, packet->getPayload()); 530 | } 531 | return; 532 | case 0x0a: 533 | { 534 | lock_guard lock(deviceMutex); 535 | device.setDiffFixData(1, 0, packet->getPayload()); 536 | } 537 | return; 538 | case 0x0b: 539 | { 540 | lock_guard lock(deviceMutex); 541 | device.setDiffFixData(1, 100, packet->getPayload()); 542 | } 543 | return; 544 | case 0x0c: 545 | { 546 | lock_guard lock(deviceMutex); 547 | device.setDiffFixData(1, 200, packet->getPayload()); 548 | } 549 | return; 550 | default: 551 | return; 552 | } 553 | } 554 | } 555 | 556 | void Protocol::parseFPGAResponse(Response *packet) 557 | { 558 | switch (packet->getCommandCode()) 559 | { 560 | case CMDCODE_FORCE_TRIGGER: 561 | return; 562 | case CMDCODE_TRIGGER_MODE: 563 | parseTriggerMode(packet); 564 | return; 565 | case CMDCODE_SET_RELAY: 566 | parseRelay(packet); 567 | return; 568 | case CMDCODE_CHANNEL_SELECTION: 569 | return; 570 | case CMDCODE_TRIGGER_SOURCE: 571 | parseTriggerSourceAndSlope(packet); 572 | return; 573 | case CMDCODE_CHANNEL_VOLTS_DIV_125: 574 | parseVoltsDiv125(packet); 575 | return; 576 | case CMDCODE_PRE_TRIGGER_LENGTH: 577 | return; 578 | case CMDCODE_POST_TRIGGER_LENGTH: 579 | return; 580 | case CMDCODE_RAM_START_POSITION: 581 | return; 582 | case CMDCODE_RESERVED_DATA_OUTPUT: 583 | return; 584 | case CMDCODE_CH1_PWM: 585 | parseCh1ZeroLevel(packet); 586 | return; 587 | case CMDCODE_CH2_PWM: 588 | parseCh2ZeroLevel(packet); 589 | return; 590 | case CMDCODE_TRIGGER_PWM: 591 | parseTriggerLevel(packet); 592 | return; 593 | case CMDCODE_LOGIC_ANALYZER_1: 594 | return; 595 | case CMDCODE_LOGIC_ANALYZER_2: 596 | return; 597 | case CMDCODE_LOGIC_ANALYZER_3: 598 | return; 599 | case CMDCODE_SAMPLE_RATE: 600 | return; 601 | case CMDCODE_FREQ_DIV_LOW: 602 | parseFreqDivLowBytes(packet); 603 | return; 604 | case CMDCODE_FREQ_DIV_HIGH: 605 | parseFreqDivHighBytes(packet); 606 | return; 607 | case CMDCODE_SERIAL_BAUD_RATE: 608 | // Serial baud rate 609 | return; 610 | case CMDCODE_RAM_CHANNEL_SELECTION: 611 | parseRamChannelSelection(packet); 612 | return; 613 | case CMDCODE_READ_RAM_COUNT: 614 | return; 615 | default: 616 | return; 617 | } 618 | } 619 | 620 | void Protocol::parseStateResponse(Response *packet) 621 | { 622 | switch (packet->getCommandCode()) 623 | { 624 | // Battery level response 625 | case 0x03: 626 | { 627 | lock_guard lock(deviceMutex); 628 | device.setBatteryLevel(packet->getPayload()[0]); 629 | } 630 | return; 631 | // Firmware version response 632 | case 0x04: 633 | char version[9]; 634 | memcpy(version, packet->getPayload(), 8); 635 | version[8] = 0; 636 | { 637 | lock_guard lock(deviceMutex); 638 | device.setARMFirmwareVersion(version); 639 | } 640 | return; 641 | default: 642 | return; 643 | } 644 | } 645 | 646 | void Protocol::parseFreqDivLowBytes(Response *packet) 647 | { 648 | int i = ((packet->getHeader()[6] & 255) << 8) | (packet->getHeader()[5] & 0xff); 649 | { 650 | lock_guard lock(deviceMutex); 651 | device.setTimeBase((TimeBase)i); 652 | } 653 | } 654 | 655 | void Protocol::parseFreqDivHighBytes(Response *packet) 656 | { 657 | int i = ((packet->getHeader()[6] & 0xff) << 8) | (packet->getHeader()[5] & 0xff); 658 | { 659 | lock_guard lock(deviceMutex); 660 | uint32_t update = (uint32_t)device.getTimeBase(); 661 | update |= (i << 16); 662 | device.setTimeBase((TimeBase)update); 663 | } 664 | } 665 | 666 | void Protocol::parseRamChannelSelection(Response *packet) 667 | { 668 | switch (packet->getHeader()[5]) 669 | { 670 | case 0x00: 671 | { 672 | lock_guard lock(deviceMutex); 673 | device.enableChannel(CHANNEL_1); 674 | device.enableChannel(CHANNEL_2); 675 | } 676 | break; 677 | case 0x01: 678 | { 679 | lock_guard lock(deviceMutex); 680 | device.disableChannel(CHANNEL_1); 681 | device.disableChannel(CHANNEL_2); 682 | } 683 | break; 684 | case 0x08: 685 | { 686 | lock_guard lock(deviceMutex); 687 | device.enableChannel(CHANNEL_1); 688 | device.disableChannel(CHANNEL_2); 689 | device.setSelectedChannel(CHANNEL_1); 690 | } 691 | break; 692 | case 0x09: 693 | { 694 | lock_guard lock(deviceMutex); 695 | device.disableChannel(CHANNEL_1); 696 | device.enableChannel(CHANNEL_2); 697 | device.setSelectedChannel(CHANNEL_2); 698 | } 699 | break; 700 | } 701 | } 702 | 703 | void Protocol::parseRelay(Response *packet) 704 | { 705 | switch (packet->getHeader()[5]) 706 | { 707 | case 0x80: 708 | { 709 | lock_guard lock(deviceMutex); 710 | device.setChannelVoltageRL1(CHANNEL_1, 1.0); 711 | } 712 | break; 713 | case 0xbf: 714 | { 715 | lock_guard lock(deviceMutex); 716 | device.setChannelVoltageRL1(CHANNEL_2, 0.1); 717 | } 718 | // device.getChannel2().setVoltageRL1(0.1); 719 | break; 720 | case 0xfb: 721 | { 722 | lock_guard lock(deviceMutex); 723 | device.setChannelVoltageRL2(CHANNEL_2, 0.1); 724 | } 725 | // device.getChannel2().setVoltageRL2(0.1); 726 | break; 727 | case 0xfd: 728 | { 729 | lock_guard lock(deviceMutex); 730 | device.setChannelVoltageRL2(CHANNEL_1, 0.1); 731 | } 732 | // device.getChannel1().setVoltageRL2(0.1); 733 | break; 734 | case 0x02: 735 | { 736 | lock_guard lock(deviceMutex); 737 | device.setChannelVoltageRL2(CHANNEL_1, 1.0); 738 | } 739 | // device.getChannel1().setVoltageRL2(1.0); 740 | break; 741 | case 0x04: 742 | { 743 | lock_guard lock(deviceMutex); 744 | device.setChannelVoltageRL2(CHANNEL_2, 1.0); 745 | } 746 | // device.getChannel2().setVoltageRL2(1.0); 747 | break; 748 | case 0x40: 749 | { 750 | lock_guard lock(deviceMutex); 751 | device.setChannelVoltageRL1(CHANNEL_2, 1.0); 752 | } 753 | // device.getChannel2().setVoltageRL1(1.0); 754 | break; 755 | case 0x7f: 756 | { 757 | lock_guard lock(deviceMutex); 758 | device.setChannelVoltageRL1(CHANNEL_1, 0.1); 759 | } 760 | // device.getChannel1().setVoltageRL1(0.1); 761 | break; 762 | default: 763 | parseCoupling(packet); 764 | break; 765 | } 766 | // switch (packet->getHeader()[5]) 767 | // { 768 | // case 0x80: 769 | // case 0x7f: 770 | // updateCh1VoltsDivStatusAfterReceivedRL1(); 771 | // return; 772 | // case 0xbf: 773 | // case 0x40: 774 | // updateCh2VoltsDivStatusAfterReceivedRL3(); 775 | // return; 776 | // case 0xfb: 777 | // case 0x04: 778 | // updateCh2VoltsDivStatusAfterReceivedRL4(); 779 | // return; 780 | // case 0xfd: 781 | // case 0x02: 782 | // updateCh1VoltsDivStatusAfterReceivedRL2(); 783 | // return; 784 | // default: 785 | // return; 786 | // } 787 | } 788 | 789 | void Protocol::parseCh1ZeroLevel(Response *packet) 790 | { 791 | int i = ((packet->getHeader()[6] & 0x0f) << 8) + (packet->getHeader()[5] & 0xff); 792 | { 793 | lock_guard lock(deviceMutex); 794 | int ordinal = (int)device.getChannelVerticalDiv(CHANNEL_1); 795 | i = (int)roundf(mapValue(i, (float)device.getChannelPWM(CHANNEL_1, ordinal, 0), (float)device.getChannelPWM(CHANNEL_1, ordinal, 1), 8.0f, 248.0f)); 796 | device.setChannelVerticalPosition(CHANNEL_1, i); 797 | } 798 | } 799 | 800 | void Protocol::parseCh2ZeroLevel(Response *packet) 801 | { 802 | int i = ((packet->getHeader()[6] & 0x0f) << 8) + (packet->getHeader()[5] & 0xff); 803 | { 804 | lock_guard lock(deviceMutex); 805 | int ordinal = (int)device.getChannelVerticalDiv(CHANNEL_2); 806 | i = (int)roundf(mapValue(i, (float)device.getChannelPWM(CHANNEL_2, ordinal, 0), (float)device.getChannelPWM(CHANNEL_2, ordinal, 1), 8.0f, 248.0f)); 807 | device.setChannelVerticalPosition(CHANNEL_2, i); 808 | } 809 | } 810 | 811 | void Protocol::parseVoltsDiv125(Response *packet) 812 | { 813 | switch (packet->getHeader()[5] & 3) 814 | { 815 | case 0: 816 | { 817 | lock_guard lock(deviceMutex); 818 | device.setChannelVoltage125(CHANNEL_1, 1.0); 819 | } 820 | break; 821 | case 1: 822 | { 823 | lock_guard lock(deviceMutex); 824 | device.setChannelVoltage125(CHANNEL_1, 2.0); 825 | } 826 | break; 827 | case 2: 828 | { 829 | lock_guard lock(deviceMutex); 830 | device.setChannelVoltage125(CHANNEL_1, 5.0); 831 | } 832 | break; 833 | } 834 | // updateCh1VoltsDivStatusAfterReceived125(); 835 | switch ((packet->getHeader()[5] >> 2) & 3) 836 | { 837 | case 0: 838 | { 839 | lock_guard lock(deviceMutex); 840 | device.setChannelVoltage125(CHANNEL_2, 1.0); 841 | } 842 | break; 843 | case 1: 844 | { 845 | lock_guard lock(deviceMutex); 846 | device.setChannelVoltage125(CHANNEL_2, 2.0); 847 | } 848 | break; 849 | case 2: 850 | { 851 | lock_guard lock(deviceMutex); 852 | device.setChannelVoltage125(CHANNEL_2, 5.0); 853 | } 854 | break; 855 | } 856 | // updateCh2VoltsDivStatusAfterReceived125(); 857 | } 858 | 859 | void Protocol::parseTriggerLevel(Response *packet) 860 | { 861 | uint16_t i = ((packet->getHeader()[6] & 0x0f) << 8) + (packet->getHeader()[5] & 0xff); 862 | { 863 | lock_guard lock(deviceMutex); 864 | i = (uint16_t)roundf(mapValue(i, (float)device.getTriggerBottomPWM(), (float)device.getTriggerTopPWM(), 8.0f, 248.0f)); 865 | device.setTriggerLevel(i); 866 | } 867 | } 868 | 869 | void Protocol::parseTriggerSourceAndSlope(Response *packet) 870 | { 871 | uint8_t i = packet->getHeader()[5] & 3; 872 | 873 | if (i == 0) 874 | { 875 | lock_guard lock(deviceMutex); 876 | device.setTriggerChannel(TRIGCHAN_CH2); 877 | } 878 | else if (i == 1) 879 | { 880 | lock_guard lock(deviceMutex); 881 | device.setTriggerChannel(TRIGCHAN_CH1); 882 | } 883 | else if (i == 2) 884 | { 885 | lock_guard lock(deviceMutex); 886 | device.setTriggerChannel(TRIGCHAN_EXT); 887 | } 888 | if (packet->getHeader()[5] & (1 << 4)) 889 | { 890 | lock_guard lock(deviceMutex); 891 | device.setScopeMode(SCOMODE_ANALOG); 892 | } 893 | else 894 | { 895 | lock_guard lock(deviceMutex); 896 | device.setScopeMode(SCOMODE_DIGITAL); 897 | } 898 | if (packet->getHeader()[5] & (1 << 7)) 899 | { 900 | lock_guard lock(deviceMutex); 901 | device.setTriggerSlope(TRIGSLOPE_RISING); 902 | } 903 | else 904 | { 905 | lock_guard lock(deviceMutex); 906 | device.setTriggerSlope(TRIGSLOPE_FALLING); 907 | } 908 | } 909 | 910 | void Protocol::parseTriggerMode(Response *packet) 911 | { 912 | { 913 | lock_guard lock(deviceMutex); 914 | device.setLittlePacketStatus(0); 915 | } 916 | 917 | uint8_t b = packet->getHeader()[5]; 918 | if (b & (1 << 0)) 919 | { 920 | lock_guard lock(deviceMutex); 921 | device.setCaptureMode(CAPMODE_ROLL); 922 | } 923 | else if (b & (1 << 3)) 924 | { 925 | lock_guard lock(deviceMutex); 926 | device.setCaptureMode(CAPMODE_SCAN); 927 | } 928 | else 929 | { 930 | lock_guard lock(deviceMutex); 931 | device.setCaptureMode(CAPMODE_NORMAL); 932 | } 933 | if (b & (1 << 1)) 934 | { 935 | lock_guard lock(deviceMutex); 936 | device.setTriggerMode(TRIGMODE_AUTO); 937 | } 938 | else if (b & (1 << 2)) 939 | { 940 | lock_guard lock(deviceMutex); 941 | device.setTriggerMode(TRIGMODE_SINGLE); 942 | } 943 | else 944 | { 945 | lock_guard lock(deviceMutex); 946 | device.setTriggerMode(TRIGMODE_NORMAL); 947 | } 948 | } 949 | 950 | void Protocol::parseCoupling(Response *packet) 951 | { 952 | switch (packet->getHeader()[5]) 953 | { 954 | case 0xef: 955 | { 956 | lock_guard lock(deviceMutex); 957 | device.setChannelCoupling(CHANNEL_1, COUPLING_DC); 958 | } 959 | break; 960 | case 0xfe: 961 | { 962 | lock_guard lock(deviceMutex); 963 | device.setChannelCoupling(CHANNEL_2, COUPLING_DC); 964 | } 965 | break; 966 | case 0xff: 967 | if (packet->getHeader()[6] == 0x01) 968 | { 969 | lock_guard lock(deviceMutex); 970 | device.setChannelCoupling(CHANNEL_1, COUPLING_GND); 971 | } 972 | else if (packet->getHeader()[6] == 0x02) 973 | { 974 | lock_guard lock(deviceMutex); 975 | device.setChannelCoupling(CHANNEL_2, COUPLING_GND); 976 | } 977 | break; 978 | case 0x01: 979 | { 980 | lock_guard lock(deviceMutex); 981 | device.setChannelCoupling(CHANNEL_1, COUPLING_AC); 982 | } 983 | break; 984 | case 0x10: 985 | { 986 | lock_guard lock(deviceMutex); 987 | device.setChannelCoupling(CHANNEL_2, COUPLING_AC); 988 | } 989 | break; 990 | } 991 | } 992 | 993 | void Protocol::parseEEPROMPage00(Response *packet) 994 | { 995 | { 996 | lock_guard lock(deviceMutex); 997 | device.setCaliLevel(packet->getPayload()); 998 | } 999 | uint16_t *iArr; 1000 | int i = 0; 1001 | int i2 = 0; 1002 | 1003 | int tmpA = 0; 1004 | int tmpB = 0; 1005 | while (tmpB < 9) 1006 | { 1007 | i = tmpA + 1; 1008 | { 1009 | lock_guard lock(deviceMutex); 1010 | device.setChannelPWM(CHANNEL_1, packet->getPayload()[tmpA] & 255, tmpB, 0); 1011 | iArr = device.getChannelPWM(CHANNEL_1, tmpB); 1012 | } 1013 | int tmp = i + 1; 1014 | iArr[0] = iArr[0] + ((packet->getPayload()[i] & 255) << 8); 1015 | i = tmp + 1; 1016 | { 1017 | lock_guard lock(deviceMutex); 1018 | device.setChannelPWM(CHANNEL_1, packet->getPayload()[tmp] & 255, tmpB, 1); 1019 | iArr = device.getChannelPWM(CHANNEL_1, tmpB); 1020 | } 1021 | i2 = i + 1; 1022 | iArr[1] = ((packet->getPayload()[i] & 255) << 8) + iArr[1]; 1023 | tmpB++; 1024 | tmpA = i2; 1025 | } 1026 | tmpB = tmpA; 1027 | for (tmpA = 0; tmpA < 9; tmpA++) 1028 | { 1029 | lock_guard lock(deviceMutex); 1030 | i = tmpB + 1; 1031 | device.setChannelPWM(CHANNEL_2, packet->getPayload()[tmpB] & 255, tmpA, 0); 1032 | uint16_t *iArr2 = device.getChannelPWM(CHANNEL_2, tmpA); 1033 | int tmp = i + 1; 1034 | iArr2[0] = iArr2[0] + ((packet->getPayload()[i] & 255) << 8); 1035 | i2 = tmp + 1; 1036 | device.setChannelPWM(CHANNEL_2, packet->getPayload()[tmp] & 255, tmpA, 1); 1037 | uint16_t *iArr3 = device.getChannelPWM(CHANNEL_2, tmpA); 1038 | tmpB = i2 + 1; 1039 | iArr3[1] = ((packet->getPayload()[i2] & 255) << 8) + iArr3[1]; 1040 | } 1041 | i2 = tmpB + 1; 1042 | { 1043 | lock_guard lock(deviceMutex); 1044 | device.setTriggerInnerPWM(0, packet->getPayload()[tmpB] & 255); 1045 | iArr = device.getTriggerInnerPWM(); 1046 | } 1047 | i = i2 + 1; 1048 | iArr[0] = iArr[0] + ((packet->getPayload()[i2] & 255) << 8); 1049 | tmpB = i + 1; 1050 | { 1051 | lock_guard lock(deviceMutex); 1052 | device.setTriggerInnerPWM(1, packet->getPayload()[i] & 255); 1053 | iArr = device.getTriggerInnerPWM(); 1054 | } 1055 | i = tmpB + 1; 1056 | iArr[1] = ((packet->getPayload()[tmpB] & 255) << 8) + iArr[1]; 1057 | tmpB = i + 1; 1058 | { 1059 | lock_guard lock(deviceMutex); 1060 | device.setTriggerInnerPWM(0, packet->getPayload()[i] & 255); 1061 | iArr = device.getTriggerInnerPWM(); 1062 | } 1063 | i = tmpB + 1; 1064 | iArr[0] = ((packet->getPayload()[tmpB] & 255) << 8) + iArr[0]; 1065 | tmpB = i + 1; 1066 | { 1067 | lock_guard lock(deviceMutex); 1068 | device.setTriggerInnerPWM(1, packet->getPayload()[i] & 255); 1069 | iArr = device.getTriggerInnerPWM(); 1070 | } 1071 | i = tmpB + 1; 1072 | iArr[1] = ((packet->getPayload()[tmpB] & 255) << 8) + iArr[1]; 1073 | tmpB = i + 1; 1074 | { 1075 | lock_guard lock(deviceMutex); 1076 | device.setTriggerInnerPWM(2, packet->getPayload()[i] & 255); 1077 | iArr = device.getTriggerInnerPWM(); 1078 | } 1079 | i = tmpB + 1; 1080 | iArr[2] = ((packet->getPayload()[tmpB] & 255) << 8) + iArr[2]; 1081 | tmpB = i + 1; 1082 | { 1083 | lock_guard lock(deviceMutex); 1084 | device.setTriggerInnerPWM(3, packet->getPayload()[i] & 255); 1085 | iArr = device.getTriggerInnerPWM(); 1086 | } 1087 | i = tmpB + 1; 1088 | iArr[3] = ((packet->getPayload()[tmpB] & 255) << 8) + iArr[3]; 1089 | { 1090 | lock_guard lock(deviceMutex); 1091 | if (device.getTriggerInnerPWM(2) < IDSO1070::SamplesCountPerPacket || device.getTriggerInnerPWM(2) > 4000) 1092 | { 1093 | device.setTriggerInnerPWM(2, device.getTriggerInnerPWM(0)); 1094 | } 1095 | if (device.getTriggerInnerPWM(3) < IDSO1070::SamplesCountPerPacket || device.getTriggerInnerPWM(3) > 4000) 1096 | { 1097 | device.setTriggerInnerPWM(3, device.getTriggerInnerPWM(1)); 1098 | } 1099 | } 1100 | return; 1101 | } 1102 | 1103 | void Protocol::parse(Sample *packet) 1104 | { 1105 | uint8_t head = packet->getPayload()[0]; 1106 | if (head & (1 << 5)) 1107 | { 1108 | int i = head & 0x0f; 1109 | { 1110 | lock_guard lock(deviceMutex); 1111 | if (device.getLittlePacketStatus() == i) 1112 | { 1113 | device.setLittlePacketStatus(device.getLittlePacketStatus() + 1); 1114 | parseSamplePacket(packet, i); 1115 | if (i == (device.getPacketsNumber() - 1)) 1116 | { 1117 | device.setLittlePacketStatus(0); 1118 | 1119 | interpolateSamples(); 1120 | 1121 | // if (this.connector.isSendingCommands()) { 1122 | // return; 1123 | // } 1124 | 1125 | if (head & (1 << 6)) 1126 | { 1127 | printf("\n\nTrigger compared\n\n"); 1128 | // trigger compared 1129 | } 1130 | 1131 | if (head & (1 << 4)) 1132 | { 1133 | printf("\n\nWave found\n\n"); 1134 | // wave found 1135 | } 1136 | else 1137 | { 1138 | // wave not found 1139 | } 1140 | } 1141 | return; 1142 | } 1143 | device.setLittlePacketStatus(0); 1144 | } 1145 | } 1146 | } 1147 | 1148 | void Protocol::parseSamplePacket(Sample *packet, int index) 1149 | { 1150 | if (device.getEnabledChannelsCount() == 2) 1151 | { 1152 | lock_guard lock(sampleMutex); 1153 | parseBothChannelsData(packet, index); 1154 | } 1155 | else if (device.isChannelEnabled(CHANNEL_1) && !device.isChannelEnabled(CHANNEL_2)) 1156 | { 1157 | lock_guard lock(sampleMutex); 1158 | parseChannel1Data(packet, index); 1159 | } 1160 | else if (device.isChannelEnabled(CHANNEL_2) && !device.isChannelEnabled(CHANNEL_1)) 1161 | { 1162 | lock_guard lock(sampleMutex); 1163 | parseChannel2Data(packet, index); 1164 | } 1165 | } 1166 | 1167 | void Protocol::parseBothChannelsData(Sample *packet, int index) 1168 | { 1169 | size_t pos = 0; 1170 | 1171 | size_t sampleOffset = index * (IDSO1070::SamplesCountPerPacket / 2); 1172 | 1173 | while ((pos * 2) < IDSO1070::SamplesCountPerPacket) 1174 | { 1175 | 1176 | if (device.getChannelCoupling(CHANNEL_2) == COUPLING_GND) 1177 | { 1178 | sampleBuffer.channel2.push_back(device.getChannelVerticalPosition(CHANNEL_2)); 1179 | } 1180 | else 1181 | { 1182 | sampleBuffer.channel2.push_back((int8_t)(packet->getPayload()[(pos * 2) + 2] & 255)); 1183 | // cout << "Sample2: " << hex << ((uint16_t)(packet->getPayload()[(pos * 2) + 2] & 255)) << endl; 1184 | } 1185 | 1186 | if (device.getChannelCoupling(CHANNEL_1) == COUPLING_GND) 1187 | { 1188 | sampleBuffer.channel1.push_back(device.getChannelVerticalPosition(CHANNEL_1)); 1189 | } 1190 | else 1191 | { 1192 | sampleBuffer.channel1.push_back((int8_t)(packet->getPayload()[(pos * 2) + 1] & 255)); 1193 | cout << "Sample1: " << hex << ((uint16_t)(packet->getPayload()[(pos * 2) + 1] & 255)) << endl; 1194 | 1195 | cout << hexdump(packet->getHeader(), 509, 16) << endl; 1196 | } 1197 | 1198 | // statisticCh1Max(sampleOffset + pos, this.channel1.getSamples()[sampleOffset + pos]); 1199 | // statisticCh1Min(sampleOffset + pos, this.channel1.getSamples()[sampleOffset + pos]); 1200 | // statisticCh2Max(sampleOffset + pos, this.channel2.getSamples()[sampleOffset + pos]); 1201 | // statisticCh2Min(sampleOffset + pos, this.channel2.getSamples()[sampleOffset + pos]); 1202 | pos++; 1203 | } 1204 | } 1205 | 1206 | void Protocol::parseChannel1Data(Sample *packet, int index) 1207 | { 1208 | size_t pos = 0; 1209 | 1210 | size_t sampleOffset = index * IDSO1070::SamplesCountPerPacket; 1211 | while (pos < IDSO1070::SamplesCountPerPacket) 1212 | { 1213 | if (device.getChannelCoupling(CHANNEL_1) == COUPLING_GND) 1214 | { 1215 | sampleBuffer.channel1.push_back(device.getChannelVerticalPosition(CHANNEL_1)); 1216 | } 1217 | else 1218 | { 1219 | sampleBuffer.channel1.push_back((int8_t)(packet->getPayload()[1 + pos] & 255)); 1220 | } 1221 | // statisticCh2Max(sampleOffset + pos, this.channel2.getSamples()[sampleOffset + pos]); 1222 | // statisticCh2Min(sampleOffset + pos, this.channel2.getSamples()[sampleOffset + pos]); 1223 | pos++; 1224 | } 1225 | } 1226 | 1227 | void Protocol::parseChannel2Data(Sample *packet, int index) 1228 | { 1229 | size_t pos = 0; 1230 | 1231 | size_t sampleOffset = index * IDSO1070::SamplesCountPerPacket; 1232 | while (pos < IDSO1070::SamplesCountPerPacket) 1233 | { 1234 | if (device.getChannelCoupling(CHANNEL_2) == COUPLING_GND) 1235 | { 1236 | sampleBuffer.channel2.push_back(device.getChannelVerticalPosition(CHANNEL_2)); 1237 | } 1238 | else 1239 | { 1240 | sampleBuffer.channel2.push_back((int8_t)(packet->getPayload()[1 + pos] & 255)); 1241 | } 1242 | // statisticCh2Max(sampleOffset + pos, this.channel2.getSamples()[sampleOffset + pos]); 1243 | // statisticCh2Min(sampleOffset + pos, this.channel2.getSamples()[sampleOffset + pos]); 1244 | pos++; 1245 | } 1246 | } 1247 | 1248 | void Protocol::interpolateSamples() 1249 | { 1250 | int i = 1; 1251 | // if (!(/* device.getTimeBase() == HDIV_1uS && */ device.getEnabledChannelsCount() == 2)) 1252 | // { 1253 | // i = 0; 1254 | // } 1255 | if (i != 0) 1256 | { 1257 | // IDSO1070Native.lerp_update(this.channel1.getInterpolatedSamples(), this.channel2.getInterpolatedSamples(), this.channel1.getSamples(), this.channel2.getSamples(), this.timeBase.ordinal(), channelStatus(), getTrigger().getTriggerChannel().ordinal(), (int)(getTrigger().getTriggerXPosition() * 100.0d), getTrigger().getTriggerLevel(), getTrigger().getTriggerSlope().ordinal(), IDSO1070::MemoryDepth, this.interpolateType.ordinal()); 1258 | if (device.isChannelEnabled(CHANNEL_1)) 1259 | { 1260 | // System.arraycopy(this.channel1.getInterpolatedSamples(), 0, this.channel1.getSamples(), 0, IDSO1070::MemoryDepth); 1261 | } 1262 | if (device.isChannelEnabled(CHANNEL_2)) 1263 | { 1264 | // System.arraycopy(this.channel2.getInterpolatedSamples(), 0, this.channel2.getSamples(), 0, IDSO1070::MemoryDepth); 1265 | } 1266 | } 1267 | } --------------------------------------------------------------------------------