├── contributors.md ├── tests ├── MakefileFortiq.win ├── Makefile2306pulsing.win ├── Makefile8108speedv007.win ├── Makefile8108SpeedHyperdrive.win ├── MakeFile8108SpeedF1_0_2_0.win ├── fortiq_test.cpp ├── test_api_vertiq8108_speed_F1_0_2_0.cpp └── 2306_pulsing_test.cpp ├── bitbucket-pipelines.yml ├── .gitignore ├── inc ├── crc_helper.h ├── serial_interface_client.hpp ├── adc_interface_client.hpp ├── stopping_handler_client.hpp ├── step_direction_input_client.hpp ├── white_led.hpp ├── pwm_interface_client.hpp ├── servo_input_parser_client.hpp ├── pulsing_rectangular_input_parser_client.hpp ├── rotor_angle_generator_client.hpp ├── voltage_target_generator_client.hpp ├── persistent_memory_client.hpp ├── anticogging_client.hpp ├── throttle_source_manager_client.hpp ├── rgb_led.hpp ├── byte_queue.h ├── client_communication.cpp ├── temperature_monitor_uc_client.hpp ├── mag_alpha_client.hpp ├── temperature_estimator_client.hpp ├── buzzer_control_client.hpp ├── drive_control_interface_client.hpp ├── anticogging_pro_client.hpp ├── hobby_input_client.hpp ├── stow_user_interface_client.hpp ├── communication_interface.h ├── esc_propeller_input_parser_client.hpp ├── gpio_controller_client.hpp ├── generic_interface.hpp ├── uavcan_node_client.hpp ├── power_monitor_client.hpp ├── power_safety_client.hpp ├── iquart_flight_controller_interface_client.hpp ├── motor_model_client.hpp ├── motor_driver_client.hpp ├── arming_handler_client.hpp ├── voltage_superposition_client.hpp ├── propeller_motor_control_client.hpp ├── current_safeties_client.hpp ├── coil_temperature_estimator_client.hpp ├── client_communication.hpp ├── packet_finder.h ├── system_control_client.hpp ├── bipbuffer.h └── multi_turn_angle_control_client.hpp ├── LICENSE ├── CONTRIBUTING.md ├── src ├── crc_helper.c ├── byte_queue.c ├── generic_interface.cpp └── packet_finder.c ├── README.md └── CODE_OF_CONDUCT.md /contributors.md: -------------------------------------------------------------------------------- 1 | # Contributors to this library 2 | 3 | * **Raphael Van Hoffelen** -*work*- Helped set up repo and its architecture 4 | * **Ben Quan** -*work*- Currently maintaining repo 5 | -------------------------------------------------------------------------------- /tests/MakefileFortiq.win: -------------------------------------------------------------------------------- 1 | SRC_FILES=.\fortiq_test.cpp ..\src\generic_interface.cpp ..\src\byte_queue.c ..\src\crc_helper.c ..\src\packet_finder.c 2 | INC_PATH=..\inc 3 | OUT_PATH=fortiq_test.exe 4 | 5 | all: 6 | g++ -I${INC_PATH} -o${OUT_PATH} ${SRC_FILES} 7 | 8 | -------------------------------------------------------------------------------- /tests/Makefile2306pulsing.win: -------------------------------------------------------------------------------- 1 | SRC_FILES=.\2306_pulsing_test.cpp ..\src\generic_interface.cpp ..\src\byte_queue.c ..\src\crc_helper.c ..\src\packet_finder.c 2 | INC_PATH=..\inc 3 | OUT_PATH=2306_pulsing_test.exe 4 | 5 | all: 6 | g++ -I${INC_PATH} -o${OUT_PATH} ${SRC_FILES} -------------------------------------------------------------------------------- /tests/Makefile8108speedv007.win: -------------------------------------------------------------------------------- 1 | SRC_FILES=.\8108_speed_v0_0_7_test.cpp ..\src\generic_interface.cpp ..\src\byte_queue.c ..\src\crc_helper.c ..\src\packet_finder.c 2 | INC_PATH=..\inc 3 | OUT_PATH=8108_speed_v0_0_7_test.exe 4 | 5 | all: 6 | g++ -I${INC_PATH} -o${OUT_PATH} ${SRC_FILES} -------------------------------------------------------------------------------- /tests/Makefile8108SpeedHyperdrive.win: -------------------------------------------------------------------------------- 1 | SRC_FILES=.\8108_speed_hyperdrive_test.cpp ..\src\generic_interface.cpp ..\src\byte_queue.c ..\src\crc_helper.c ..\src\packet_finder.c 2 | INC_PATH=..\inc 3 | OUT_PATH=8108_speed_hyperdrive_test.exe 4 | 5 | all: 6 | g++ -I${INC_PATH} -o${OUT_PATH} ${SRC_FILES} -------------------------------------------------------------------------------- /tests/MakeFile8108SpeedF1_0_2_0.win: -------------------------------------------------------------------------------- 1 | SRC_FILES=.\test_api_vertiq8108_speed_F1_0_2_0.cpp ..\src\generic_interface.cpp ..\src\byte_queue.c ..\src\crc_helper.c ..\src\packet_finder.c 2 | INC_PATH=..\inc 3 | OUT_PATH=8108_speed_F1_0_2_0_test.exe 4 | 5 | all: 6 | g++ -I${INC_PATH} -o${OUT_PATH} ${SRC_FILES} -------------------------------------------------------------------------------- /bitbucket-pipelines.yml: -------------------------------------------------------------------------------- 1 | # This is an example Starter pipeline configuration 2 | # Use a skeleton to build, test and deploy using manual and parallel steps 3 | # ----- 4 | # You can specify a custom docker image from Docker Hub as your build environment. 5 | 6 | image: atlassian/default-image:3 7 | 8 | pipelines: 9 | branches: 10 | master: 11 | - step: 12 | script: 13 | - git remote add sync git@github.com:iq-motion-control/iq-module-communication-cpp.git 14 | - git checkout master 15 | - git pull 16 | - git push sync master --force 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # These are some examples of commonly ignored file patterns. 2 | # You should customize this list as applicable to your project. 3 | # Learn more about .gitignore: 4 | # https://www.atlassian.com/git/tutorials/saving-changes/gitignore 5 | 6 | # Node artifact files 7 | node_modules/ 8 | dist/ 9 | 10 | # Compiled Java class files 11 | *.class 12 | 13 | # Compiled Python bytecode 14 | *.py[cod] 15 | 16 | # Log files 17 | *.log 18 | 19 | # Package files 20 | *.jar 21 | 22 | # Maven 23 | target/ 24 | dist/ 25 | 26 | # JetBrains IDE 27 | .idea/ 28 | 29 | # Unit test reports 30 | TEST*.xml 31 | 32 | # Generated by MacOS 33 | .DS_Store 34 | 35 | # Generated by Windows 36 | Thumbs.db 37 | 38 | # Applications 39 | *.app 40 | *.exe 41 | *.war 42 | 43 | # Large media files 44 | *.mp4 45 | *.tiff 46 | *.avi 47 | *.flv 48 | *.mov 49 | *.wmv 50 | 51 | -------------------------------------------------------------------------------- /inc/crc_helper.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: crc_helper.h 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: James Paulos 13 | Contributors: Matthew Piccoli, Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef CRC_HELPER_H 17 | #define CRC_HELPER_H 18 | 19 | #include 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | /* Compute CRC word for a byte string. 26 | */ 27 | uint16_t MakeCrc(const uint8_t *data, uint16_t count); 28 | 29 | /* Update a CRC accumulation with one data byte. 30 | */ 31 | uint16_t ByteUpdateCrc(uint16_t crc, uint8_t data); 32 | 33 | /* Update a CRC accumulation with several data bytes. 34 | */ 35 | uint16_t ArrayUpdateCrc(uint16_t crc, const uint8_t *data, uint16_t count); 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif // __cplusplus 40 | 41 | #endif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 IQ Motion Control 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. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before making a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | 8 | ## Pull Request Process 9 | 10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a 11 | build. 12 | 2. Increase the version numbers in any example files and the README.md to the new version that this 13 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). Use [shields.io](https://shields.io/category/version) to create the tag. 14 | 4. Add yourself to the contributor.md page explaining your work and adding your github account if you want. 15 | 3. Contact somebody at IQ Motion Control to make sure that your contribution is good (asking for a pull request is fine if you give us your contact information so that we can contact you). 16 | 17 | ## Code of Conduct 18 | 19 | Please read our [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) 20 | 21 | -------------------------------------------------------------------------------- /src/crc_helper.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | /* 9 | Name: crc_helper.c 10 | Last update: 3/7/2019 by Raphael Van Hoffelen 11 | Author: James Paulos 12 | Contributors: Matthew Piccoli, Raphael Van Hoffelen 13 | */ 14 | 15 | #include "crc_helper.h" 16 | 17 | // Compute CRC word for a byte string. 18 | uint16_t MakeCrc(const uint8_t *data, uint16_t count) { 19 | 20 | uint16_t crc = 0xffff; 21 | 22 | uint16_t i; 23 | for(i = 0; i < count; i++) { 24 | crc = ByteUpdateCrc(crc, data[i]); 25 | } 26 | return crc; 27 | } 28 | 29 | // Update a CRC accumulation with one data byte. 30 | uint16_t ByteUpdateCrc(uint16_t crc, uint8_t data) { 31 | 32 | uint16_t x = (crc >> 8) ^ data; 33 | x ^= x >> 4; 34 | 35 | crc = (crc << 8) ^ (x << 12) ^ (x <<5) ^ x; 36 | return crc; 37 | } 38 | 39 | // Update a CRC accumulation with several data bytes. 40 | uint16_t ArrayUpdateCrc(uint16_t crc, const uint8_t *data, uint16_t count) { 41 | 42 | uint16_t i; 43 | for(i = 0; i < count; i++) { 44 | crc = ByteUpdateCrc(crc, data[i]); 45 | } 46 | return crc; 47 | } 48 | -------------------------------------------------------------------------------- /inc/serial_interface_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: serial_interface_client.hpp 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: Matthew Piccoli 13 | Contributors: Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef SERIAL_INTERFACE_CLIENT_H 17 | #define SERIAL_INTERFACE_CLIENT_H 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeSerialInterface = 16; 22 | 23 | class SerialInterfaceClient: public ClientAbstract{ 24 | public: 25 | SerialInterfaceClient(uint8_t obj_idn): 26 | ClientAbstract(kTypeSerialInterface, obj_idn), 27 | baud_rate_( kTypeSerialInterface, obj_idn, kSubBaudRate) 28 | {}; 29 | 30 | // Client Entries 31 | ClientEntry baud_rate_; 32 | 33 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) 34 | { 35 | static const uint8_t kEntryLength = kSubBaudRate+1; 36 | ClientEntryAbstract* entry_array[kEntryLength] = { 37 | &baud_rate_, // 0 38 | }; 39 | 40 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 41 | } 42 | 43 | private: 44 | static const uint8_t kSubBaudRate = 0; 45 | }; 46 | 47 | #endif // SERIAL_INTERFACE_CLIENT_H 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![tag](https://img.shields.io/github/v/tag/iq-motion-control/iq-module-communication-cpp) 2 | ![release](https://img.shields.io/github/release/iq-motion-control/iq-module-communication-cpp/all.svg) 3 | 4 | # C++ API 5 | 6 | This is the library to control a IQ Motion Control Module with C++ 7 | 8 | ## Getting Started 9 | 10 | Add this library to your C++ project to interface with the motors. 11 | Read the programming [documentation](http://iq-control.com/support) on our website to learn how to use this library. 12 | Use our [release page](https://github.com/iq-motion-control/iq-module-communication-cpp/releases) to make sure you are using the latest version 13 | 14 | ### Prerequisites 15 | 16 | You will need C++11 to run this library 17 | 18 | ## Contributing 19 | 20 | Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us. 21 | 22 | ## Versioning 23 | 24 | We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/iq-motion-control/iq-module-communication-cpp/tags). 25 | For the releases available, see the [releases on this repository](https://github.com/iq-motion-control/iq-module-communication-cpp/releases). 26 | 27 | ## Authors 28 | 29 | * **Matthew piccoli** 30 | 31 | See also the list of [contributors](contributors.md) who participated in this project. 32 | 33 | ## License 34 | 35 | This project is licensed under the MIT license - see the [LICENSE.md](LICENSE) file for details 36 | -------------------------------------------------------------------------------- /inc/adc_interface_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: adc_interface_client.hpp 11 | Last update: 2023/04/18 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef ADC_INTERFACE_CLIENT_HPP_ 17 | #define ADC_INTERFACE_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeAdcInterface = 91; 22 | 23 | class AdcInterfaceClient : public ClientAbstract { 24 | public: 25 | AdcInterfaceClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeAdcInterface, obj_idn), 27 | adc_voltage_(kTypeAdcInterface, obj_idn, kSubAdcVoltage), 28 | raw_value_(kTypeAdcInterface, obj_idn, kSubRawValue){}; 29 | 30 | // Client Entries 31 | ClientEntry adc_voltage_; 32 | ClientEntry raw_value_; 33 | 34 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 35 | static const uint8_t kEntryLength = kSubRawValue + 1; 36 | ClientEntryAbstract* entry_array[kEntryLength] = { 37 | &adc_voltage_, // 0 38 | &raw_value_ // 1 39 | }; 40 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 41 | } 42 | 43 | private: 44 | static const uint8_t kSubAdcVoltage = 0; 45 | static const uint8_t kSubRawValue = 1; 46 | }; 47 | 48 | #endif /* ADC_INTERFACE_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/stopping_handler_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: stopping_handler_client.hpp 11 | Last update: 2023/04/12 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef STOPPING_HANDLER_CLIENT_HPP_ 17 | #define STOPPING_HANDLER_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeStoppingHandler = 87; 22 | 23 | class StoppingHandlerClient : public ClientAbstract { 24 | public: 25 | StoppingHandlerClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeStoppingHandler, obj_idn), 27 | stopped_speed_(kTypeStoppingHandler, obj_idn, kSubStoppedSpeed), 28 | stopped_time_(kTypeStoppingHandler, obj_idn, kSubStoppedTime){}; 29 | 30 | // Client Entries 31 | ClientEntry stopped_speed_; 32 | ClientEntry stopped_time_; 33 | 34 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 35 | static const uint8_t kEntryLength = kSubStoppedTime + 1; 36 | ClientEntryAbstract* entry_array[kEntryLength] = { 37 | &stopped_speed_, // 0 38 | &stopped_time_ // 1 39 | }; 40 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 41 | } 42 | 43 | private: 44 | static const uint8_t kSubStoppedSpeed = 0; 45 | static const uint8_t kSubStoppedTime = 1; 46 | }; 47 | 48 | #endif /* STOPPING_HANDLER_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/step_direction_input_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: step_direction_input_client.hpp 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: Matthew Piccoli 13 | Contributors: Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef STEP_DIRECTION_INPUT_CLIENT_HPP_ 17 | #define STEP_DIRECTION_INPUT_CLIENT_HPP_ 18 | 19 | 20 | #include "client_communication.hpp" 21 | 22 | const uint8_t kTypeStepDirInput = 58; 23 | 24 | class StepDirectionInputClient: public ClientAbstract{ 25 | public: 26 | StepDirectionInputClient(uint8_t obj_idn): 27 | ClientAbstract( kTypeStepDirInput, obj_idn), 28 | angle_( kTypeStepDirInput, obj_idn, kSubAngle), 29 | angle_step_( kTypeStepDirInput, obj_idn, kSubAngleStep) 30 | {}; 31 | 32 | // Client Entries 33 | ClientEntry angle_; 34 | ClientEntry angle_step_; 35 | 36 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) 37 | { 38 | static const uint8_t kEntryLength = kSubAngleStep+1; 39 | ClientEntryAbstract* entry_array[kEntryLength] = { 40 | &angle_, // 0 41 | &angle_step_ // 1 42 | }; 43 | 44 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 45 | } 46 | 47 | private: 48 | static const uint8_t kSubAngle = 0; 49 | static const uint8_t kSubAngleStep = 1; 50 | }; 51 | 52 | #endif /* STEP_DIRECTION_INPUT_CLIENT_HPP_ */ 53 | -------------------------------------------------------------------------------- /inc/white_led.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the Vertiq C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | #ifndef WHITE_LED_CLIENT_H 10 | #define WHITE_LED_CLIENT_H 11 | 12 | #include "client_communication.hpp" 13 | 14 | const uint8_t kTypeWhiteLed = 101; 15 | 16 | class WhiteLedClient : public ClientAbstract { 17 | public: 18 | WhiteLedClient(uint8_t obj_idn) 19 | : ClientAbstract(kTypeWhiteLed, obj_idn), 20 | intensity_(kTypeWhiteLed, obj_idn, kSubIntensity), 21 | strobe_active_(kTypeWhiteLed, obj_idn, kSubStrobeActive), 22 | strobe_period_(kTypeWhiteLed, obj_idn, kSubStrobePeriod), 23 | strobe_pattern_(kTypeWhiteLed, obj_idn, kSubStrobePattern){}; 24 | 25 | // Client Entries 26 | ClientEntry intensity_; 27 | ClientEntry strobe_active_; 28 | ClientEntry strobe_period_; 29 | ClientEntry strobe_pattern_; 30 | 31 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 32 | static const uint8_t kEntryLength = kSubStrobePattern + 1; 33 | ClientEntryAbstract* entry_array[kEntryLength] = { 34 | &intensity_, // 0 35 | &strobe_active_, // 1 36 | &strobe_period_, // 2 37 | &strobe_pattern_ // 3 38 | }; 39 | 40 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 41 | } 42 | 43 | private: 44 | static const uint8_t kSubIntensity = 0; 45 | static const uint8_t kSubStrobeActive = 1; 46 | static const uint8_t kSubStrobePeriod = 2; 47 | static const uint8_t kSubStrobePattern = 3; 48 | 49 | }; 50 | 51 | #endif // WHITE_LED_CLIENT_H 52 | -------------------------------------------------------------------------------- /inc/pwm_interface_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: pwm_interface_client.hpp 11 | Last update: 2023/04/18 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef PWM_INTERFACE_CLIENT_HPP_ 17 | #define PWM_INTERFACE_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypePwmInterface = 92; 22 | 23 | class PwmInterfaceClient : public ClientAbstract { 24 | public: 25 | PwmInterfaceClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypePwmInterface, obj_idn), 27 | pwm_frequency_(kTypePwmInterface, obj_idn, kSubPwmFrequency), 28 | duty_cycle_(kTypePwmInterface, obj_idn, kSubDutyCycle), 29 | pwm_mode_(kTypePwmInterface, obj_idn, kSubPwmMode){}; 30 | 31 | // Client Entries 32 | ClientEntry pwm_frequency_; 33 | ClientEntry duty_cycle_; 34 | ClientEntry pwm_mode_; 35 | 36 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 37 | static const uint8_t kEntryLength = kSubPwmMode + 1; 38 | ClientEntryAbstract* entry_array[kEntryLength] = { 39 | &pwm_frequency_, // 0 40 | &duty_cycle_, // 1 41 | &pwm_mode_ // 2 42 | }; 43 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 44 | } 45 | 46 | private: 47 | static const uint8_t kSubPwmFrequency = 0; 48 | static const uint8_t kSubDutyCycle = 1; 49 | static const uint8_t kSubPwmMode = 2; 50 | }; 51 | 52 | #endif /* PWM_INTERFACE_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/servo_input_parser_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: servo_input_parser_client.hpp 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: Matthew Piccoli 13 | Contributors: Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef SERVO_INPUT_PARSER_CLIENT_HPP_ 17 | #define SERVO_INPUT_PARSER_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeServoInputParser = 78; 22 | 23 | class ServoInputParserClient: public ClientAbstract{ 24 | public: 25 | ServoInputParserClient(uint8_t obj_idn): 26 | ClientAbstract( kTypeServoInputParser, obj_idn), 27 | mode_( kTypeServoInputParser, obj_idn, kSubMode), 28 | unit_min_( kTypeServoInputParser, obj_idn, kSubUnitMin), 29 | unit_max_( kTypeServoInputParser, obj_idn, kSubUnitMax) 30 | {}; 31 | 32 | // Client Entries 33 | // Control commands 34 | ClientEntry mode_; 35 | ClientEntry unit_min_; 36 | ClientEntry unit_max_; 37 | 38 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) 39 | { 40 | static const uint8_t kEntryLength = kSubUnitMax+1; 41 | ClientEntryAbstract* entry_array[kEntryLength] = { 42 | &mode_, // 0 43 | &unit_min_, // 1 44 | &unit_max_ // 2 45 | }; 46 | 47 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 48 | } 49 | 50 | private: 51 | static const uint8_t kSubMode = 0; 52 | static const uint8_t kSubUnitMin = 1; 53 | static const uint8_t kSubUnitMax = 2; 54 | }; 55 | 56 | #endif /* SERVO_INPUT_PARSER_CLIENT_HPP_ */ 57 | -------------------------------------------------------------------------------- /inc/pulsing_rectangular_input_parser_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: pulsing_rectangular_input_parser_client.hpp 11 | Last update: 2024/08/26 by Fred Kummer 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef PULSING_RECTANGULAR_INPUT_PARSER_CLIENT_HPP_ 17 | #define PULSING_RECTANGULAR_INPUT_PARSER_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypePulsingRectangularInputParser = 89; 22 | 23 | class PulsingRectangularInputParserClient : public ClientAbstract { 24 | public: 25 | PulsingRectangularInputParserClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypePulsingRectangularInputParser, obj_idn), 27 | pulsing_scaling_mode_(kTypePulsingRectangularInputParser, obj_idn, kSubPulsingScalingMode), 28 | pulsing_scaling_limit_(kTypePulsingRectangularInputParser, obj_idn, kSubPulsingScalingLimit){}; 29 | 30 | // Client Entries 31 | ClientEntry pulsing_scaling_mode_; 32 | ClientEntry pulsing_scaling_limit_; 33 | 34 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 35 | static const uint8_t kEntryLength = kSubPulsingScalingLimit + 1; 36 | ClientEntryAbstract* entry_array[kEntryLength] = { 37 | &pulsing_scaling_mode_, // 0 38 | &pulsing_scaling_limit_ // 1 39 | }; 40 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 41 | } 42 | 43 | private: 44 | static const uint8_t kSubPulsingScalingMode = 0; 45 | static const uint8_t kSubPulsingScalingLimit = 1; 46 | }; 47 | 48 | #endif /* PULSING_RECTANGULAR_INPUT_PARSER_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/rotor_angle_generator_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: rotor_angle_generator_client.hpp 11 | Last update: 2025-03-11 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef ROTOR_ANGLE_GENERATOR_CLIENT_HPP_ 17 | #define ROTOR_ANGLE_GENERATOR_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeRotorAngleGenerator = 95; 22 | 23 | class RotorAngleGeneratorClient : public ClientAbstract { 24 | public: 25 | RotorAngleGeneratorClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeRotorAngleGenerator, obj_idn), 27 | rotor_angle_(kTypeRotorAngleGenerator, obj_idn, kSubRotorAngle), 28 | manual_angle_(kTypeRotorAngleGenerator, obj_idn, kSubManualAngle), 29 | use_manual_angle_(kTypeRotorAngleGenerator, obj_idn, kSubUseManualAngle) 30 | {}; 31 | 32 | // Client Entries 33 | ClientEntry rotor_angle_; 34 | ClientEntry manual_angle_; 35 | ClientEntry use_manual_angle_; 36 | 37 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 38 | static const uint8_t kEntryLength = kSubUseManualAngle + 1; 39 | ClientEntryAbstract* entry_array[kEntryLength] = { 40 | &rotor_angle_, // 0 41 | &manual_angle_, // 1 42 | &use_manual_angle_, // 2 43 | }; 44 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 45 | } 46 | 47 | private: 48 | static const uint8_t kSubRotorAngle = 0; 49 | static const uint8_t kSubManualAngle = 1; 50 | static const uint8_t kSubUseManualAngle = 2; 51 | 52 | }; 53 | 54 | #endif /* ROTOR_ANGLE_GENERATOR_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/voltage_target_generator_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: voltage_target_generator_client.hpp 11 | Last update: 2025-03-11 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef VOLTAGE_TARGET_GENERATOR_CLIENT_HPP_ 17 | #define VOLTAGE_TARGET_GENERATOR_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeVoltageTargetGenerator = 94; 22 | 23 | class VoltageTargetGeneratorClient : public ClientAbstract { 24 | public: 25 | VoltageTargetGeneratorClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeVoltageTargetGenerator, obj_idn), 27 | q_current_(kTypeVoltageTargetGenerator, obj_idn, kSubQCurrent), 28 | d_current_(kTypeVoltageTargetGenerator, obj_idn, kSubDCurrent), 29 | q_voltage_(kTypeVoltageTargetGenerator, obj_idn, kSubQVoltage), 30 | d_voltage_(kTypeVoltageTargetGenerator, obj_idn, kSubDVoltage) 31 | {}; 32 | 33 | // Client Entries 34 | ClientEntry q_current_; 35 | ClientEntry d_current_; 36 | ClientEntry q_voltage_; 37 | ClientEntry d_voltage_; 38 | 39 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 40 | static const uint8_t kEntryLength = kSubDVoltage + 1; 41 | ClientEntryAbstract* entry_array[kEntryLength] = { 42 | &q_current_, // 0 43 | &d_current_, // 1 44 | &q_voltage_, // 2 45 | &d_voltage_, // 3 46 | }; 47 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 48 | } 49 | 50 | private: 51 | static const uint8_t kSubQCurrent = 0; 52 | static const uint8_t kSubDCurrent = 1; 53 | static const uint8_t kSubQVoltage = 2; 54 | static const uint8_t kSubDVoltage = 3; 55 | 56 | }; 57 | 58 | #endif /* VOLTAGE_TARGET_GENERATOR_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/persistent_memory_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: persistent_memory_client.hpp 11 | Last update: 10/31/2022 by Ben Quan 12 | Author: Matthew Piccoli 13 | Contributors: Ben Quan, Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef PERSISTENT_MEMORY_CLIENT_HPP_ 17 | #define PERSISTENT_MEMORY_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypePersistentMemory = 11; 22 | 23 | class PersistentMemoryClient: public ClientAbstract{ 24 | public: 25 | PersistentMemoryClient(uint8_t obj_idn): 26 | ClientAbstract( kTypePersistentMemory, obj_idn), 27 | erase_( kTypePersistentMemory, obj_idn, kSubErase), 28 | revert_to_default_( kTypePersistentMemory, obj_idn, kSubRevertToDefault), 29 | format_key_1_( kTypePersistentMemory, obj_idn, kSubFormatKey1), 30 | format_key_2_( kTypePersistentMemory, obj_idn, kSubFormatKey2) 31 | {}; 32 | 33 | // Client Entries 34 | // Control commands 35 | ClientEntryVoid erase_; 36 | ClientEntryVoid revert_to_default_; 37 | ClientEntry format_key_1_; 38 | ClientEntry format_key_2_; 39 | 40 | 41 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) 42 | { 43 | static const uint8_t kEntryLength = kSubFormatKey2+1; 44 | ClientEntryAbstract* entry_array[kEntryLength] = { 45 | &erase_, // 0 46 | &revert_to_default_, // 1 47 | &format_key_1_, // 2 48 | &format_key_2_ // 3 49 | }; 50 | 51 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 52 | } 53 | 54 | private: 55 | static const uint8_t kSubErase = 0; 56 | static const uint8_t kSubRevertToDefault = 1; 57 | static const uint8_t kSubFormatKey1 = 2; 58 | static const uint8_t kSubFormatKey2 = 3; 59 | }; 60 | 61 | #endif /* PERSISTENT_MEMORY_CLIENT_HPP_ */ 62 | -------------------------------------------------------------------------------- /inc/anticogging_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: anticogging_client.hpp 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: Matthew Piccoli 13 | Contributors: Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef ANTICOGGING_CLIENT_H 17 | #define ANTICOGGING_CLIENT_H 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeAnticogging = 71; 22 | 23 | class AnticoggingClient: public ClientAbstract{ 24 | public: 25 | AnticoggingClient(uint8_t obj_idn): 26 | ClientAbstract( kTypeAnticogging, obj_idn), 27 | table_size_( kTypeAnticogging, obj_idn, kSubTableSize), 28 | is_data_valid_( kTypeAnticogging, obj_idn, kSubIsDataValid), 29 | is_enabled_( kTypeAnticogging, obj_idn, kSubIsEnabled), 30 | erase_( kTypeAnticogging, obj_idn, kSubErase), 31 | left_shift_( kTypeAnticogging, obj_idn, kSubLeftShift) 32 | {}; 33 | 34 | // Client Entries 35 | ClientEntry table_size_; 36 | ClientEntry is_data_valid_; 37 | ClientEntry is_enabled_; 38 | ClientEntryVoid erase_; 39 | ClientEntry left_shift_; 40 | 41 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) 42 | { 43 | static const uint8_t kEntryLength = kSubLeftShift+1; 44 | ClientEntryAbstract* entry_array[kEntryLength] = { 45 | &table_size_, // 0 46 | &is_data_valid_, // 1 47 | &is_enabled_, // 2 48 | &erase_, // 3 49 | &left_shift_ // 4 50 | }; 51 | 52 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 53 | } 54 | 55 | private: 56 | static const uint8_t kSubTableSize = 0; 57 | static const uint8_t kSubIsDataValid = 1; 58 | static const uint8_t kSubIsEnabled = 2; 59 | static const uint8_t kSubErase = 3; 60 | static const uint8_t kSubLeftShift = 4; 61 | }; 62 | 63 | #endif // ANTICOGGING_CLIENT_H 64 | -------------------------------------------------------------------------------- /inc/throttle_source_manager_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: throttle_source_manager_client.hpp 11 | Last update: 2024/01/30 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef THROTTLE_SOURCE_MANAGER_CLIENT_HPP_ 17 | #define THROTTLE_SOURCE_MANAGER_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeThrottleSourceManager = 104; 22 | 23 | class ThrottleSourceManagerClient : public ClientAbstract { 24 | public: 25 | ThrottleSourceManagerClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeThrottleSourceManager, obj_idn), 27 | throttle_timeout_(kTypeThrottleSourceManager, obj_idn, kSubThrottleTimeout), 28 | dronecan_priority_(kTypeThrottleSourceManager, obj_idn, kSubDronecanPriority), 29 | hobby_priority_(kTypeThrottleSourceManager, obj_idn, kSubHobbyPriority), 30 | iquart_priority_(kTypeThrottleSourceManager, obj_idn, kSubIquartPriority) 31 | {}; 32 | 33 | // Client Entries 34 | ClientEntry throttle_timeout_; 35 | ClientEntry dronecan_priority_; 36 | ClientEntry hobby_priority_; 37 | ClientEntry iquart_priority_; 38 | 39 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 40 | static const uint8_t kEntryLength = kSubIquartPriority + 1; 41 | ClientEntryAbstract* entry_array[kEntryLength] = { 42 | &throttle_timeout_, // 0 43 | &dronecan_priority_, // 1 44 | &hobby_priority_, // 2 45 | &iquart_priority_, // 3 46 | }; 47 | 48 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 49 | } 50 | 51 | private: 52 | static const uint8_t kSubThrottleTimeout = 0; 53 | static const uint8_t kSubDronecanPriority = 1; 54 | static const uint8_t kSubHobbyPriority = 2; 55 | static const uint8_t kSubIquartPriority = 3; 56 | }; 57 | 58 | #endif /* THROTTLE_SOURCE_MANAGER_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/rgb_led.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the Vertiq C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | #ifndef RGB_LED_CLIENT_H 10 | #define RGB_LED_CLIENT_H 11 | 12 | #include "client_communication.hpp" 13 | 14 | const uint8_t kTypeRgbLed = 100; 15 | 16 | class RgbLedClient : public ClientAbstract { 17 | public: 18 | RgbLedClient(uint8_t obj_idn) 19 | : ClientAbstract(kTypeRgbLed, obj_idn), 20 | red_(kTypeRgbLed, obj_idn, kSubRed), 21 | green_(kTypeRgbLed, obj_idn, kSubGreen), 22 | blue_(kTypeRgbLed, obj_idn, kSubBlue), 23 | update_color_(kTypeRgbLed, obj_idn, kSubUpdateColor), 24 | strobe_active_(kTypeRgbLed, obj_idn, kSubStrobeActive), 25 | strobe_period_(kTypeRgbLed, obj_idn, kSubStrobePeriod), 26 | strobe_pattern_(kTypeRgbLed, obj_idn, kSubStrobePattern){}; 27 | 28 | // Client Entries 29 | ClientEntry red_; 30 | ClientEntry green_; 31 | ClientEntry blue_; 32 | ClientEntryVoid update_color_; 33 | ClientEntry strobe_active_; 34 | ClientEntry strobe_period_; 35 | ClientEntry strobe_pattern_; 36 | 37 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 38 | static const uint8_t kEntryLength = kSubStrobePattern + 1; 39 | ClientEntryAbstract* entry_array[kEntryLength] = { 40 | &red_, // 0 41 | &green_, // 1 42 | &blue_, // 2 43 | &update_color_, // 3 44 | &strobe_active_, // 4 45 | &strobe_period_, // 5 46 | &strobe_pattern_ // 6 47 | }; 48 | 49 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 50 | } 51 | 52 | private: 53 | static const uint8_t kSubRed = 0; 54 | static const uint8_t kSubGreen = 1; 55 | static const uint8_t kSubBlue = 2; 56 | static const uint8_t kSubUpdateColor = 3; 57 | static const uint8_t kSubStrobeActive = 4; 58 | static const uint8_t kSubStrobePeriod = 5; 59 | static const uint8_t kSubStrobePattern = 6; 60 | 61 | }; 62 | 63 | #endif // RGB_LED_CLIENT_H 64 | -------------------------------------------------------------------------------- /inc/byte_queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: byte_queue.h 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: James Paulos 13 | Contributors: Matthew Piccoli, Raphael Van Hoffelen 14 | */ 15 | 16 | /* A FIFO buffer for uint8 bytes implemented with a fixed size circular 17 | * buffer. A ByteQueue struct maintains the buffer data and state for one 18 | * buffer instance, and many simultaneous instances are supported. An operation 19 | * on one buffer must not be interrupted by another operation on that same 20 | * buffer (possibly via an interrupt). This restriction is not enforced and no 21 | * error code is generated. 22 | */ 23 | 24 | #ifndef BYTE_QUEUE_H 25 | #define BYTE_QUEUE_H 26 | 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /// ByteQueue instance state struct, voluntarily opaque. 34 | struct ByteQueue { 35 | uint8_t* data; // pointer to array allocated for data 36 | uint8_t *start; // points to first data byte 37 | uint8_t *end; // points to empty byte past last data byte 38 | uint16_t data_size; // size allocated for data 39 | uint16_t count; // current contained element count 40 | }; 41 | 42 | // initialize buffer as empty 43 | // must provide pointer to allocated array for buffer to use 44 | void InitBQ(struct ByteQueue *b, uint8_t* data, uint16_t data_size); 45 | 46 | // return 1 if buffer full, 0 else 47 | int8_t IsFullBQ(struct ByteQueue *b); 48 | 49 | // return 1 if buffer empty, 0 else 50 | int8_t IsEmptyBQ(struct ByteQueue *b); 51 | 52 | // return number elements in buffer 53 | uint16_t CountBQ(struct ByteQueue *p); 54 | 55 | // read and remove next character from buffer 56 | uint8_t GetByteBQ(struct ByteQueue *b); 57 | 58 | // read but don't remove next character from buffer 59 | uint8_t PeekByteBQ(struct ByteQueue *b); 60 | 61 | // add one character to buffer 62 | // return 1 for success, 0 for failure (buffer overflow) 63 | int8_t PutByteBQ(struct ByteQueue *b, uint8_t item); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif // __cplusplus 68 | 69 | #endif // BYTE_QUEUE_H 70 | -------------------------------------------------------------------------------- /inc/client_communication.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: client_communication.cpp 11 | Last update: 4/12/2019 by Matthew Piccoli 12 | Author: Matthew Piccoli 13 | Contributors: Raphael Van Hoffelen 14 | */ 15 | 16 | #include "client_communication.hpp" 17 | 18 | int8_t ParseMsg(uint8_t* rx_data, uint8_t rx_length, 19 | ClientEntryAbstract** entry_array, uint8_t entry_length) 20 | { 21 | uint8_t type_idn = rx_data[0]; 22 | uint8_t sub_idn = rx_data[1]; 23 | uint8_t obj_idn = rx_data[2] >> 2; // high 6 bits are obj_idn 24 | Access dir = static_cast(rx_data[2] & 0b00000011); // low two bits 25 | 26 | // if we have a reply (we only parse replies here) 27 | if(dir == kReply) 28 | { 29 | // if sub_idn is within array range (safe to access array at this location) 30 | if(sub_idn < entry_length) 31 | { 32 | // if there is a ClientEntry object at this sub_idn 33 | if(entry_array[sub_idn] != nullptr) 34 | { 35 | // if the type and obj identifiers match 36 | if(entry_array[sub_idn]->type_idn_ == type_idn && 37 | entry_array[sub_idn]->obj_idn_ == obj_idn) 38 | { 39 | // ... then we have a valid message 40 | entry_array[sub_idn]->Reply(&rx_data[3],rx_length-3); 41 | return 1; // I parsed something 42 | } 43 | } 44 | } 45 | } 46 | return 0; // I didn't parse anything 47 | } 48 | 49 | int8_t ParseMsg(uint8_t* rx_data, uint8_t rx_length, 50 | ClientEntryAbstract& entry) 51 | { 52 | uint8_t type_idn = rx_data[0]; 53 | uint8_t sub_idn = rx_data[1]; 54 | uint8_t obj_idn = rx_data[2] >> 2; // high 6 bits are obj_idn 55 | Access dir = static_cast(rx_data[2] & 0b00000011); // low two bits 56 | 57 | // if we have a reply (we only parse replies here) 58 | if(dir == kReply) 59 | { 60 | // if the type and obj identifiers match 61 | if(entry.type_idn_ == type_idn && 62 | entry.obj_idn_ == obj_idn && entry.sub_idn_ == sub_idn) 63 | { 64 | // ... then we have a valid message 65 | entry.Reply(&rx_data[3],rx_length-3); 66 | return 1; // I parsed something 67 | } 68 | } 69 | return 0; // I didn't parse anything 70 | } -------------------------------------------------------------------------------- /inc/temperature_monitor_uc_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: temperature_monitor_uc_client.hpp 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: Matthew Piccoli 13 | Contributors: Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef TEMPERATURE_MONITOR_UC_CLIENT_HPP_ 17 | #define TEMPERATURE_MONITOR_UC_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeTemperatureMonitorUcClient = 73; 22 | 23 | class TemperatureMonitorUcClient: public ClientAbstract{ 24 | public: 25 | TemperatureMonitorUcClient(uint8_t obj_idn): 26 | ClientAbstract( kTypeTemperatureMonitorUcClient, obj_idn), 27 | uc_temp_( kTypeTemperatureMonitorUcClient, obj_idn, kSubUcTemp), 28 | filter_fs_( kTypeTemperatureMonitorUcClient, obj_idn, kSubFilterFs), 29 | filter_fc_( kTypeTemperatureMonitorUcClient, obj_idn, kSubFilterFc), 30 | otw_( kTypeTemperatureMonitorUcClient, obj_idn, kSubOtw), 31 | otlo_( kTypeTemperatureMonitorUcClient, obj_idn, kSubOtlo), 32 | derate_( kTypeTemperatureMonitorUcClient, obj_idn, kSubDerate) 33 | {}; 34 | 35 | // Client Entries 36 | // Control commands 37 | ClientEntry uc_temp_; 38 | ClientEntry filter_fs_; 39 | ClientEntry filter_fc_; 40 | ClientEntry otw_; 41 | ClientEntry otlo_; 42 | ClientEntry derate_; 43 | 44 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) 45 | { 46 | static const uint8_t kEntryLength = kSubDerate+1; 47 | ClientEntryAbstract* entry_array[kEntryLength] = { 48 | &uc_temp_, // 0 49 | &filter_fs_, // 1 50 | &filter_fc_, // 2 51 | &otw_, // 3 52 | &otlo_, // 4 53 | &derate_ // 5 54 | }; 55 | 56 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 57 | } 58 | 59 | private: 60 | static const uint8_t kSubUcTemp = 0; 61 | static const uint8_t kSubFilterFs = 1; 62 | static const uint8_t kSubFilterFc = 2; 63 | static const uint8_t kSubOtw = 3; 64 | static const uint8_t kSubOtlo = 4; 65 | static const uint8_t kSubDerate = 5; 66 | }; 67 | 68 | #endif /* TEMPERATURE_MONITOR_UC_CLIENT_HPP_ */ 69 | -------------------------------------------------------------------------------- /inc/mag_alpha_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 Vertiq support@vertiq.co 3 | 4 | This file is part of the Vertiq C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: mag_alpha_client.hpp 11 | Last update: 2023/06/29 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef MAG_ALPHA_CLIENT_HPP 17 | #define MAG_ALPHA_CLIENT_HPP 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeMagAlpha = 75; 22 | 23 | class MagAlphaClient: public ClientAbstract{ 24 | public: 25 | MagAlphaClient(uint8_t obj_idn): 26 | ClientAbstract( kTypeMagAlpha, obj_idn), 27 | angle_raw_(kTypeMagAlpha, obj_idn, kSubAngleRaw), 28 | angle_rad_(kTypeMagAlpha, obj_idn, kSubAngleRad), 29 | alarm_(kTypeMagAlpha, obj_idn, kSubAlarm), 30 | mght_(kTypeMagAlpha, obj_idn, kSubMght), 31 | mglt_(kTypeMagAlpha, obj_idn, kSubMglt), 32 | reg_val_(kTypeMagAlpha, obj_idn, kSubRegVal), 33 | reg_adr_(kTypeMagAlpha, obj_idn, kSubRegAdr), 34 | reg_str_(kTypeMagAlpha, obj_idn, kSubRegStr) 35 | {}; 36 | 37 | // Client Entries 38 | ClientEntry angle_raw_; 39 | ClientEntry angle_rad_; 40 | ClientEntry alarm_; 41 | ClientEntry mght_; 42 | ClientEntry mglt_; 43 | ClientEntry reg_val_; 44 | ClientEntry reg_adr_; 45 | ClientEntryVoid reg_str_; 46 | 47 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) 48 | { 49 | static const uint8_t kEntryLength = kSubRegStr+1; 50 | ClientEntryAbstract* entry_array[kEntryLength] = { 51 | &angle_raw_, // 0 52 | &angle_rad_, // 1 53 | &alarm_, // 2 54 | &mght_, // 3 55 | &mglt_, // 4 56 | ®_val_, // 5 57 | ®_adr_, // 6 58 | ®_str_ // 7 59 | }; 60 | 61 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 62 | } 63 | 64 | private: 65 | static const uint8_t kSubAngleRaw = 0; 66 | static const uint8_t kSubAngleRad = 1; 67 | static const uint8_t kSubAlarm = 2; 68 | static const uint8_t kSubMght = 3; 69 | static const uint8_t kSubMglt = 4; 70 | static const uint8_t kSubRegVal = 5; 71 | static const uint8_t kSubRegAdr = 6; 72 | static const uint8_t kSubRegStr = 7; 73 | }; 74 | 75 | #endif // MAG_ALPHA_CLIENT_H -------------------------------------------------------------------------------- /inc/temperature_estimator_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: temperature_estimator_client.hpp 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: Matthew Piccoli 13 | Contributors: Raphael Van Hoffelen 14 | */ 15 | 16 | 17 | #ifndef TEMPERATURE_ESTIMATOR_CLIENT_HPP_ 18 | #define TEMPERATURE_ESTIMATOR_CLIENT_HPP_ 19 | 20 | #include "client_communication.hpp" 21 | 22 | const uint8_t kTypeTemperatureEstimatorClient = 77; 23 | 24 | class TemperatureEstimatorClient: public ClientAbstract{ 25 | public: 26 | TemperatureEstimatorClient(uint8_t obj_idn): 27 | ClientAbstract( kTypeTemperatureEstimatorClient, obj_idn), 28 | temp_( kTypeTemperatureEstimatorClient, obj_idn, kSubTemp), 29 | otw_( kTypeTemperatureEstimatorClient, obj_idn, kSubOtw), 30 | otlo_( kTypeTemperatureEstimatorClient, obj_idn, kSubOtlo), 31 | thermal_resistance_( kTypeTemperatureEstimatorClient, obj_idn, kSubThermalResistance), 32 | thermal_capacitance_( kTypeTemperatureEstimatorClient, obj_idn, kSubThermalCapacitance), 33 | derate_( kTypeTemperatureEstimatorClient, obj_idn, kSubDerate) 34 | {}; 35 | 36 | // Client Entries 37 | // Control commands 38 | ClientEntry temp_; 39 | ClientEntry otw_; 40 | ClientEntry otlo_; 41 | ClientEntry thermal_resistance_; 42 | ClientEntry thermal_capacitance_; 43 | ClientEntry derate_; 44 | 45 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) 46 | { 47 | static const uint8_t kEntryLength = kSubDerate+1; 48 | ClientEntryAbstract* entry_array[kEntryLength] = { 49 | &temp_, // 0 50 | &otw_, // 1 51 | &otlo_, // 2 52 | &thermal_resistance_, // 3 53 | &thermal_capacitance_,// 4 54 | &derate_ // 5 55 | }; 56 | 57 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 58 | } 59 | 60 | private: 61 | static const uint8_t kSubTemp = 0; 62 | static const uint8_t kSubOtw = 1; 63 | static const uint8_t kSubOtlo = 2; 64 | static const uint8_t kSubThermalResistance = 3; 65 | static const uint8_t kSubThermalCapacitance = 4; 66 | static const uint8_t kSubDerate = 5; 67 | }; 68 | 69 | #endif /* TEMPERATURE_ESTIMATOR_CLIENT_HPP_ */ 70 | -------------------------------------------------------------------------------- /inc/buzzer_control_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: buzzer_control_client.hpp 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: Matthew Piccoli 13 | Contributors: Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef BUZZER_CONTROL_CLIENT_H 17 | #define BUZZER_CONTROL_CLIENT_H 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeBuzzerControl = 61; 22 | 23 | class BuzzerControlClient: public ClientAbstract{ 24 | public: 25 | BuzzerControlClient(uint8_t obj_idn): 26 | ClientAbstract( kTypeBuzzerControl, obj_idn), 27 | ctrl_mode_( kTypeBuzzerControl, obj_idn, kSubCtrlMode), 28 | ctrl_brake_( kTypeBuzzerControl, obj_idn, kSubCtrlBrake), 29 | ctrl_coast_( kTypeBuzzerControl, obj_idn, kSubCtrlCoast), 30 | ctrl_note_( kTypeBuzzerControl, obj_idn, kSubCtrlNote), 31 | volume_max_( kTypeBuzzerControl, obj_idn, kSubVolumeMax), 32 | hz_( kTypeBuzzerControl, obj_idn, kSubHz), 33 | volume_( kTypeBuzzerControl, obj_idn, kSubVolume), 34 | duration_( kTypeBuzzerControl, obj_idn, kSubDuration) 35 | {}; 36 | 37 | // Client Entries 38 | ClientEntryVoid ctrl_mode_; 39 | ClientEntryVoid ctrl_brake_; 40 | ClientEntryVoid ctrl_coast_; 41 | ClientEntryVoid ctrl_note_; 42 | ClientEntry volume_max_; 43 | ClientEntry hz_; 44 | ClientEntry volume_; 45 | ClientEntry duration_; 46 | 47 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) 48 | { 49 | static const uint8_t kEntryLength = kSubDuration+1; 50 | ClientEntryAbstract* entry_array[kEntryLength] = { 51 | &ctrl_mode_, // 0 52 | &ctrl_brake_, // 1 53 | &ctrl_coast_, // 2 54 | &ctrl_note_, // 3 55 | &volume_max_, // 4 56 | &hz_, // 5 57 | &volume_, // 6 58 | &duration_, // 7 59 | }; 60 | 61 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 62 | } 63 | 64 | private: 65 | static const uint8_t kSubCtrlMode = 0; 66 | static const uint8_t kSubCtrlBrake = 1; 67 | static const uint8_t kSubCtrlCoast = 2; 68 | static const uint8_t kSubCtrlNote = 3; 69 | static const uint8_t kSubVolumeMax = 4; 70 | static const uint8_t kSubHz = 5; 71 | static const uint8_t kSubVolume = 6; 72 | static const uint8_t kSubDuration = 7; 73 | }; 74 | 75 | #endif // BUZZER_CONTROL_CLIENT_H 76 | -------------------------------------------------------------------------------- /inc/drive_control_interface_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: drive_control_interface_client.hpp 11 | Last update: 2025-03-12 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef DRIVE_CONTROL_INTERFACE_CLIENT_HPP_ 17 | #define DRIVE_CONTROL_INTERFACE_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeDriveControlInterface = 97; 22 | 23 | class DriveControlInterfaceClient : public ClientAbstract { 24 | public: 25 | DriveControlInterfaceClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeDriveControlInterface, obj_idn), 27 | voltage_target_(kTypeDriveControlInterface, obj_idn, kSubVoltageTarget), 28 | pwm_target_(kTypeDriveControlInterface, obj_idn, kSubPwmTarget), 29 | torque_target_(kTypeDriveControlInterface, obj_idn, kSubTorqueTarget), 30 | q_current_target_(kTypeDriveControlInterface, obj_idn, kSubQCurrentTarget), 31 | d_current_target_(kTypeDriveControlInterface, obj_idn, kSubDCurrentTarget), 32 | coast_(kTypeDriveControlInterface, obj_idn, kSubCoast), 33 | brake_(kTypeDriveControlInterface, obj_idn, kSubBrake), 34 | mode_(kTypeDriveControlInterface, obj_idn, kSubMode) 35 | {}; 36 | 37 | // Client Entries 38 | ClientEntry voltage_target_; 39 | ClientEntry pwm_target_; 40 | ClientEntry torque_target_; 41 | ClientEntry q_current_target_; 42 | ClientEntry d_current_target_; 43 | ClientEntryVoid coast_; 44 | ClientEntryVoid brake_; 45 | ClientEntry mode_; 46 | 47 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 48 | static const uint8_t kEntryLength = kSubMode + 1; 49 | ClientEntryAbstract* entry_array[kEntryLength] = { 50 | &voltage_target_, // 0 51 | &pwm_target_, // 1 52 | &torque_target_, // 2 53 | &q_current_target_, // 3 54 | &d_current_target_, // 4 55 | &coast_, // 5 56 | &brake_, // 6 57 | &mode_ // 7 58 | }; 59 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 60 | } 61 | 62 | private: 63 | static const uint8_t kSubVoltageTarget = 0; 64 | static const uint8_t kSubPwmTarget = 1; 65 | static const uint8_t kSubTorqueTarget = 2; 66 | static const uint8_t kSubQCurrentTarget = 3; 67 | static const uint8_t kSubDCurrentTarget = 4; 68 | static const uint8_t kSubCoast = 5; 69 | static const uint8_t kSubBrake = 6; 70 | static const uint8_t kSubMode = 7; 71 | 72 | }; 73 | 74 | #endif /* DRIVE_CONTROL_INTERFACE_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/anticogging_pro_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 Vertiq support@vertiq.co 3 | 4 | This file is part of the Vertiq C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: anticogging_pro_client.hpp 11 | Last update: 2023/06/29 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef ANTICOGGING_PRO_CLIENT_HPP 17 | #define ANTICOGGING_PRO_CLIENT_HPP 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeAnticoggingPro = 79; 22 | 23 | class AnticoggingProClient: public ClientAbstract{ 24 | public: 25 | AnticoggingProClient(uint8_t obj_idn): 26 | ClientAbstract( kTypeAnticoggingPro, obj_idn), 27 | enabled_(kTypeAnticoggingPro, obj_idn, kSubEnabled), 28 | tau_(kTypeAnticoggingPro, obj_idn, kSubTau), 29 | num_harmonics_(kTypeAnticoggingPro, obj_idn, kSubNumHarmonics), 30 | voltage_(kTypeAnticoggingPro, obj_idn, kSubVoltage), 31 | index_(kTypeAnticoggingPro, obj_idn, kSubIndex), 32 | harmonic_(kTypeAnticoggingPro, obj_idn, kSubHarmonic), 33 | a_(kTypeAnticoggingPro, obj_idn, kSubA), 34 | phase_(kTypeAnticoggingPro, obj_idn, kSubPhase), 35 | phase_total_(kTypeAnticoggingPro, obj_idn, kSubPhaseTotal), 36 | amplitude_(kTypeAnticoggingPro, obj_idn, kSubAmplitude), 37 | max_harmonics_(kTypeAnticoggingPro, obj_idn, kSubMaxHarmonics) 38 | {}; 39 | 40 | // Client Entries 41 | ClientEntry enabled_; 42 | ClientEntry tau_; 43 | ClientEntry num_harmonics_; 44 | ClientEntry voltage_; 45 | ClientEntry index_; 46 | ClientEntry harmonic_; 47 | ClientEntry a_; 48 | ClientEntry phase_; 49 | ClientEntry phase_total_; 50 | ClientEntry amplitude_; 51 | ClientEntry max_harmonics_; 52 | 53 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) 54 | { 55 | static const uint8_t kEntryLength = kSubMaxHarmonics+1; 56 | ClientEntryAbstract* entry_array[kEntryLength] = { 57 | &enabled_, // 0 58 | &tau_, // 1 59 | &num_harmonics_, // 2 60 | &voltage_, // 3 61 | &index_, // 4 62 | &harmonic_, // 5 63 | &a_, // 6 64 | &phase_, // 7 65 | &phase_total_, // 8 66 | &litude_, // 9 67 | &max_harmonics_ // 10 68 | }; 69 | 70 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 71 | } 72 | 73 | private: 74 | static const uint8_t kSubEnabled = 0; 75 | static const uint8_t kSubTau = 1; 76 | static const uint8_t kSubNumHarmonics = 2; 77 | static const uint8_t kSubVoltage = 3; 78 | static const uint8_t kSubIndex = 4; 79 | static const uint8_t kSubHarmonic = 5; 80 | static const uint8_t kSubA = 6; 81 | static const uint8_t kSubPhase = 7; 82 | static const uint8_t kSubPhaseTotal = 8; 83 | static const uint8_t kSubAmplitude = 9; 84 | static const uint8_t kSubMaxHarmonics = 10; 85 | }; 86 | 87 | #endif // ANTICOGGING_PRO_CLIENT_H 88 | -------------------------------------------------------------------------------- /inc/hobby_input_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: hobby_input_client.hpp 11 | Last update: 2025-08-26 by Ben Quan 12 | Author: Matthew Piccoli 13 | Contributors: Ben Quan, Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef HOBBY_INPUT_CLIENT_HPP_ 17 | #define HOBBY_INPUT_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeHobbyInput = 76; 22 | 23 | class HobbyInputClient: public ClientAbstract{ 24 | public: 25 | HobbyInputClient(uint8_t obj_idn): 26 | ClientAbstract( kTypeHobbyInput, obj_idn), 27 | allowed_protocols_( kTypeHobbyInput, obj_idn, kSubAllowedProtocols), 28 | protocol_( kTypeHobbyInput, obj_idn, kSubProtocol), 29 | calibrated_protocol_( kTypeHobbyInput, obj_idn, kSubCalibratedProtocol), 30 | calibrated_high_ticks_us_( kTypeHobbyInput, obj_idn, kSubCalibratedHighTicksUs), 31 | calibrated_low_ticks_us_( kTypeHobbyInput, obj_idn, kSubCalibratedLowTicksUs), 32 | reset_calibration_( kTypeHobbyInput, obj_idn, kSubResetCalibration), 33 | hobby_telemetry_frequency_(kTypeHobbyInput, obj_idn, kSubHobbyTelemetryFrequency), 34 | hobby_telemetry_speed_style_(kTypeHobbyInput, obj_idn, kSubHobbyTelemetrySpeedStyle), 35 | allow_dshot_disarming_message_(kTypeHobbyInput, obj_idn, kSubAllowDshotDisarmingMessage) 36 | {}; 37 | 38 | // Client Entries 39 | // Control commands 40 | ClientEntry allowed_protocols_; 41 | ClientEntry protocol_; 42 | ClientEntry calibrated_protocol_; 43 | ClientEntry calibrated_high_ticks_us_; 44 | ClientEntry calibrated_low_ticks_us_; 45 | ClientEntryVoid reset_calibration_; 46 | ClientEntry hobby_telemetry_frequency_; 47 | ClientEntry hobby_telemetry_speed_style_; 48 | ClientEntry allow_dshot_disarming_message_; 49 | 50 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) 51 | { 52 | static const uint8_t kEntryLength = kSubAllowDshotDisarmingMessage+1; 53 | ClientEntryAbstract* entry_array[kEntryLength] = { 54 | &allowed_protocols_, // 0 55 | &protocol_, // 1 56 | &calibrated_protocol_, // 2 57 | &calibrated_high_ticks_us_, // 3 58 | &calibrated_low_ticks_us_, // 4 59 | &reset_calibration_, // 5 60 | &hobby_telemetry_frequency_, // 6 61 | &hobby_telemetry_speed_style_, // 7 62 | &allow_dshot_disarming_message_ // 8 63 | }; 64 | 65 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 66 | } 67 | 68 | private: 69 | static const uint8_t kSubAllowedProtocols = 0; 70 | static const uint8_t kSubProtocol = 1; 71 | static const uint8_t kSubCalibratedProtocol = 2; 72 | static const uint8_t kSubCalibratedHighTicksUs = 3; 73 | static const uint8_t kSubCalibratedLowTicksUs = 4; 74 | static const uint8_t kSubResetCalibration = 5; 75 | static const uint8_t kSubHobbyTelemetryFrequency = 6; 76 | static const uint8_t kSubHobbyTelemetrySpeedStyle = 7; 77 | static const uint8_t kSubAllowDshotDisarmingMessage = 8; 78 | }; 79 | 80 | #endif /* HOBBY_INPUT_CLIENT_HPP_ */ 81 | -------------------------------------------------------------------------------- /inc/stow_user_interface_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: stow_user_interface_client.hpp 11 | Last update: 2024/09/19 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef STOW_USER_INTERFACE_CLIENT_HPP_ 17 | #define STOW_USER_INTERFACE_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeStowUserInterface = 85; 22 | 23 | class StowUserInterfaceClient : public ClientAbstract { 24 | public: 25 | StowUserInterfaceClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeStowUserInterface, obj_idn), 27 | zero_angle_(kTypeStowUserInterface, obj_idn, kSubZeroAngle), 28 | target_angle_(kTypeStowUserInterface, obj_idn, kSubTargetAngle), 29 | target_acceleration_(kTypeStowUserInterface, obj_idn, kSubTargetAcceleration), 30 | sample_zero_(kTypeStowUserInterface, obj_idn, kSubSampleZero), 31 | stow_(kTypeStowUserInterface, obj_idn, kSubStow), 32 | stow_kp_(kTypeStowUserInterface, obj_idn, kSubStowKp), 33 | stow_ki_(kTypeStowUserInterface, obj_idn, kSubStowKi), 34 | stow_kd_(kTypeStowUserInterface, obj_idn, kSubStowKd), 35 | hold_stow_(kTypeStowUserInterface, obj_idn, kSubHoldStow), 36 | stow_status_(kTypeStowUserInterface, obj_idn, kSubStowStatus), 37 | stow_result_(kTypeStowUserInterface, obj_idn, kSubStowResult){}; 38 | 39 | // Client Entries 40 | ClientEntry zero_angle_; 41 | ClientEntry target_angle_; 42 | ClientEntry target_acceleration_; 43 | ClientEntryVoid sample_zero_; 44 | ClientEntryVoid stow_; 45 | ClientEntry stow_kp_; 46 | ClientEntry stow_ki_; 47 | ClientEntry stow_kd_; 48 | ClientEntry hold_stow_; 49 | ClientEntry stow_status_; 50 | ClientEntry stow_result_; 51 | 52 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 53 | static const uint8_t kEntryLength = kSubStowResult + 1; 54 | ClientEntryAbstract* entry_array[kEntryLength] = { 55 | &zero_angle_, // 0 56 | &target_angle_, // 1 57 | &target_acceleration_, // 2 58 | &sample_zero_, // 3 59 | &stow_, // 4 60 | &stow_kp_, // 5 61 | &stow_ki_, // 6 62 | &stow_kd_, // 7 63 | &hold_stow_, // 8 64 | &stow_status_, // 9 65 | &stow_result_ // 10 66 | }; 67 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 68 | } 69 | 70 | private: 71 | static const uint8_t kSubZeroAngle = 0; 72 | static const uint8_t kSubTargetAngle = 1; 73 | static const uint8_t kSubTargetAcceleration = 2; 74 | static const uint8_t kSubSampleZero = 3; 75 | static const uint8_t kSubStow = 4; 76 | static const uint8_t kSubStowKp = 5; 77 | static const uint8_t kSubStowKi = 6; 78 | static const uint8_t kSubStowKd = 7; 79 | static const uint8_t kSubHoldStow = 8; 80 | static const uint8_t kSubStowStatus = 9; 81 | static const uint8_t kSubStowResult = 10; 82 | }; 83 | 84 | #endif /* STOW_USER_INTERFACE_CLIENT_HPP_ */ 85 | -------------------------------------------------------------------------------- /inc/communication_interface.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: communication_interface.hpp 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: Matthew Piccoli 13 | Contributors: Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef COMMUNICATION_INTERFACE_H 17 | #define COMMUNICATION_INTERFACE_H 18 | 19 | #include 20 | 21 | class CommunicationInterface{ 22 | private: 23 | 24 | public: 25 | /******************************************************************************* 26 | * Receive 27 | ******************************************************************************/ 28 | 29 | /// Poll the hardware for new byte data. 30 | /// Returns: 1 packet ready 31 | /// 0 normal operation 32 | /// -1 failure 33 | /// 34 | virtual int8_t GetBytes() = 0; 35 | 36 | /// Peek at the next available incoming packet. If a packet is ready, pointer 37 | /// 'packet' will point to the first byte of type+data and 'length' will give 38 | /// the length of packet type+data. Arguments 'packet' and 'length' are ignored 39 | /// if no packet is ready. Repeated calls to Peek will return pointers to the 40 | /// same packet data until Drop is used. 41 | /// Returns: 1 packet peek available 42 | /// 0 no packet peek available 43 | /// -1 failure 44 | /// 45 | virtual int8_t PeekPacket(uint8_t **packet, uint8_t *length) = 0; 46 | 47 | /// Drop the next available packet from queue. Usually called after Peek. 48 | /// Returns: 1 packet removed 49 | /// 0 no packet ready to remove 50 | /// -1 failure 51 | /// 52 | virtual int8_t DropPacket() = 0; 53 | 54 | 55 | /******************************************************************************* 56 | * Send 57 | ******************************************************************************/ 58 | 59 | /// Add a packet to the outgoing USB queue with automatically generated header 60 | /// and CRC. A hardware transmission is not immediately initiated unless the 61 | /// endpoint is filled. To force a transmission, follow with SendNow(). This 62 | /// operation is nonblocking. If the buffer fills, the most recent data is lost. 63 | virtual int8_t SendPacket(uint8_t msg_type, uint8_t *data, uint16_t length) = 0; 64 | 65 | /// Add bytes to the outgoing USB queue. A hardware transmission is not 66 | /// immediately initiated unless the endpoint is filled. To force a 67 | /// transmission, follow with SendUsbNow(). This operation is 68 | /// nonblocking. If the buffer fills, the most recent data is lost. 69 | virtual int8_t SendBytes(uint8_t *bytes, uint16_t length) = 0; 70 | 71 | /// Initiate a hardware transmission, which will chain transmissions through 72 | /// the endpoint IN interrupt until the buffer empties completely. 73 | virtual void SendNow() = 0; 74 | 75 | /******************************************************************************* 76 | * Parsing 77 | ******************************************************************************/ 78 | 79 | /// Read a given message and act appropriately. 80 | virtual void ReadMsg(CommunicationInterface& com, uint8_t* data, uint8_t length) = 0; 81 | }; // end class CommunicationInterface 82 | 83 | #endif // COMMUNICATION_INTERFACE_H -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at raf@iq-control.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /inc/esc_propeller_input_parser_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: esc_propeller_input_parser_client.hpp 11 | Last update: 2025/03/07 by Ben Quan 12 | Author: Matthew Piccoli 13 | Contributors: Ben Quan, Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef ESC_PROPELLER_INPUT_PARSER_CLIENT_HPP_ 17 | #define ESC_PROPELLER_INPUT_PARSER_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeEscPropellerInputParser = 60; 22 | 23 | class EscPropellerInputParserClient : public ClientAbstract { 24 | public: 25 | EscPropellerInputParserClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeEscPropellerInputParser, obj_idn), 27 | mode_(kTypeEscPropellerInputParser, obj_idn, kSubMode), 28 | raw_value_(kTypeEscPropellerInputParser, obj_idn, kSubRawValue), 29 | sign_(kTypeEscPropellerInputParser, obj_idn, kSubSign), 30 | volts_max_(kTypeEscPropellerInputParser, obj_idn, kSubVoltsMax), 31 | velocity_max_(kTypeEscPropellerInputParser, obj_idn, kSubVelocityMax), 32 | safe_factor_(kTypeEscPropellerInputParser, obj_idn, kSubSafeFactor), 33 | flip_negative_(kTypeEscPropellerInputParser, obj_idn, kSubFlipNegative), 34 | zero_spin_throttle_(kTypeEscPropellerInputParser, obj_idn, kSubZeroSpinThrottle), 35 | zero_spin_tolerance_(kTypeEscPropellerInputParser, obj_idn, kSubZeroSpinTolerance), 36 | report_telemetry_as_speed_(kTypeEscPropellerInputParser, obj_idn, kSubReportTelemetryAsSpeed){}; 37 | 38 | // Client Entries 39 | // Control commands 40 | ClientEntry mode_; 41 | ClientEntry raw_value_; 42 | ClientEntry sign_; 43 | ClientEntry volts_max_; 44 | ClientEntry velocity_max_; 45 | ClientEntry safe_factor_; 46 | ClientEntry flip_negative_; 47 | ClientEntry zero_spin_throttle_; 48 | ClientEntry zero_spin_tolerance_; 49 | ClientEntry report_telemetry_as_speed_; 50 | 51 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 52 | static const uint8_t kEntryLength = kSubReportTelemetryAsSpeed + 1; 53 | ClientEntryAbstract* entry_array[kEntryLength] = { 54 | &mode_, // 0 55 | &raw_value_, // 1 56 | nullptr, // 2 57 | &sign_, // 3 58 | &volts_max_, // 4 59 | &velocity_max_, // 5 60 | nullptr, // 6 61 | &safe_factor_, // 7 62 | &flip_negative_, // 8 63 | &zero_spin_throttle_, // 9 64 | &zero_spin_tolerance_, // 10 65 | &report_telemetry_as_speed_ // 11 66 | }; 67 | 68 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 69 | } 70 | 71 | private: 72 | static const uint8_t kSubMode = 0; 73 | static const uint8_t kSubRawValue = 1; 74 | static const uint8_t kSubSign = 3; 75 | static const uint8_t kSubVoltsMax = 4; 76 | static const uint8_t kSubVelocityMax = 5; 77 | static const uint8_t kSubSafeFactor = 7; 78 | static const uint8_t kSubFlipNegative = 8; 79 | static const uint8_t kSubZeroSpinThrottle = 9; 80 | static const uint8_t kSubZeroSpinTolerance = 10; 81 | static const uint8_t kSubReportTelemetryAsSpeed = 11; 82 | }; 83 | 84 | #endif /* ESC_PROPELLER_INPUT_PARSER_CLIENT_HPP_ */ 85 | -------------------------------------------------------------------------------- /src/byte_queue.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: byte_queue.c 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: James Paulos 13 | Contributors: Matthew Piccoli, Raphael Van Hoffelen 14 | */ 15 | 16 | /// A FIFO buffer for uint8 bytes implemented with a fixed size circular buffer. 17 | /// See header file for usage. 18 | 19 | #include "byte_queue.h" 20 | 21 | 22 | void InitBQ(struct ByteQueue *p, uint8_t* data, uint16_t data_size) { 23 | p->data = data; 24 | p->data_size = data_size; 25 | p->start = p->data; 26 | p->end = p->data; 27 | p->count = 0; 28 | } 29 | 30 | 31 | int8_t IsFullBQ(struct ByteQueue *p) { 32 | // if p->end at end of fixed array 33 | if (p->end == p->data + p->data_size - 1) { 34 | if (p->start == p->data) { 35 | return 1; // buffer full if p->start is at beginning of fixed array 36 | } else { 37 | return 0; // buffer not full 38 | } 39 | } 40 | // otherwise p->end not at end of fixed array 41 | else { 42 | if (p->end == p->start - 1) { 43 | return 1; // buffer full if p->end preceeds p->start by one 44 | } else { 45 | return 0; // buffer not full 46 | } 47 | } 48 | } 49 | 50 | 51 | int8_t IsEmptyBQ(struct ByteQueue *p) { 52 | if(p->start == p->end) 53 | return 1; 54 | else 55 | return 0; 56 | } 57 | 58 | 59 | uint16_t CountBQ(struct ByteQueue *p) { 60 | return(p->count); 61 | } 62 | 63 | 64 | uint8_t GetByteBQ(struct ByteQueue *p) { 65 | 66 | // silent failure if empty 67 | if(IsEmptyBQ(p)) { 68 | return(0); 69 | } 70 | else { 71 | // otherwise buffer contains data 72 | // get data at start 73 | uint8_t temp_char = *(p->start); 74 | // if start is not at the end of the array, advance start 75 | if (p->start != p->data + p->data_size - 1) { 76 | p->start = p->start + 1; 77 | } 78 | // otherwise wrap start to the beginning of the array 79 | else { 80 | p->start = p->data; 81 | } 82 | p->count--; 83 | return temp_char; 84 | } 85 | } 86 | 87 | 88 | uint8_t PeekByteBQ(struct ByteQueue *p) { 89 | // silent failure if empty 90 | if(IsEmptyBQ(p)) { 91 | return(0); 92 | } 93 | else { 94 | return(*(p->start)); 95 | } 96 | } 97 | 98 | 99 | int8_t PutByteBQ(struct ByteQueue *p, uint8_t item) { 100 | // if p->end points to last element of array 101 | if (p->end == p->data + p->data_size - 1) 102 | { 103 | // if start is at the beginning of the array, the buffer is full 104 | if (p->start == p->data) { 105 | return 0; // failure, buffer is full 106 | } 107 | // otherwise stuff item at p->end 108 | else { 109 | *(p->end) = item; // stuff item at p->end 110 | p->end = p->data; // move p->end to start of array 111 | } 112 | } 113 | // otherwise p->end does not point to last element of array 114 | else { 115 | // if p->end preceeds p->start by one, buffer is full 116 | if (p->end == (p->start - 1)) { 117 | return 0; // failure, buffer is full 118 | } 119 | // otherwise stuff item at p->end 120 | else { 121 | *(p->end) = item; // stuff item at p->end 122 | p->end = p->end + 1; // advance p->end one 123 | } 124 | } 125 | p->count++; 126 | return 1; // success 127 | } 128 | -------------------------------------------------------------------------------- /src/generic_interface.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: generic_interface.cpp 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: Matthew Piccoli 13 | Contributors: Raphael Van Hoffelen 14 | */ 15 | 16 | #include "generic_interface.hpp" 17 | #include "crc_helper.h" 18 | #include "string.h" // for memcpy 19 | 20 | GenericInterface::GenericInterface() 21 | { 22 | InitBQ(&index_queue, pf_index_data, GENERIC_PF_INDEX_DATA_SIZE); 23 | InitPacketFinder(&pf, &index_queue); 24 | tx_bipbuf = BipBuffer(tx_buffer, GENERIC_TX_BUFFER_SIZE); 25 | } 26 | 27 | int8_t GenericInterface::GetBytes() 28 | { 29 | // I can't do anything on my own since I don't have hardware 30 | // Use SetRxBytes(uint8_t* data_in, uint16_t length_in) 31 | return 0; 32 | } 33 | 34 | int8_t GenericInterface::SetRxBytes(uint8_t* data_in, uint16_t length_in) 35 | { 36 | if(data_in == nullptr) 37 | return -1; 38 | 39 | if(length_in) 40 | { 41 | //copy it over 42 | PutBytes(&pf, data_in, length_in); 43 | return 1; 44 | } 45 | else 46 | return 0; 47 | } 48 | 49 | int8_t GenericInterface::PeekPacket(uint8_t **packet, uint8_t *length) 50 | { 51 | return(::PeekPacket(&pf, packet, length)); 52 | } 53 | 54 | int8_t GenericInterface::DropPacket() 55 | { 56 | return(::DropPacket(&pf)); 57 | } 58 | 59 | int8_t GenericInterface::SendPacket(uint8_t msg_type, uint8_t *data, uint16_t length) 60 | { 61 | // This function must not be interrupted by another call to SendBytes or 62 | // SendPacket, or else the packet it builds will be spliced/corrupted. 63 | 64 | uint8_t header[3]; 65 | header[0] = kStartByte; // const defined by packet_finder.c 66 | header[1] = length; 67 | header[2] = msg_type; 68 | SendBytes(header, 3); 69 | 70 | SendBytes(data, length); 71 | 72 | uint8_t footer[2]; 73 | uint16_t crc; 74 | crc = MakeCrc(&(header[1]), 2); 75 | crc = ArrayUpdateCrc(crc, data, length); 76 | footer[0] = crc & 0x00FF; 77 | footer[1] = crc >> 8; 78 | SendBytes(footer, 2); 79 | 80 | return(1); 81 | } 82 | 83 | int8_t GenericInterface::SendBytes(uint8_t *bytes, uint16_t length) 84 | { 85 | uint16_t length_temp = 0; 86 | uint8_t* location_temp; 87 | int8_t ret = 0; 88 | 89 | // Reserve space in the buffer 90 | location_temp = tx_bipbuf.Reserve(length, length_temp); 91 | 92 | // If there's room, do the copy 93 | if(length == length_temp) 94 | { 95 | memcpy(location_temp, bytes, length_temp); // do copy 96 | tx_bipbuf.Commit(length_temp); 97 | ret = 1; 98 | } 99 | else 100 | { 101 | tx_bipbuf.Commit(0); // Call the restaurant, cancel the reservations 102 | } 103 | 104 | return ret; 105 | } 106 | 107 | int8_t GenericInterface::GetTxBytes(uint8_t* data_out, uint8_t& length_out) 108 | { 109 | uint16_t length_temp; 110 | uint8_t* location_temp; 111 | 112 | location_temp = tx_bipbuf.GetContiguousBlock(length_temp); 113 | if(length_temp) 114 | { 115 | memcpy(data_out, location_temp, length_temp); 116 | length_out = length_temp; 117 | tx_bipbuf.DecommitBlock(length_temp); 118 | 119 | location_temp = tx_bipbuf.GetContiguousBlock(length_temp); 120 | memcpy(&data_out[length_out], location_temp, length_temp); 121 | length_out = length_out + length_temp; 122 | tx_bipbuf.DecommitBlock(length_temp); 123 | return 1; 124 | } 125 | return 0; 126 | } 127 | 128 | void GenericInterface::SendNow() 129 | { 130 | // I'm useless. 131 | } 132 | 133 | void GenericInterface::ReadMsg(CommunicationInterface& com, uint8_t* data, uint8_t length) 134 | { 135 | // I currently don't support being talked to 136 | (void)com; 137 | (void)data; 138 | (void)length; 139 | } -------------------------------------------------------------------------------- /inc/gpio_controller_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: gpio_controller_client.hpp 11 | Last update: 2023/04/18 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef GPIO_CONTROLLER_CLIENT_HPP_ 17 | #define GPIO_CONTROLLER_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeGpioController = 90; 22 | 23 | class GpioControllerClient : public ClientAbstract { 24 | public: 25 | GpioControllerClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeGpioController, obj_idn), 27 | mode_register_(kTypeGpioController, obj_idn, kSubModeRegister), 28 | inputs_register_(kTypeGpioController, obj_idn, kSubInputsRegister), 29 | outputs_register_(kTypeGpioController, obj_idn, kSubOutputsRegister), 30 | use_pull_register_(kTypeGpioController, obj_idn, kSubUsePullRegister), 31 | pull_type_register_(kTypeGpioController, obj_idn, kSubPullTypeRegister), 32 | push_pull_open_drain_register_(kTypeGpioController, obj_idn, kSubPushPullOpenDrainRegister), 33 | addressable_gpio_mode_(kTypeGpioController, obj_idn, kSubAddressableGpioMode), 34 | addressable_outputs_(kTypeGpioController, obj_idn, kSubAddressableOutputs), 35 | addressable_use_pull_(kTypeGpioController, obj_idn, kSubAddressableUsePull), 36 | addressable_pull_type_(kTypeGpioController, obj_idn, kSubAddressablePullType), 37 | addressable_push_pull_open_drain_(kTypeGpioController, obj_idn, kSubAddressablePushPullOpenDrain){}; 38 | 39 | // Client Entries 40 | ClientEntry mode_register_; // 0 41 | ClientEntry inputs_register_; // 1 42 | ClientEntry outputs_register_; // 2 43 | ClientEntry use_pull_register_; // 3 44 | ClientEntry pull_type_register_; // 4 45 | ClientEntry push_pull_open_drain_register_; // 5 46 | ClientEntry addressable_gpio_mode_; // 6 47 | ClientEntry addressable_outputs_; // 7 48 | ClientEntry addressable_use_pull_; // 8 49 | ClientEntry addressable_pull_type_; // 9 50 | ClientEntry addressable_push_pull_open_drain_; // 10 51 | 52 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 53 | static const uint8_t kEntryLength = kSubAddressablePushPullOpenDrain + 1; 54 | ClientEntryAbstract* entry_array[kEntryLength] = { 55 | &mode_register_, // 0 56 | &inputs_register_, // 1 57 | &outputs_register_, // 2 58 | &use_pull_register_, // 3 59 | &pull_type_register_, // 4 60 | &push_pull_open_drain_register_, // 5 61 | &addressable_gpio_mode_, // 6 62 | &addressable_outputs_, // 7 63 | &addressable_use_pull_, // 8 64 | &addressable_pull_type_, // 9 65 | &addressable_push_pull_open_drain_ // 10 66 | }; 67 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 68 | } 69 | 70 | private: 71 | static const uint8_t kSubModeRegister = 0; 72 | static const uint8_t kSubInputsRegister = 1; 73 | static const uint8_t kSubOutputsRegister = 2; 74 | static const uint8_t kSubUsePullRegister = 3; 75 | static const uint8_t kSubPullTypeRegister = 4; 76 | static const uint8_t kSubPushPullOpenDrainRegister = 5; 77 | static const uint8_t kSubAddressableGpioMode = 6; 78 | static const uint8_t kSubAddressableOutputs = 7; 79 | static const uint8_t kSubAddressableUsePull = 8; 80 | static const uint8_t kSubAddressablePullType = 9; 81 | static const uint8_t kSubAddressablePushPullOpenDrain = 10; 82 | }; 83 | 84 | #endif /* GPIO_CONTROLLER_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/generic_interface.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: generic_interface.hpp 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: Matthew Piccoli 13 | Contributors: Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef GENERIC_INTERFACE_H 17 | #define GENERIC_INTERFACE_H 18 | 19 | #include "communication_interface.h" 20 | #include "packet_finder.h" 21 | #include "byte_queue.h" 22 | #include "bipbuffer.h" 23 | 24 | #define GENERIC_PF_INDEX_DATA_SIZE 20 // size of index buffer in packet_finder 25 | 26 | #ifndef GENERIC_TX_BUFFER_SIZE 27 | #define GENERIC_TX_BUFFER_SIZE 64 28 | #endif 29 | 30 | class GenericInterface: public CommunicationInterface{ 31 | private: 32 | 33 | public: 34 | // Member Variables 35 | struct PacketFinder pf; // packet_finder instance 36 | struct ByteQueue index_queue; // needed by pf for storing indices 37 | uint8_t pf_index_data[GENERIC_PF_INDEX_DATA_SIZE]; // data for index_queue used by pf 38 | BipBuffer tx_bipbuf; // bipbuffer for transmissions 39 | uint8_t tx_buffer[GENERIC_TX_BUFFER_SIZE]; // raw buffer for transmissions 40 | 41 | 42 | // Default Constructor 43 | GenericInterface(); 44 | 45 | /******************************************************************************* 46 | * Receive 47 | ******************************************************************************/ 48 | 49 | /// Poll the hardware for new byte data. 50 | /// Returns: 1 packet ready 51 | /// 0 normal operation 52 | /// -1 failure 53 | /// 54 | int8_t GetBytes(); 55 | int8_t SetRxBytes(uint8_t* data_in, uint16_t length_in); 56 | 57 | /// Peek at the next available incoming packet. If a packet is ready, pointer 58 | /// 'packet' will point to the first byte of type+data and 'length' will give 59 | /// the length of packet type+data. Arguments 'packet' and 'length' are ignored 60 | /// if no packet is ready. Repeated calls to Peek will return pointers to the 61 | /// same packet data until Drop is used. 62 | /// Returns: 1 packet peek available 63 | /// 0 no packet peek available 64 | /// -1 failure 65 | /// 66 | int8_t PeekPacket(uint8_t **packet, uint8_t *length); 67 | 68 | /// Drop the next available packet from queue. Usually called after Peek. 69 | /// Returns: 1 packet removed 70 | /// 0 no packet ready to remove 71 | /// -1 failure 72 | /// 73 | int8_t DropPacket(); 74 | 75 | /******************************************************************************* 76 | * Send 77 | ******************************************************************************/ 78 | 79 | /// Add a packet to the outgoing queue with automatically generated header 80 | /// and CRC. If the buffer fills, the most recent data is lost. 81 | int8_t SendPacket(uint8_t msg_type, uint8_t *data, uint16_t length); 82 | 83 | /// Add bytes to the outgoing queue. 84 | /// If the buffer fills, the most recent data is lost. 85 | int8_t SendBytes(uint8_t *bytes, uint16_t length); 86 | 87 | /// Does nothing in this interface 88 | void SendNow(); 89 | 90 | /// Gets all outbound bytes 91 | /// The data is copied into the user supplied data_out buffer. 92 | /// The length of data transferred is copied into length_out. 93 | /// Returns: 1 for data transferred 94 | /// 0 for no data transferred (buffer empty) 95 | int8_t GetTxBytes(uint8_t* data_out, uint8_t& length_out); 96 | 97 | /******************************************************************************* 98 | * Parsing 99 | ******************************************************************************/ 100 | 101 | /// Read a given message and act appropriately. 102 | void ReadMsg(CommunicationInterface& com, uint8_t* data, uint8_t length); 103 | }; // class GenericInterface 104 | 105 | #endif // GENERIC_INTERFACE_H -------------------------------------------------------------------------------- /inc/uavcan_node_client.hpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright 2024 Vertiq, Inc support@vertiq.co 4 | 5 | This file is part of the IQ C++ API. 6 | 7 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 8 | */ 9 | 10 | /* 11 | Name: uavcan_node_client.hpp 12 | Last update: 2025/01/31 by Ben Quan 13 | Author: Ben Quan 14 | Contributors: 15 | */ 16 | 17 | #ifndef UAVCAN_NODE_CLIENT_HPP_ 18 | #define UAVCAN_NODE_CLIENT_HPP_ 19 | 20 | #include "client_communication.hpp" 21 | 22 | const uint8_t kTypeUavcanNode = 80; 23 | 24 | class UavcanNodeClient : public ClientAbstract { 25 | public: 26 | UavcanNodeClient(uint8_t obj_idn) 27 | : ClientAbstract(kTypeUavcanNode, obj_idn), 28 | uavcan_node_id_(kTypeUavcanNode, obj_idn, kSubUavcanNodeId), 29 | uavcan_esc_index_(kTypeUavcanNode, obj_idn, kSubUavcanEscIndex), 30 | zero_behavior_(kTypeUavcanNode, obj_idn, kSubZeroBehavior), 31 | last_error_code_(kTypeUavcanNode, obj_idn, kSubLastErrorCode), 32 | receive_error_counter_(kTypeUavcanNode, obj_idn, kSubReceiveErrorCounter), 33 | transmit_error_counter_(kTypeUavcanNode, obj_idn, kSubTransmitErrorCounter), 34 | bus_off_flag_(kTypeUavcanNode, obj_idn, kSubBusOffFlag), 35 | error_passive_flag_(kTypeUavcanNode, obj_idn, kSubErrorPassiveFlag), 36 | error_warning_flag_(kTypeUavcanNode, obj_idn, kSubErrorWarningFlag), 37 | telemetry_frequency_(kTypeUavcanNode, obj_idn, kSubTelemetryFrequency), 38 | bit_rate_(kTypeUavcanNode, obj_idn, kSubBitRate), 39 | bypass_arming_(kTypeUavcanNode, obj_idn, kSubBypassArming), 40 | arming_by_arming_status_(kTypeUavcanNode, obj_idn, kSubArmingByArmingStatus), 41 | telemetry_style_(kTypeUavcanNode, obj_idn, kSubTelemetryStyle) 42 | {}; 43 | 44 | // Client Entries 45 | ClientEntry uavcan_node_id_; 46 | ClientEntry uavcan_esc_index_; 47 | ClientEntry zero_behavior_; 48 | ClientEntry last_error_code_; 49 | ClientEntry receive_error_counter_; 50 | ClientEntry transmit_error_counter_; 51 | ClientEntry bus_off_flag_; 52 | ClientEntry error_passive_flag_; 53 | ClientEntry error_warning_flag_; 54 | ClientEntry telemetry_frequency_; 55 | ClientEntry bit_rate_; 56 | ClientEntry bypass_arming_; 57 | ClientEntry arming_by_arming_status_; 58 | ClientEntry telemetry_style_; 59 | 60 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 61 | static const uint8_t kEntryLength = kSubTelemetryStyle + 1; 62 | ClientEntryAbstract* entry_array[kEntryLength] = { 63 | &uavcan_node_id_, // 0 64 | &uavcan_esc_index_, // 1 65 | &zero_behavior_, // 2 66 | &last_error_code_, // 3 67 | &receive_error_counter_, // 4 68 | &transmit_error_counter_, // 5 69 | &bus_off_flag_, // 6 70 | &error_passive_flag_, // 7 71 | &error_warning_flag_, // 8 72 | &telemetry_frequency_, // 9 73 | &bit_rate_, // 10 74 | &bypass_arming_, // 11 75 | &arming_by_arming_status_, // 12 76 | &telemetry_style_ // 13 77 | }; 78 | 79 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 80 | } 81 | 82 | private: 83 | static const uint8_t kSubUavcanNodeId = 0; 84 | static const uint8_t kSubUavcanEscIndex = 1; 85 | static const uint8_t kSubZeroBehavior = 2; 86 | static const uint8_t kSubLastErrorCode = 3; 87 | static const uint8_t kSubReceiveErrorCounter = 4; 88 | static const uint8_t kSubTransmitErrorCounter = 5; 89 | static const uint8_t kSubBusOffFlag = 6; 90 | static const uint8_t kSubErrorPassiveFlag = 7; 91 | static const uint8_t kSubErrorWarningFlag = 8; 92 | static const uint8_t kSubTelemetryFrequency = 9; 93 | static const uint8_t kSubBitRate = 10; 94 | static const uint8_t kSubBypassArming = 11; 95 | static const uint8_t kSubArmingByArmingStatus = 12; 96 | static const uint8_t kSubTelemetryStyle = 13; 97 | }; 98 | 99 | #endif /* UAVCAN_NODE_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/power_monitor_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: power_monitor_client.hpp 11 | Last update: 2024/09/19 by Ben Quan 12 | Author: Matthew Piccoli 13 | Contributors: Ben Quan, Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef POWER_MONITOR_CLIENT_HPP_ 17 | #define POWER_MONITOR_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypePowerMonitor = 69; 22 | 23 | class PowerMonitorClient: public ClientAbstract{ 24 | public: 25 | PowerMonitorClient(uint8_t obj_idn): 26 | ClientAbstract( kTypePowerMonitor, obj_idn), 27 | volts_( kTypePowerMonitor, obj_idn, kSubVolts), 28 | amps_( kTypePowerMonitor, obj_idn, kSubAmps), 29 | watts_( kTypePowerMonitor, obj_idn, kSubWatts), 30 | joules_( kTypePowerMonitor, obj_idn, kSubJoules), 31 | reset_joules_( kTypePowerMonitor, obj_idn, kSubResetJoules), 32 | filter_fs_( kTypePowerMonitor, obj_idn, kSubFilterFs), 33 | filter_fc_( kTypePowerMonitor, obj_idn, kSubFilterFc), 34 | volts_raw_( kTypePowerMonitor, obj_idn, kSubVoltsRaw), 35 | amps_raw_( kTypePowerMonitor, obj_idn, kSubAmpsRaw), 36 | volts_gain_( kTypePowerMonitor, obj_idn, kSubVoltsGain), 37 | amps_gain_( kTypePowerMonitor, obj_idn, kSubAmpsGain), 38 | amps_bias_( kTypePowerMonitor, obj_idn, kSubAmpsBias), 39 | volts_cascaded_( kTypePowerMonitor, obj_idn, kSubVoltsCascaded), 40 | volts_cascaded_filter_fc_( kTypePowerMonitor, obj_idn, kSubVoltsCascadedFilterFc) 41 | {}; 42 | 43 | // Client Entries 44 | // Control commands 45 | ClientEntry volts_; 46 | ClientEntry amps_; 47 | ClientEntry watts_; 48 | ClientEntry joules_; 49 | ClientEntryVoid reset_joules_; 50 | ClientEntry filter_fs_; 51 | ClientEntry filter_fc_; 52 | ClientEntry volts_raw_; 53 | ClientEntry amps_raw_; 54 | ClientEntry volts_gain_; 55 | ClientEntry amps_gain_; 56 | ClientEntry amps_bias_; 57 | ClientEntry volts_cascaded_; 58 | ClientEntry volts_cascaded_filter_fc_; 59 | 60 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) 61 | { 62 | static const uint8_t kEntryLength = kSubVoltsCascadedFilterFc+1; 63 | ClientEntryAbstract* entry_array[kEntryLength] = { 64 | &volts_, // 0 65 | &s_, // 1 66 | &watts_, // 2 67 | &joules_, // 3 68 | &reset_joules_, // 4 69 | &filter_fs_, // 5 70 | &filter_fc_, // 6 71 | &volts_raw_, // 7 72 | &s_raw_, // 8 73 | &volts_gain_, // 9 74 | &s_gain_, // 10 75 | &s_bias_, // 11 76 | &volts_cascaded_, // 13 77 | &volts_cascaded_filter_fc_ // 14 78 | }; 79 | 80 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 81 | } 82 | 83 | private: 84 | static const uint8_t kSubVolts = 0; 85 | static const uint8_t kSubAmps = 1; 86 | static const uint8_t kSubWatts = 2; 87 | static const uint8_t kSubJoules = 3; 88 | static const uint8_t kSubResetJoules = 4; 89 | static const uint8_t kSubFilterFs = 5; 90 | static const uint8_t kSubFilterFc = 6; 91 | static const uint8_t kSubVoltsRaw = 7; 92 | static const uint8_t kSubAmpsRaw = 8; 93 | static const uint8_t kSubVoltsGain = 9; 94 | static const uint8_t kSubAmpsGain = 10; 95 | static const uint8_t kSubAmpsBias = 11; 96 | static const uint8_t kSubVoltsCascaded = 13; 97 | static const uint8_t kSubVoltsCascadedFilterFc = 14; 98 | }; 99 | 100 | #endif /* POWER_MONITOR_CLIENT_HPP_ */ 101 | -------------------------------------------------------------------------------- /inc/power_safety_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: power_safety_client.hpp 11 | Last update: 2023/04/24 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef POWER_SAFETY_CLIENT_HPP_ 17 | #define POWER_SAFETY_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypePowerSafety = 84; 22 | 23 | class PowerSafetyClient : public ClientAbstract { 24 | public: 25 | PowerSafetyClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypePowerSafety, obj_idn), 27 | fault_now_(kTypePowerSafety, obj_idn, kSubFaultNow), 28 | fault_ever_(kTypePowerSafety, obj_idn, kSubFaultEver), 29 | fault_latching_(kTypePowerSafety, obj_idn, kSubFaultLatching), 30 | volt_input_low_(kTypePowerSafety, obj_idn, kSubVoltInputLow), 31 | volt_input_high_(kTypePowerSafety, obj_idn, kSubVoltInputHigh), 32 | vref_int_low_(kTypePowerSafety, obj_idn, kSubVrefIntLow), 33 | vref_int_high_(kTypePowerSafety, obj_idn, kSubVrefIntHigh), 34 | current_input_low_(kTypePowerSafety, obj_idn, kSubCurrentInputLow), 35 | current_input_high_(kTypePowerSafety, obj_idn, kSubCurrentInputHigh), 36 | motor_current_low_(kTypePowerSafety, obj_idn, kSubMotorCurrentLow), 37 | motor_current_high_(kTypePowerSafety, obj_idn, kSubMotorCurrentHigh), 38 | temperature_uc_low_(kTypePowerSafety, obj_idn, kSubTemperatureUcLow), 39 | temperature_uc_high_(kTypePowerSafety, obj_idn, kSubTemperatureUcHigh), 40 | temperature_coil_low_(kTypePowerSafety, obj_idn, kSubTemperatureCoilLow), 41 | temperature_coil_high_(kTypePowerSafety, obj_idn, kSubTemperatureCoilHigh){}; 42 | 43 | // Client Entries 44 | ClientEntry fault_now_; 45 | ClientEntry fault_ever_; 46 | ClientEntry fault_latching_; 47 | ClientEntry volt_input_low_; 48 | ClientEntry volt_input_high_; 49 | ClientEntry vref_int_low_; 50 | ClientEntry vref_int_high_; 51 | ClientEntry current_input_low_; 52 | ClientEntry current_input_high_; 53 | ClientEntry motor_current_low_; 54 | ClientEntry motor_current_high_; 55 | ClientEntry temperature_uc_low_; 56 | ClientEntry temperature_uc_high_; 57 | ClientEntry temperature_coil_low_; 58 | ClientEntry temperature_coil_high_; 59 | 60 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 61 | static const uint8_t kEntryLength = kSubTemperatureCoilHigh + 1; 62 | ClientEntryAbstract* entry_array[kEntryLength] = { 63 | &fault_now_, // 0 64 | &fault_ever_, // 1 65 | &fault_latching_, // 2 66 | &volt_input_low_, // 3 67 | &volt_input_high_, // 4 68 | &vref_int_low_, // 5 69 | &vref_int_high_, // 6 70 | ¤t_input_low_, // 7 71 | ¤t_input_high_, // 8 72 | &motor_current_low_, // 9 73 | &motor_current_high_, // 10 74 | &temperature_uc_low_, // 11 75 | &temperature_uc_high_, // 12 76 | &temperature_coil_low_, // 13 77 | &temperature_coil_high_, // 14 78 | }; 79 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 80 | } 81 | 82 | private: 83 | static const uint8_t kSubFaultNow = 0; 84 | static const uint8_t kSubFaultEver = 1; 85 | static const uint8_t kSubFaultLatching = 2; 86 | static const uint8_t kSubVoltInputLow = 3; 87 | static const uint8_t kSubVoltInputHigh = 4; 88 | static const uint8_t kSubVrefIntLow = 5; 89 | static const uint8_t kSubVrefIntHigh = 6; 90 | static const uint8_t kSubCurrentInputLow = 7; 91 | static const uint8_t kSubCurrentInputHigh = 8; 92 | static const uint8_t kSubMotorCurrentLow = 9; 93 | static const uint8_t kSubMotorCurrentHigh = 10; 94 | static const uint8_t kSubTemperatureUcLow = 11; 95 | static const uint8_t kSubTemperatureUcHigh = 12; 96 | static const uint8_t kSubTemperatureCoilLow = 13; 97 | static const uint8_t kSubTemperatureCoilHigh = 14; 98 | }; 99 | 100 | #endif /* POWER_SAFETY_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/iquart_flight_controller_interface_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: iquart_flight_controller_interface_client.hpp 11 | Last update: 2023/04/19 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef IQUART_FLIGHT_CONTROLLER_INTERFACE_CLIENT_HPP_ 17 | #define IQUART_FLIGHT_CONTROLLER_INTERFACE_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | #define MAX_CONTROL_VALUES_PER_IFCI 16 22 | 23 | const uint8_t kTypeIQUartFlightControllerInterface = 88; 24 | 25 | /** 26 | * @brief A struct that holds the data from a received telemetry packet 27 | * 28 | */ 29 | struct __attribute__ ((__packed__)) IFCITelemetryData{ 30 | int16_t mcu_temp; //centi ℃ 31 | int16_t coil_temp; //centi ℃ 32 | int16_t voltage; //cV 33 | int16_t current; //cA 34 | int16_t consumption; //mAh 35 | int16_t speed; //rad/s 36 | uint32_t uptime; //s 37 | }; 38 | 39 | /** 40 | * @brief A struct that can be used to more easily send an IFCI packed command message 41 | * 42 | */ 43 | struct __attribute__ ((__packed__)) IFCIPackedMessage{ 44 | uint16_t commands[MAX_CONTROL_VALUES_PER_IFCI]; //An array to hold all control values 45 | uint8_t telem_byte; //The module ID to send back its telemetry 46 | uint8_t num_cvs; //The number of control values being sent in this command 47 | }; 48 | 49 | class IQUartFlightControllerInterfaceClient : public ClientAbstract { 50 | public: 51 | IQUartFlightControllerInterfaceClient(uint8_t obj_idn, uint8_t * data_buf = nullptr) 52 | : ClientAbstract(kTypeIQUartFlightControllerInterface, obj_idn), 53 | packed_command_(kTypeIQUartFlightControllerInterface, obj_idn, kSubPackedCommand, data_buf), 54 | telemetry_(kTypeIQUartFlightControllerInterface, obj_idn, kSubTelemetry), 55 | throttle_cvi_(kTypeIQUartFlightControllerInterface, obj_idn, kSubThrottleCvi), 56 | x_cvi_(kTypeIQUartFlightControllerInterface, obj_idn, kSubXCvi), 57 | y_cvi_(kTypeIQUartFlightControllerInterface, obj_idn, kSubYCvi){}; 58 | 59 | // Client Entries 60 | PackedClientEntry packed_command_; 61 | ClientEntry telemetry_; 62 | ClientEntry throttle_cvi_; 63 | ClientEntry x_cvi_; 64 | ClientEntry y_cvi_; 65 | 66 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 67 | static const uint8_t kEntryLength = kSubYCvi + 1; 68 | ClientEntryAbstract* entry_array[kEntryLength] = { 69 | &packed_command_, // 0 70 | &telemetry_, // 1 71 | &throttle_cvi_, // 2 72 | &x_cvi_, // 3 73 | &y_cvi_ // 4 74 | }; 75 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 76 | } 77 | 78 | /** 79 | * @brief This function takes in an IFCIPackedMessage struct, and prepares the data as a series of bytes ready for transmission over IQUART 80 | * As an example, assume you want to send 4 throttle commands, and get telemetry from Module ID 3. To do so, make an IFCIPackedMessage and set 81 | * commands[0] through commands[3] to throttle values [0, 65535], telem_byte to 3, and num_cvs to 4. Then, create a byte array, and a byte to store the 82 | * message length, and call this function. 83 | * 84 | * @param ifci_commands The IFCIPackedMessage struct that you want to send 85 | * @param output_data A pointer to an array of bytes that will store the data 86 | * @param output_data_length The length of the data stored in the output_data array 87 | */ 88 | void PackageIfciCommandsForTransmission(IFCIPackedMessage * ifci_commands, uint8_t * output_data, uint8_t * output_data_length){ 89 | //Copy the CV bytes 90 | memcpy(output_data, ifci_commands->commands, ifci_commands->num_cvs * 2); 91 | 92 | //Add the telem byte 93 | output_data[ifci_commands->num_cvs * 2] = ifci_commands->telem_byte; 94 | 95 | //Set the output data length 96 | *output_data_length = ifci_commands->num_cvs * 2 + 1; 97 | } 98 | 99 | private: 100 | static const uint8_t kSubPackedCommand = 0; 101 | static const uint8_t kSubTelemetry = 1; 102 | static const uint8_t kSubThrottleCvi = 2; 103 | static const uint8_t kSubXCvi = 3; 104 | static const uint8_t kSubYCvi = 4; 105 | }; 106 | 107 | #endif /* IQUART_FLIGHT_CONTROLLER_INTERFACE_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/motor_model_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: motor_model_client.hpp 11 | Last update: 2025-03-11 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef MOTOR_MODEL_CLIENT_HPP_ 17 | #define MOTOR_MODEL_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeMotorModel = 98; 22 | 23 | class MotorModelClient : public ClientAbstract { 24 | public: 25 | MotorModelClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeMotorModel, obj_idn), 27 | mechanical_inductance_(kTypeMotorModel, obj_idn, kSubMechanicalInductance), 28 | mechanical_velocity_(kTypeMotorModel, obj_idn, kSubMechanicalVelocity), 29 | mechanical_ke_at_20c_(kTypeMotorModel, obj_idn, kSubMechanicalKeAt20c), 30 | mechanical_ke_(kTypeMotorModel, obj_idn, kSubMechanicalKe), 31 | coil_resistance_at_20c_(kTypeMotorModel, obj_idn, kSubCoilResistanceAt20c), 32 | coil_resistance_(kTypeMotorModel, obj_idn, kSubCoilResistance), 33 | additional_resistance_(kTypeMotorModel, obj_idn, kSubAdditionalResistance), 34 | effective_resistance_(kTypeMotorModel, obj_idn, kSubEffectiveResistance), 35 | pole_pairs_(kTypeMotorModel, obj_idn, kSubPolePairs), 36 | lead_time_(kTypeMotorModel, obj_idn, kSubLeadTime), 37 | permute_wires_(kTypeMotorModel, obj_idn, kSubPermuteWires), 38 | calibration_angle_(kTypeMotorModel, obj_idn, kSubCalibrationAngle), 39 | lead_angle_(kTypeMotorModel, obj_idn, kSubLeadAngle), 40 | back_emf_(kTypeMotorModel, obj_idn, kSubBackEmf), 41 | encoder_angle_(kTypeMotorModel, obj_idn, kSubEncoderAngle), 42 | coil_temperature_(kTypeMotorModel, obj_idn, kSubCoilTemperature), 43 | mechanical_acceleration_(kTypeMotorModel, obj_idn, kSubMechanicalAcceleration) 44 | {}; 45 | 46 | // Client Entries 47 | ClientEntry mechanical_inductance_; 48 | ClientEntry mechanical_velocity_; 49 | ClientEntry mechanical_ke_at_20c_; 50 | ClientEntry mechanical_ke_; 51 | ClientEntry coil_resistance_at_20c_; 52 | ClientEntry coil_resistance_; 53 | ClientEntry additional_resistance_; 54 | ClientEntry effective_resistance_; 55 | ClientEntry pole_pairs_; 56 | ClientEntry lead_time_; 57 | ClientEntry permute_wires_; 58 | ClientEntry calibration_angle_; 59 | ClientEntry lead_angle_; 60 | ClientEntry back_emf_; 61 | ClientEntry encoder_angle_; 62 | ClientEntry coil_temperature_; 63 | ClientEntry mechanical_acceleration_; 64 | 65 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 66 | static const uint8_t kEntryLength = kSubMechanicalAcceleration + 1; 67 | ClientEntryAbstract* entry_array[kEntryLength] = { 68 | &mechanical_inductance_, // 0 69 | &mechanical_velocity_, // 1 70 | &mechanical_ke_at_20c_, // 2 71 | &mechanical_ke_, // 3 72 | &coil_resistance_at_20c_, // 4 73 | &coil_resistance_, // 5 74 | &additional_resistance_, // 6 75 | &effective_resistance_, // 7 76 | &pole_pairs_, // 8 77 | &lead_time_, // 9 78 | &permute_wires_, // 10 79 | &calibration_angle_, // 11 80 | &lead_angle_, // 12 81 | &back_emf_, // 13 82 | &encoder_angle_, // 14 83 | &coil_temperature_, // 15 84 | &mechanical_acceleration_, // 16 85 | }; 86 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 87 | } 88 | 89 | private: 90 | static const uint8_t kSubMechanicalInductance = 0; 91 | static const uint8_t kSubMechanicalVelocity = 1; 92 | static const uint8_t kSubMechanicalKeAt20c = 2; 93 | static const uint8_t kSubMechanicalKe = 3; 94 | static const uint8_t kSubCoilResistanceAt20c = 4; 95 | static const uint8_t kSubCoilResistance = 5; 96 | static const uint8_t kSubAdditionalResistance = 6; 97 | static const uint8_t kSubEffectiveResistance = 7; 98 | static const uint8_t kSubPolePairs = 8; 99 | static const uint8_t kSubLeadTime = 9; 100 | static const uint8_t kSubPermuteWires = 10; 101 | static const uint8_t kSubCalibrationAngle = 11; 102 | static const uint8_t kSubLeadAngle = 12; 103 | static const uint8_t kSubBackEmf = 13; 104 | static const uint8_t kSubEncoderAngle = 14; 105 | static const uint8_t kSubCoilTemperature = 15; 106 | static const uint8_t kSubMechanicalAcceleration = 16; 107 | 108 | }; 109 | 110 | #endif /* MOTOR_MODEL_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/motor_driver_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: motor_driver_client.hpp 11 | Last update: 2025-03-11 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef MOTOR_DRIVER_CLIENT_HPP_ 17 | #define MOTOR_DRIVER_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeMotorDriver = 96; 22 | 23 | class MotorDriverClient : public ClientAbstract { 24 | public: 25 | MotorDriverClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeMotorDriver, obj_idn), 27 | rotor_magnitude_(kTypeMotorDriver, obj_idn, kSubRotorMagnitude), 28 | rotor_angle_(kTypeMotorDriver, obj_idn, kSubRotorAngle), 29 | final_rotor_magnitude_(kTypeMotorDriver, obj_idn, kSubFinalRotorMagnitude), 30 | final_rotor_angle_(kTypeMotorDriver, obj_idn, kSubFinalRotorAngle), 31 | direct_stator_magnitude_(kTypeMotorDriver, obj_idn, kSubDirectStatorMagnitude), 32 | direct_stator_angle_(kTypeMotorDriver, obj_idn, kSubDirectStatorAngle), 33 | stator_magnitude_(kTypeMotorDriver, obj_idn, kSubStatorMagnitude), 34 | stator_electrical_angle_(kTypeMotorDriver, obj_idn, kSubStatorElectricalAngle), 35 | pwm_(kTypeMotorDriver, obj_idn, kSubPwm), 36 | coast_(kTypeMotorDriver, obj_idn, kSubCoast), 37 | brake_(kTypeMotorDriver, obj_idn, kSubBrake), 38 | set_apply_target_mode_(kTypeMotorDriver, obj_idn, kSubSetApplyTargetMode), 39 | set_apply_direct_stator_sv_mode_(kTypeMotorDriver, obj_idn, kSubSetApplyDirectStatorSvMode), 40 | driver_mode_(kTypeMotorDriver, obj_idn, kSubDriverMode), 41 | additional_drive_volts_(kTypeMotorDriver, obj_idn, kSubAdditionalDriveVolts), 42 | estimated_motor_amps_(kTypeMotorDriver, obj_idn, kSubEstimatedMotorAmps), 43 | commutation_hz_(kTypeMotorDriver, obj_idn, kSubCommutationHz) 44 | {}; 45 | 46 | // Client Entries 47 | ClientEntry rotor_magnitude_; 48 | ClientEntry rotor_angle_; 49 | ClientEntry final_rotor_magnitude_; 50 | ClientEntry final_rotor_angle_; 51 | ClientEntry direct_stator_magnitude_; 52 | ClientEntry direct_stator_angle_; 53 | ClientEntry stator_magnitude_; 54 | ClientEntry stator_electrical_angle_; 55 | ClientEntry pwm_; 56 | ClientEntryVoid coast_; 57 | ClientEntryVoid brake_; 58 | ClientEntryVoid set_apply_target_mode_; 59 | ClientEntryVoid set_apply_direct_stator_sv_mode_; 60 | ClientEntry driver_mode_; 61 | ClientEntry additional_drive_volts_; 62 | ClientEntry estimated_motor_amps_; 63 | ClientEntry commutation_hz_; 64 | 65 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 66 | static const uint8_t kEntryLength = kSubCommutationHz + 1; 67 | ClientEntryAbstract* entry_array[kEntryLength] = { 68 | &rotor_magnitude_, // 0 69 | &rotor_angle_, // 1 70 | &final_rotor_magnitude_, // 2 71 | &final_rotor_angle_, // 3 72 | &direct_stator_magnitude_, // 4 73 | &direct_stator_angle_, // 5 74 | &stator_magnitude_, // 6 75 | &stator_electrical_angle_, // 7 76 | &pwm_, // 8 77 | &coast_, // 9 78 | &brake_, // 10 79 | &set_apply_target_mode_, // 11 80 | &set_apply_direct_stator_sv_mode_, // 12 81 | &driver_mode_, // 13 82 | &additional_drive_volts_, // 14 83 | &estimated_motor_amps_, // 15 84 | &commutation_hz_, // 16 85 | }; 86 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 87 | } 88 | 89 | private: 90 | static const uint8_t kSubRotorMagnitude = 0; 91 | static const uint8_t kSubRotorAngle = 1; 92 | static const uint8_t kSubFinalRotorMagnitude = 2; 93 | static const uint8_t kSubFinalRotorAngle = 3; 94 | static const uint8_t kSubDirectStatorMagnitude = 4; 95 | static const uint8_t kSubDirectStatorAngle = 5; 96 | static const uint8_t kSubStatorMagnitude = 6; 97 | static const uint8_t kSubStatorElectricalAngle = 7; 98 | static const uint8_t kSubPwm = 8; 99 | static const uint8_t kSubCoast = 9; 100 | static const uint8_t kSubBrake = 10; 101 | static const uint8_t kSubSetApplyTargetMode = 11; 102 | static const uint8_t kSubSetApplyDirectStatorSvMode = 12; 103 | static const uint8_t kSubDriverMode = 13; 104 | static const uint8_t kSubAdditionalDriveVolts = 14; 105 | static const uint8_t kSubEstimatedMotorAmps = 15; 106 | static const uint8_t kSubCommutationHz = 16; 107 | 108 | }; 109 | 110 | #endif /* MOTOR_DRIVER_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /tests/fortiq_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This example C++ program uses the Power Monitor client to retrieve the Voltage of a motor. 3 | * The serial port setup for windows is based on the example provided by microsoft: 4 | * https://learn.microsoft.com/en-us/windows/win32/devio/configuring-a-communications-resource 5 | * 6 | * Name: fortiq_test.cpp 7 | * Last update: 2023/04/18 by Ben Quan 8 | * Author: Ben Quan and Jordan Leiber 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include "../inc/adc_interface_client.hpp" 17 | #include "../inc/client_communication.cpp" 18 | #include "../inc/client_communication.hpp" 19 | #include "../inc/generic_interface.hpp" 20 | #include "../inc/gpio_controller_client.hpp" 21 | #include "../inc/power_monitor_client.hpp" 22 | #include "../inc/pwm_interface_client.hpp" 23 | 24 | using namespace std; 25 | 26 | HANDLE com_port; // Handler for COM port 27 | TCHAR *pcCommPort = TEXT("COM3"); // Change COM4 to whichever port your motor is connected to 28 | GenericInterface com; // Interface used by com port to communicate with motor 29 | 30 | PowerMonitorClient power(0); // Client endpoint for voltage reading 31 | GpioControllerClient gpio(0); 32 | PwmInterfaceClient pwm(0); 33 | AdcInterfaceClient adc(0); 34 | 35 | // Send out any message data we have over the serial interface 36 | int handle_com_tx() { 37 | uint8_t packet_buf[64]; 38 | uint8_t length = 0; 39 | DWORD bytes_written; 40 | 41 | // Get the packet from the com interface and place it into the packet buffer 42 | if (com.GetTxBytes(packet_buf, length)) { 43 | WriteFile(com_port, packet_buf, length, &bytes_written, NULL); 44 | } 45 | 46 | return bytes_written; 47 | } 48 | 49 | // Grab any received data on the serial interface 50 | int handle_com_rx() { 51 | uint8_t recv_bytes[64]; 52 | DWORD dwBytesReceived; 53 | 54 | ReadFile(com_port, &recv_bytes, 64, &dwBytesReceived, 0); 55 | com.SetRxBytes(recv_bytes, dwBytesReceived); 56 | 57 | return dwBytesReceived; 58 | } 59 | 60 | // Hand off any received data to each module so they can handle it 61 | void update_modules() { 62 | // Temporary Pointer to the packet data location 63 | uint8_t *packet_data; 64 | uint8_t packet_length; 65 | 66 | // Loads the packet data buffer with data receieved from the motor 67 | while (com.PeekPacket(&packet_data, &packet_length)) { 68 | power.ReadMsg(packet_data, packet_length); 69 | gpio.ReadMsg(packet_data, packet_length); 70 | pwm.ReadMsg(packet_data, packet_length); 71 | adc.ReadMsg(packet_data, packet_length); 72 | com.DropPacket(); 73 | } 74 | } 75 | 76 | // Handles communication with motor 77 | void send_message_and_process_reply() { 78 | handle_com_tx(); 79 | handle_com_rx(); 80 | update_modules(); 81 | } 82 | 83 | // Sends the command to motor to get Voltage 84 | float get_voltage() { 85 | power.volts_.get(com); 86 | send_message_and_process_reply(); 87 | return power.volts_.get_reply(); 88 | } 89 | 90 | void set_gpio_outputs() {} 91 | 92 | int main() { 93 | com_port = CreateFile(pcCommPort, GENERIC_READ | GENERIC_WRITE, 94 | 0, // must be opened with exclusive-access 95 | NULL, // default security attributes 96 | OPEN_EXISTING, // must use OPEN_EXISTING 97 | 0, // not overlapped I/O 98 | NULL); // hTemplate must be NULL for comm devices 99 | 100 | cout << com_port << endl; 101 | 102 | if (com_port == INVALID_HANDLE_VALUE) 103 | cout << "Error in opening serial port" << endl; 104 | else 105 | cout << "opening serial port successful" << endl; 106 | 107 | DCB dcb = {0}; // Device-control block used to configure serial communications 108 | dcb.DCBlength = sizeof(DCB); 109 | GetCommState(com_port, &dcb); 110 | dcb.BaudRate = CBR_115200; // Set baud rate to 115200 111 | dcb.ByteSize = 8; 112 | SetCommState(com_port, &dcb); 113 | 114 | // Set up a read timeout 115 | COMMTIMEOUTS timeouts; 116 | GetCommTimeouts(com_port, &timeouts); 117 | timeouts.ReadIntervalTimeout = 5; 118 | SetCommTimeouts(com_port, &timeouts); 119 | 120 | // Get and print the current Voltage reading of the motor 121 | float current_voltage = get_voltage(); 122 | cout << "voltage: " << to_string(current_voltage) << endl; 123 | 124 | gpio.outputs_register_.set(com, 2); 125 | gpio.outputs_register_.get(com); 126 | send_message_and_process_reply(); 127 | cout << "gpio outputs: " << to_string(gpio.outputs_register_.get_reply()) << endl; 128 | 129 | pwm.duty_cycle_.set(com, 50); 130 | pwm.duty_cycle_.get(com); 131 | send_message_and_process_reply(); 132 | cout << "duty cycle: " << to_string(pwm.duty_cycle_.get_reply()) << endl; 133 | 134 | gpio.addressable_outputs_.set(com, 131); 135 | 136 | adc.adc_voltage_.get(com); 137 | send_message_and_process_reply(); 138 | cout << "adc volts: " << to_string(adc.adc_voltage_.get_reply()) << endl; 139 | 140 | return 0; 141 | } -------------------------------------------------------------------------------- /inc/arming_handler_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: arming_handler_client.hpp 11 | Last update: 2025-08-22 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef ARMING_HANDLER_CLIENT_HPP_ 17 | #define ARMING_HANDLER_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeArmingHandler = 86; 22 | 23 | class ArmingHandlerClient : public ClientAbstract { 24 | public: 25 | ArmingHandlerClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeArmingHandler, obj_idn), 27 | always_armed_(kTypeArmingHandler, obj_idn, kSubAlwaysArmed), 28 | arm_on_throttle_(kTypeArmingHandler, obj_idn, kSubArmOnThrottle), 29 | arm_throttle_upper_limit_(kTypeArmingHandler, obj_idn, kSubArmThrottleUpperLimit), 30 | arm_throttle_lower_limit_(kTypeArmingHandler, obj_idn, kSubArmThrottleLowerLimit), 31 | disarm_on_throttle_(kTypeArmingHandler, obj_idn, kSubDisarmOnThrottle), 32 | disarm_throttle_upper_limit_(kTypeArmingHandler, obj_idn, kSubDisarmThrottleUpperLimit), 33 | disarm_throttle_lower_limit_(kTypeArmingHandler, obj_idn, kSubDisarmThrottleLowerLimit), 34 | consecutive_arming_throttles_to_arm_(kTypeArmingHandler, obj_idn, 35 | kSubConsecutiveArmingThrottlesToArm), 36 | disarm_behavior_(kTypeArmingHandler, obj_idn, kSubDisarmBehavior), 37 | disarm_song_option_(kTypeArmingHandler, obj_idn, kSubDisarmSongOption), 38 | manual_arming_throttle_source_(kTypeArmingHandler, obj_idn, kSubManualArmingThrottleSource), 39 | motor_armed_(kTypeArmingHandler, obj_idn, kSubMotorArmed), 40 | consecutive_disarming_throttles_to_disarm_(kTypeArmingHandler, obj_idn, kSubConsecutiveDisarmingThrottlesToDisarm), 41 | play_arming_song_on_arm_(kTypeArmingHandler, obj_idn, kSubPlayArmingSongOnArm){}; 42 | 43 | // Client Entries 44 | ClientEntry always_armed_; 45 | ClientEntry arm_on_throttle_; 46 | ClientEntry arm_throttle_upper_limit_; 47 | ClientEntry arm_throttle_lower_limit_; 48 | ClientEntry disarm_on_throttle_; 49 | ClientEntry disarm_throttle_upper_limit_; 50 | ClientEntry disarm_throttle_lower_limit_; 51 | ClientEntry consecutive_arming_throttles_to_arm_; 52 | ClientEntry disarm_behavior_; 53 | ClientEntry disarm_song_option_; 54 | ClientEntry manual_arming_throttle_source_; 55 | ClientEntry motor_armed_; 56 | ClientEntry consecutive_disarming_throttles_to_disarm_; 57 | ClientEntry play_arming_song_on_arm_; 58 | 59 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 60 | static const uint8_t kEntryLength = kSubPlayArmingSongOnArm + 1; 61 | ClientEntryAbstract* entry_array[kEntryLength] = { 62 | nullptr, // 0 63 | &always_armed_, // 1 64 | &arm_on_throttle_, // 2 65 | &arm_throttle_upper_limit_, // 3 66 | &arm_throttle_lower_limit_, // 4 67 | &disarm_on_throttle_, // 5 68 | &disarm_throttle_upper_limit_, // 6 69 | &disarm_throttle_lower_limit_, // 7 70 | &consecutive_arming_throttles_to_arm_, // 8 71 | &disarm_behavior_, // 9 72 | &disarm_song_option_, // 10 73 | &manual_arming_throttle_source_, // 11 74 | &motor_armed_, // 12 75 | &consecutive_disarming_throttles_to_disarm_,// 13 76 | &play_arming_song_on_arm_ // 14 77 | }; 78 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 79 | } 80 | 81 | private: 82 | static const uint8_t kSubAlwaysArmed = 1; 83 | static const uint8_t kSubArmOnThrottle = 2; 84 | static const uint8_t kSubArmThrottleUpperLimit = 3; 85 | static const uint8_t kSubArmThrottleLowerLimit = 4; 86 | static const uint8_t kSubDisarmOnThrottle = 5; 87 | static const uint8_t kSubDisarmThrottleUpperLimit = 6; 88 | static const uint8_t kSubDisarmThrottleLowerLimit = 7; 89 | static const uint8_t kSubConsecutiveArmingThrottlesToArm = 8; 90 | static const uint8_t kSubDisarmBehavior = 9; 91 | static const uint8_t kSubDisarmSongOption = 10; 92 | static const uint8_t kSubManualArmingThrottleSource = 11; 93 | static const uint8_t kSubMotorArmed = 12; 94 | static const uint8_t kSubConsecutiveDisarmingThrottlesToDisarm = 13; 95 | static const uint8_t kSubPlayArmingSongOnArm = 14; 96 | }; 97 | 98 | #endif /* ARMING_HANDLER_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/voltage_superposition_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: voltage_superposition_client.hpp 11 | Last update: 2023/04/19 by Ben Quan 12 | Author: Luca Scheuer 13 | Contributors: Ben Quan, Luca Scheuer 14 | */ 15 | 16 | #ifndef COMMON_CPP_INC_VOLTAGE_SUPERPOSITION_CLIENT_HPP_ 17 | #define COMMON_CPP_INC_VOLTAGE_SUPERPOSITION_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | #include "communication_interface.h" 21 | 22 | const uint8_t kTypeVoltageSuperposition = 74; 23 | 24 | class VoltageSuperPositionClient : public ClientAbstract { 25 | public: 26 | VoltageSuperPositionClient(uint8_t obj_idn) 27 | : ClientAbstract(kTypeVoltageSuperposition, obj_idn), 28 | zero_angle_(kTypeVoltageSuperposition, obj_idn, kSubZeroAngle), 29 | frequency_(kTypeVoltageSuperposition, obj_idn, kSubFrequency), 30 | phase_(kTypeVoltageSuperposition, obj_idn, kSubPhase), 31 | amplitude_(kTypeVoltageSuperposition, obj_idn, kSubAmplitude), 32 | voltage_(kTypeVoltageSuperposition, obj_idn, kSubVoltage), 33 | max_allowed_amplitude_(kTypeVoltageSuperposition, obj_idn, kSubMaxAllowedAmplitude), 34 | velocity_cutoff_(kTypeVoltageSuperposition, obj_idn, kSubVelocityCutoff), 35 | poly_limit_zero_(kTypeVoltageSuperposition, obj_idn, kSubPolyLimitZero), 36 | poly_limit_one_(kTypeVoltageSuperposition, obj_idn, kSubPolyLimitOne), 37 | poly_limit_two_(kTypeVoltageSuperposition, obj_idn, kSubPolyLimitTwo), 38 | poly_limit_three_(kTypeVoltageSuperposition, obj_idn, kSubPolyLimitThree), 39 | phase_lead_time_(kTypeVoltageSuperposition, obj_idn, kSubPhaseLeadTime), 40 | phase_lead_angle_(kTypeVoltageSuperposition, obj_idn, kSubPhaseLeadAngle), 41 | phase_act_(kTypeVoltageSuperposition, obj_idn, kSubPhaseActual), 42 | amplitude_act_(kTypeVoltageSuperposition, obj_idn, kSubAmplitudeActual), 43 | sample_mechanical_zero_(kTypeVoltageSuperposition, obj_idn, kSubSampleMechanicalZero), 44 | propeller_torque_offset_angle_(kTypeVoltageSuperposition, obj_idn, 45 | kSubPropellerTorqueOffsetAngle){}; 46 | 47 | // Client Entries 48 | ClientEntry zero_angle_; 49 | ClientEntry frequency_; 50 | ClientEntry phase_; 51 | ClientEntry amplitude_; 52 | ClientEntry voltage_; 53 | ClientEntry max_allowed_amplitude_; 54 | ClientEntry velocity_cutoff_; 55 | ClientEntry poly_limit_zero_; 56 | ClientEntry poly_limit_one_; 57 | ClientEntry poly_limit_two_; 58 | ClientEntry poly_limit_three_; 59 | ClientEntry phase_lead_time_; 60 | ClientEntry phase_lead_angle_; 61 | ClientEntry phase_act_; 62 | ClientEntry amplitude_act_; 63 | ClientEntryVoid sample_mechanical_zero_; 64 | ClientEntry propeller_torque_offset_angle_; 65 | 66 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) override { 67 | static const uint8_t kEntryLength = kSubPropellerTorqueOffsetAngle + 1; 68 | ClientEntryAbstract* entry_array[kEntryLength] = { 69 | &zero_angle_, // 0 70 | &frequency_, // 1 71 | &phase_, // 2 72 | &litude_, // 3 73 | &voltage_, // 4 74 | &max_allowed_amplitude_, // 5 75 | &velocity_cutoff_, // 6 76 | &poly_limit_zero_, // 7 77 | &poly_limit_one_, // 8 78 | &poly_limit_two_, // 9 79 | &poly_limit_three_, // 10 80 | &phase_lead_time_, // 11 81 | &phase_lead_angle_, // 12 82 | &phase_act_, // 13 83 | &litude_act_, // 14 84 | &sample_mechanical_zero_, // 15 85 | &propeller_torque_offset_angle_ // 16 86 | 87 | }; 88 | 89 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 90 | } 91 | 92 | private: 93 | static const uint8_t kSubZeroAngle = 0; 94 | static const uint8_t kSubFrequency = 1; 95 | static const uint8_t kSubPhase = 2; 96 | static const uint8_t kSubAmplitude = 3; 97 | static const uint8_t kSubVoltage = 4; 98 | static const uint8_t kSubMaxAllowedAmplitude = 5; 99 | static const uint8_t kSubVelocityCutoff = 6; 100 | static const uint8_t kSubPolyLimitZero = 7; 101 | static const uint8_t kSubPolyLimitOne = 8; 102 | static const uint8_t kSubPolyLimitTwo = 9; 103 | static const uint8_t kSubPolyLimitThree = 10; 104 | static const uint8_t kSubPhaseLeadTime = 11; 105 | static const uint8_t kSubPhaseLeadAngle = 12; 106 | static const uint8_t kSubPhaseActual = 13; 107 | static const uint8_t kSubAmplitudeActual = 14; 108 | static const uint8_t kSubSampleMechanicalZero = 15; 109 | static const uint8_t kSubPropellerTorqueOffsetAngle = 16; 110 | }; 111 | 112 | #endif -------------------------------------------------------------------------------- /inc/propeller_motor_control_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: propeller_motor_control_client.hpp 11 | Last update: 2025-08-26 by Ben Quan 12 | Author: Matthew Piccoli 13 | Contributors: Ben Quan, Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef PROPELLER_MOTOR_CONTROL_CLIENT_HPP_ 17 | #define PROPELLER_MOTOR_CONTROL_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypePropellerMotorControl = 52; 22 | 23 | class PropellerMotorControlClient : public ClientAbstract { 24 | public: 25 | PropellerMotorControlClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypePropellerMotorControl, obj_idn), 27 | ctrl_mode_(kTypePropellerMotorControl, obj_idn, kSubCtrlMode), 28 | ctrl_brake_(kTypePropellerMotorControl, obj_idn, kSubCtrlBrake), 29 | ctrl_coast_(kTypePropellerMotorControl, obj_idn, kSubCtrlCoast), 30 | ctrl_pwm_(kTypePropellerMotorControl, obj_idn, kSubCtrlPwm), 31 | ctrl_volts_(kTypePropellerMotorControl, obj_idn, kSubCtrlVolts), 32 | ctrl_velocity_(kTypePropellerMotorControl, obj_idn, kSubCtrlVelocity), 33 | velocity_kp_(kTypePropellerMotorControl, obj_idn, kSubVelocityKp), 34 | velocity_ki_(kTypePropellerMotorControl, obj_idn, kSubVelocityKi), 35 | velocity_kd_(kTypePropellerMotorControl, obj_idn, kSubVelocityKd), 36 | velocity_ff0_(kTypePropellerMotorControl, obj_idn, kSubVelocityFF0), 37 | velocity_ff1_(kTypePropellerMotorControl, obj_idn, kSubVelocityFF1), 38 | velocity_ff2_(kTypePropellerMotorControl, obj_idn, kSubVelocityFF2), 39 | timeout_(kTypePropellerMotorControl, obj_idn, kSubTimeout), 40 | input_filter_fc_(kTypePropellerMotorControl, obj_idn, kSubInputFilterFc), 41 | timeout_meaning_(kTypePropellerMotorControl, obj_idn, kSubTimeoutMeaning), 42 | timeout_behavior_(kTypePropellerMotorControl, obj_idn, kSubTimeoutBehavior), 43 | timeout_song_option_(kTypePropellerMotorControl, obj_idn, kSubTimeoutSongOption), 44 | additional_velocity_(kTypePropellerMotorControl, obj_idn, kSubAdditionalVelocity){}; 45 | 46 | // Client Entries 47 | // Control commands 48 | ClientEntry ctrl_mode_; 49 | ClientEntryVoid ctrl_brake_; 50 | ClientEntryVoid ctrl_coast_; 51 | ClientEntry ctrl_pwm_; 52 | ClientEntry ctrl_volts_; 53 | ClientEntry ctrl_velocity_; 54 | // Velocity control 55 | ClientEntry velocity_kp_; 56 | ClientEntry velocity_ki_; 57 | ClientEntry velocity_kd_; 58 | ClientEntry velocity_ff0_; 59 | ClientEntry velocity_ff1_; 60 | ClientEntry velocity_ff2_; 61 | // Timeout 62 | ClientEntry timeout_; 63 | // Filter 64 | ClientEntry input_filter_fc_; 65 | ClientEntry timeout_meaning_; 66 | ClientEntry timeout_behavior_; 67 | ClientEntry timeout_song_option_; 68 | //Additional Velocity 69 | ClientEntry additional_velocity_; 70 | 71 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 72 | static const uint8_t kEntryLength = kSubAdditionalVelocity + 1; 73 | ClientEntryAbstract* entry_array[kEntryLength] = { 74 | &ctrl_mode_, // 0 75 | &ctrl_brake_, // 1 76 | &ctrl_coast_, // 2 77 | &ctrl_pwm_, // 3 78 | &ctrl_volts_, // 4 79 | &ctrl_velocity_, // 5 80 | nullptr, // 6 81 | &velocity_kp_, // 7 82 | &velocity_ki_, // 8 83 | &velocity_kd_, // 9 84 | &velocity_ff0_, // 10 85 | &velocity_ff1_, // 11 86 | &velocity_ff2_, // 12 87 | nullptr, // 13 88 | nullptr, // 14 89 | &timeout_, // 15 90 | &input_filter_fc_, // 16 91 | &timeout_meaning_, // 17 92 | &timeout_behavior_, // 18 93 | &timeout_song_option_, // 19 94 | &additional_velocity_ // 20 95 | }; 96 | 97 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 98 | } 99 | 100 | private: 101 | static const uint8_t kSubCtrlMode = 0; 102 | static const uint8_t kSubCtrlBrake = 1; 103 | static const uint8_t kSubCtrlCoast = 2; 104 | static const uint8_t kSubCtrlPwm = 3; 105 | static const uint8_t kSubCtrlVolts = 4; 106 | static const uint8_t kSubCtrlVelocity = 5; 107 | static const uint8_t kSubVelocityKp = 7; 108 | static const uint8_t kSubVelocityKi = 8; 109 | static const uint8_t kSubVelocityKd = 9; 110 | static const uint8_t kSubVelocityFF0 = 10; 111 | static const uint8_t kSubVelocityFF1 = 11; 112 | static const uint8_t kSubVelocityFF2 = 12; 113 | static const uint8_t kSubTimeout = 15; 114 | static const uint8_t kSubInputFilterFc = 16; 115 | static const uint8_t kSubTimeoutMeaning = 17; 116 | static const uint8_t kSubTimeoutBehavior = 18; 117 | static const uint8_t kSubTimeoutSongOption = 19; 118 | static const uint8_t kSubAdditionalVelocity = 20; 119 | }; 120 | 121 | #endif /* PROPELLER_MOTOR_CONTROL_CLIENT_HPP_ */ 122 | -------------------------------------------------------------------------------- /inc/current_safeties_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2025 Vertiq, Inc support@vertiq.co 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: current_safeties_client.hpp 11 | Last update: 2025-03-11 by Ben Quan 12 | Author: Ben Quan 13 | Contributors: 14 | */ 15 | 16 | #ifndef CURRENT_SAFETIES_CLIENT_HPP_ 17 | #define CURRENT_SAFETIES_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeCurrentSafeties = 102; 22 | 23 | class CurrentSafetiesClient : public ClientAbstract { 24 | public: 25 | CurrentSafetiesClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeCurrentSafeties, obj_idn), 27 | final_max_current_derate_(kTypeCurrentSafeties, obj_idn, kSubFinalMaxCurrentDerate), 28 | base_max_current_(kTypeCurrentSafeties, obj_idn, kSubBaseMaxCurrent), 29 | derated_max_current_(kTypeCurrentSafeties, obj_idn, kSubDeratedMaxCurrent), 30 | speed_redline_start_(kTypeCurrentSafeties, obj_idn, kSubSpeedRedlineStart), 31 | speed_redline_end_(kTypeCurrentSafeties, obj_idn, kSubSpeedRedlineEnd), 32 | supply_voltage_max_start_(kTypeCurrentSafeties, obj_idn, kSubSupplyVoltageMaxStart), 33 | supply_voltage_max_end_(kTypeCurrentSafeties, obj_idn, kSubSupplyVoltageMaxEnd), 34 | motoring_supply_current_limit_enable_(kTypeCurrentSafeties, obj_idn, kSubMotoringSupplyCurrentLimitEnable), 35 | motoring_supply_current_max_start_(kTypeCurrentSafeties, obj_idn, kSubMotoringSupplyCurrentMaxStart), 36 | motoring_supply_current_max_end_(kTypeCurrentSafeties, obj_idn, kSubMotoringSupplyCurrentMaxEnd), 37 | regen_supply_current_limit_enable_(kTypeCurrentSafeties, obj_idn, kSubRegenSupplyCurrentLimitEnable), 38 | regen_supply_current_max_start_(kTypeCurrentSafeties, obj_idn, kSubRegenSupplyCurrentMaxStart), 39 | regen_supply_current_max_end_(kTypeCurrentSafeties, obj_idn, kSubRegenSupplyCurrentMaxEnd), 40 | final_q_current_target_(kTypeCurrentSafeties, obj_idn, kSubFinalQCurrentTarget), 41 | final_d_current_target_(kTypeCurrentSafeties, obj_idn, kSubFinalDCurrentTarget), 42 | supply_current_filter_fc_(kTypeCurrentSafeties, obj_idn, kSubSupplyCurrentFilterFc), 43 | current_slew_rate_limit_(kTypeCurrentSafeties, obj_idn, kSubCurrentSlewRateLimit), 44 | current_slew_rate_enable_(kTypeCurrentSafeties, obj_idn, kSubCurrentSlewRateEnable) 45 | {}; 46 | 47 | // Client Entries 48 | ClientEntry final_max_current_derate_; 49 | ClientEntry base_max_current_; 50 | ClientEntry derated_max_current_; 51 | ClientEntry speed_redline_start_; 52 | ClientEntry speed_redline_end_; 53 | ClientEntry supply_voltage_max_start_; 54 | ClientEntry supply_voltage_max_end_; 55 | ClientEntry motoring_supply_current_limit_enable_; 56 | ClientEntry motoring_supply_current_max_start_; 57 | ClientEntry motoring_supply_current_max_end_; 58 | ClientEntry regen_supply_current_limit_enable_; 59 | ClientEntry regen_supply_current_max_start_; 60 | ClientEntry regen_supply_current_max_end_; 61 | ClientEntry final_q_current_target_; 62 | ClientEntry final_d_current_target_; 63 | ClientEntry supply_current_filter_fc_; 64 | ClientEntry current_slew_rate_limit_; 65 | ClientEntry current_slew_rate_enable_; 66 | 67 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 68 | static const uint8_t kEntryLength = kSubCurrentSlewRateEnable + 1; 69 | ClientEntryAbstract* entry_array[kEntryLength] = { 70 | &final_max_current_derate_, // 0 71 | &base_max_current_, // 1 72 | &derated_max_current_, // 2 73 | &speed_redline_start_, // 3 74 | &speed_redline_end_, // 4 75 | &supply_voltage_max_start_, // 5 76 | &supply_voltage_max_end_, // 6 77 | &motoring_supply_current_limit_enable_, // 7 78 | &motoring_supply_current_max_start_, // 8 79 | &motoring_supply_current_max_end_, // 9 80 | ®en_supply_current_limit_enable_, // 10 81 | ®en_supply_current_max_start_, // 11 82 | ®en_supply_current_max_end_, // 12 83 | &final_q_current_target_, // 13 84 | &final_d_current_target_, // 14 85 | &supply_current_filter_fc_, // 15 86 | ¤t_slew_rate_limit_, // 16 87 | ¤t_slew_rate_enable_, // 17 88 | }; 89 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 90 | } 91 | 92 | private: 93 | static const uint8_t kSubFinalMaxCurrentDerate = 0; 94 | static const uint8_t kSubBaseMaxCurrent = 1; 95 | static const uint8_t kSubDeratedMaxCurrent = 2; 96 | static const uint8_t kSubSpeedRedlineStart = 3; 97 | static const uint8_t kSubSpeedRedlineEnd = 4; 98 | static const uint8_t kSubSupplyVoltageMaxStart = 5; 99 | static const uint8_t kSubSupplyVoltageMaxEnd = 6; 100 | static const uint8_t kSubMotoringSupplyCurrentLimitEnable = 7; 101 | static const uint8_t kSubMotoringSupplyCurrentMaxStart = 8; 102 | static const uint8_t kSubMotoringSupplyCurrentMaxEnd = 9; 103 | static const uint8_t kSubRegenSupplyCurrentLimitEnable = 10; 104 | static const uint8_t kSubRegenSupplyCurrentMaxStart = 11; 105 | static const uint8_t kSubRegenSupplyCurrentMaxEnd = 12; 106 | static const uint8_t kSubFinalQCurrentTarget = 13; 107 | static const uint8_t kSubFinalDCurrentTarget = 14; 108 | static const uint8_t kSubSupplyCurrentFilterFc = 15; 109 | static const uint8_t kSubCurrentSlewRateLimit = 16; 110 | static const uint8_t kSubCurrentSlewRateEnable = 17; 111 | 112 | }; 113 | 114 | #endif /* CURRENT_SAFETIES_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/coil_temperature_estimator_client.hpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Copyright 2023 IQinetics Technologies, Inc support@iq-control.com 4 | 5 | This file is part of the IQ C++ API. 6 | 7 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 8 | */ 9 | 10 | /* 11 | Name: coil_temperature_estimator_client.hpp 12 | Last update: 2023/04/12 by Ben Quan 13 | Author: Ben Quan 14 | Contributors: 15 | */ 16 | 17 | #ifndef COIL_TEMPERATURE_ESTIMATOR_CLIENT_HPP_ 18 | #define COIL_TEMPERATURE_ESTIMATOR_CLIENT_HPP_ 19 | 20 | #include "client_communication.hpp" 21 | 22 | const uint8_t kTypeCoilTemperatureEstimator = 83; 23 | 24 | class CoilTemperatureEstimatorClient : public ClientAbstract { 25 | public: 26 | CoilTemperatureEstimatorClient(uint8_t obj_idn) 27 | : ClientAbstract(kTypeCoilTemperatureEstimator, obj_idn), 28 | t_coil_(kTypeCoilTemperatureEstimator, obj_idn, kSubTCoil), 29 | t_alu_(kTypeCoilTemperatureEstimator, obj_idn, kSubTAlu), 30 | t_amb_(kTypeCoilTemperatureEstimator, obj_idn, kSubTAmb), 31 | h_coil_amb_free_conv_(kTypeCoilTemperatureEstimator, obj_idn, kSubHCoilAmbFreeConv), 32 | h_coil_stator_cond_(kTypeCoilTemperatureEstimator, obj_idn, kSubHCoilStatorCond), 33 | h_coil_amb_forced_conv_(kTypeCoilTemperatureEstimator, obj_idn, kSubHCoilAmbForcedConv), 34 | c_coil_(kTypeCoilTemperatureEstimator, obj_idn, kSubCCoil), 35 | h_coil_amb_forced_conv_coeff_(kTypeCoilTemperatureEstimator, obj_idn, kSubHCoilAmbForcedConvCoeff), 36 | otw_(kTypeCoilTemperatureEstimator, obj_idn, kSubOtw), 37 | otlo_(kTypeCoilTemperatureEstimator, obj_idn, kSubOtlo), 38 | derate_(kTypeCoilTemperatureEstimator, obj_idn, kSubDerate), 39 | q_coil_joule_(kTypeCoilTemperatureEstimator, obj_idn, kSubQCoilJoule), 40 | q_coil_amb_conv_(kTypeCoilTemperatureEstimator, obj_idn, kSubQCoilAmbConv), 41 | q_coil_stator_cond_(kTypeCoilTemperatureEstimator, obj_idn, kSubQCoilStatorCond), 42 | h_lam_alu_(kTypeCoilTemperatureEstimator, obj_idn, kSubHLamAlu), 43 | c_lam_(kTypeCoilTemperatureEstimator, obj_idn, kSubCLam), 44 | k_lam_hist_coeff_(kTypeCoilTemperatureEstimator, obj_idn, kSubKLamHistCoeff), 45 | q_lam_hist_(kTypeCoilTemperatureEstimator, obj_idn, kSubQLamHist), 46 | q_lam_alu_(kTypeCoilTemperatureEstimator, obj_idn, kSubQLamAlu), 47 | t_lam_(kTypeCoilTemperatureEstimator, obj_idn, kSubTLam){}; 48 | 49 | // Client Entries 50 | ClientEntry t_coil_; 51 | ClientEntry t_alu_; 52 | ClientEntry t_amb_; 53 | ClientEntry h_coil_amb_free_conv_; 54 | ClientEntry h_coil_stator_cond_; 55 | ClientEntry h_coil_amb_forced_conv_; 56 | ClientEntry c_coil_; 57 | ClientEntry h_coil_amb_forced_conv_coeff_; 58 | ClientEntry otw_; 59 | ClientEntry otlo_; 60 | ClientEntry derate_; 61 | ClientEntry q_coil_joule_; 62 | ClientEntry q_coil_amb_conv_; 63 | ClientEntry q_coil_stator_cond_; 64 | ClientEntry h_lam_alu_; 65 | ClientEntry c_lam_; 66 | ClientEntry k_lam_hist_coeff_; 67 | ClientEntry q_lam_hist_; 68 | ClientEntry q_lam_alu_; 69 | ClientEntry t_lam_; 70 | 71 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 72 | static const uint8_t kEntryLength = kSubTLam + 1; 73 | ClientEntryAbstract* entry_array[kEntryLength] = { 74 | &t_coil_, // 0 75 | &t_alu_, // 1 76 | &t_amb_, // 2 77 | &h_coil_amb_free_conv_, // 3 78 | &h_coil_stator_cond_, // 4 79 | &h_coil_amb_forced_conv_, // 5 80 | &c_coil_, // 6 81 | &h_coil_amb_forced_conv_coeff_, // 7 82 | &otw_, // 8 83 | &otlo_, // 9 84 | &derate_, // 10 85 | &q_coil_joule_, // 11 86 | &q_coil_amb_conv_, // 12 87 | &q_coil_stator_cond_, // 13 88 | &h_lam_alu_, // 14 89 | &c_lam_, // 15 90 | &k_lam_hist_coeff_, // 16 91 | &q_lam_hist_, // 17 92 | &q_lam_alu_, // 18 93 | &t_lam_ // 19 94 | }; 95 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 96 | } 97 | 98 | private: 99 | static const uint8_t kSubTCoil = 0; 100 | static const uint8_t kSubTAlu = 1; 101 | static const uint8_t kSubTAmb = 2; 102 | static const uint8_t kSubHCoilAmbFreeConv = 3; 103 | static const uint8_t kSubHCoilStatorCond = 4; 104 | static const uint8_t kSubHCoilAmbForcedConv = 5; 105 | static const uint8_t kSubCCoil = 6; 106 | static const uint8_t kSubHCoilAmbForcedConvCoeff = 7; 107 | static const uint8_t kSubOtw = 8; 108 | static const uint8_t kSubOtlo = 9; 109 | static const uint8_t kSubDerate = 10; 110 | static const uint8_t kSubQCoilJoule = 11; 111 | static const uint8_t kSubQCoilAmbConv = 12; 112 | static const uint8_t kSubQCoilStatorCond = 13; 113 | static const uint8_t kSubHLamAlu = 14; 114 | static const uint8_t kSubCLam = 15; 115 | static const uint8_t kSubKLamHistCoeff = 16; 116 | static const uint8_t kSubQLamHist = 17; 117 | static const uint8_t kSubQLamAlu = 18; 118 | static const uint8_t kSubTLam = 19; 119 | }; 120 | 121 | #endif /* COIL_TEMPERATURE_ESTIMATOR_CLIENT_HPP_ */ -------------------------------------------------------------------------------- /inc/client_communication.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: client_communication.hpp 11 | Last update: 4/12/2019 by Matthew Piccoli 12 | Author: Matthew Piccoli 13 | Contributors: Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef CLIENT_COMMUNICATION_H 17 | #define CLIENT_COMMUNICATION_H 18 | 19 | #include // for memcpy 20 | #include "communication_interface.h" 21 | 22 | enum Access {kGet=0, kSet=1, kSave=2, kReply=3}; 23 | 24 | class ClientEntryAbstract { 25 | public: 26 | ClientEntryAbstract(uint8_t type_idn, uint8_t obj_idn, uint8_t sub_idn): 27 | type_idn_(type_idn), 28 | obj_idn_(obj_idn), 29 | sub_idn_(sub_idn) {}; 30 | 31 | virtual ~ClientEntryAbstract(){}; 32 | 33 | virtual void Reply(const uint8_t* data, uint8_t len) = 0; 34 | 35 | const uint8_t type_idn_; 36 | const uint8_t obj_idn_; 37 | const uint8_t sub_idn_; 38 | }; 39 | 40 | class ClientEntryVoid: public ClientEntryAbstract { 41 | public: 42 | ClientEntryVoid(uint8_t type_idn, uint8_t obj_idn, uint8_t sub_idn): 43 | ClientEntryAbstract(type_idn, obj_idn, sub_idn), 44 | is_fresh_(false) 45 | {}; 46 | 47 | void get(CommunicationInterface &com) { 48 | uint8_t tx_msg[2]; 49 | tx_msg[0] = sub_idn_; 50 | tx_msg[1] = (obj_idn_<<2) | kGet; // high six | low two 51 | com.SendPacket(type_idn_, tx_msg, 2); 52 | }; 53 | 54 | void set(CommunicationInterface &com) { 55 | uint8_t tx_msg[2]; // must fit outgoing message 56 | tx_msg[0] = sub_idn_; 57 | tx_msg[1] = (obj_idn_<<2) | kSet; // high six | low two 58 | com.SendPacket(type_idn_, tx_msg, 2); 59 | } 60 | 61 | void save(CommunicationInterface &com) { 62 | uint8_t tx_msg[2]; 63 | tx_msg[0] = sub_idn_; 64 | tx_msg[1] = (obj_idn_<<2) | kSave; // high six | low two 65 | com.SendPacket(type_idn_, tx_msg, 2); 66 | } 67 | 68 | void Reply(const uint8_t* data, uint8_t len) { 69 | (void)data; 70 | if(len == 0) { 71 | is_fresh_ = true; 72 | } 73 | }; 74 | 75 | bool IsFresh() {return is_fresh_;}; 76 | 77 | private: 78 | bool is_fresh_; 79 | }; 80 | 81 | template 82 | class ClientEntry: public ClientEntryAbstract { 83 | public: 84 | ClientEntry(uint8_t type_idn, uint8_t obj_idn, uint8_t sub_idn): 85 | ClientEntryAbstract(type_idn, obj_idn, sub_idn), 86 | is_fresh_(false), 87 | value_() 88 | {}; 89 | 90 | void get(CommunicationInterface &com) { 91 | uint8_t tx_msg[2]; 92 | tx_msg[0] = sub_idn_; 93 | tx_msg[1] = (obj_idn_<<2) | kGet; // high six | low two 94 | com.SendPacket(type_idn_, tx_msg, 2); 95 | }; 96 | 97 | void set(CommunicationInterface &com, T value) { 98 | uint8_t tx_msg[2+sizeof(T)]; // must fit outgoing message 99 | tx_msg[0] = sub_idn_; 100 | tx_msg[1] = (obj_idn_<<2) | kSet; // high six | low two 101 | memcpy(&tx_msg[2], &value, sizeof(T)); 102 | com.SendPacket(type_idn_, tx_msg, 2+sizeof(T)); 103 | } 104 | 105 | void save(CommunicationInterface &com) { 106 | uint8_t tx_msg[2]; 107 | tx_msg[0] = sub_idn_; 108 | tx_msg[1] = (obj_idn_<<2) | kSave; // high six | low two 109 | com.SendPacket(type_idn_, tx_msg, 2); 110 | } 111 | 112 | void Reply(const uint8_t* data, uint8_t len) { 113 | if(len == sizeof(T)) { 114 | memcpy(&value_, data, sizeof(T)); 115 | is_fresh_ = true; 116 | } 117 | }; 118 | 119 | T get_reply() { 120 | is_fresh_ = false; 121 | return value_; 122 | }; 123 | 124 | bool IsFresh() {return is_fresh_;}; 125 | 126 | private: 127 | bool is_fresh_; 128 | T value_; 129 | }; 130 | 131 | class PackedClientEntry : public ClientEntryAbstract { 132 | public: 133 | PackedClientEntry(uint8_t type_idn, uint8_t obj_idn, uint8_t sub_idn, uint8_t * data_buf): 134 | ClientEntryAbstract(type_idn, obj_idn, sub_idn), 135 | data_buf_(data_buf) 136 | {}; 137 | 138 | //Take in an array of bytes and a length, and ship the bytes out as an IQUART packet 139 | void set(CommunicationInterface &com, uint8_t * buf, uint8_t data_length) { 140 | uint8_t tx_msg[2+data_length]; // must fit outgoing message 141 | tx_msg[0] = sub_idn_; 142 | tx_msg[1] = (obj_idn_<<2) | kSet; // high six | low two 143 | memcpy(&tx_msg[2], buf, data_length); 144 | com.SendPacket(type_idn_, tx_msg, 2+data_length); 145 | } 146 | 147 | void get(CommunicationInterface &com) { 148 | uint8_t tx_msg[2]; 149 | tx_msg[0] = sub_idn_; 150 | tx_msg[1] = (obj_idn_<<2) | kGet; // high six | low two 151 | com.SendPacket(type_idn_, tx_msg, 2); 152 | }; 153 | 154 | void Reply(const uint8_t* data, uint8_t len) { 155 | if(data_buf_ != nullptr){ 156 | memcpy(data_buf_, data, len); 157 | is_fresh_ = true; 158 | } 159 | }; 160 | 161 | void get_reply(uint8_t * output_buf, uint8_t output_len) { 162 | if(data_buf_ != nullptr){ 163 | is_fresh_ = false; 164 | memcpy(output_buf, data_buf_, output_len); 165 | } 166 | }; 167 | 168 | bool IsFresh() {return is_fresh_;}; 169 | 170 | private: 171 | bool is_fresh_; 172 | uint8_t * data_buf_; 173 | 174 | }; 175 | 176 | class ClientAbstract{ 177 | public: 178 | ClientAbstract(uint8_t type_idn, uint8_t obj_idn): 179 | type_idn_(type_idn), 180 | obj_idn_(obj_idn) {}; 181 | 182 | virtual ~ClientAbstract(){}; 183 | 184 | virtual void ReadMsg(uint8_t* rx_data, uint8_t rx_length) = 0; 185 | 186 | const uint8_t type_idn_; 187 | const uint8_t obj_idn_; 188 | }; 189 | 190 | int8_t ParseMsg(uint8_t* rx_data, uint8_t rx_length, 191 | ClientEntryAbstract** entry_array, uint8_t entry_length); 192 | 193 | int8_t ParseMsg(uint8_t* rx_data, uint8_t rx_length, 194 | ClientEntryAbstract& entry); 195 | 196 | #endif // CLIENT_COMMUNICATION_H 197 | -------------------------------------------------------------------------------- /inc/packet_finder.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: packet_finder.h 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: James Paulos 13 | Contributors: Matthew Piccoli, Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef PACKET_FINDER_H 17 | #define PACKET_FINDER_H 18 | 19 | /// PacketFinder enables extraction of well formed, crc-verified packets from a 20 | /// byte stream. It is a specialized queue/buffer which takes in raw bytes and 21 | /// returns packet data. The returned packet data is a byte array consisting of 22 | /// a type byte followed by data bytes. 23 | /// 24 | /// General Packet Format: 25 | /// | 0x55 | length | type | ---data--- | crcL | crcH | 26 | /// 'length' is the (uint8) number of bytes in 'data' 27 | /// 'type' is the (uint8) message type 28 | /// 'data' is a series of (uint8) bytes, serialized Little-Endian 29 | /// 'crc' is the (uint16) CRC value for 'length'+'type'+'data', Little-Endian 30 | 31 | #include "byte_queue.h" 32 | #include 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | //#define COMPUTER 39 | #ifdef COMPUTER 40 | #define PACKET_BUFFER_SIZE 1023 /// size of input buffer 41 | #else 42 | #define PACKET_BUFFER_SIZE 64 /// size of input buffer 43 | #endif 44 | #define MAX_PACKET_SIZE 64 /// size packet (including header and CRC) 45 | #define MAX_PACKET_DATA_SIZE (MAX_PACKET_SIZE-5) /// size data (not type, etc) 46 | 47 | extern const uint8_t kStartByte; /// special start byte 48 | 49 | /// Internally used state machine states, voluntarily opaque. 50 | enum PacketFinderState { 51 | kStart, 52 | kLen, 53 | kType, 54 | kData, 55 | kCRCL, 56 | kCRCH, 57 | }; 58 | 59 | /// Interally used instance state struct, voluntarily opaque. 60 | struct PacketFinder { 61 | 62 | uint8_t* start_data; /// pointer to first data byte in buffer 63 | uint8_t* end_data; /// pointer to byte following last data byte in buffer 64 | 65 | enum PacketFinderState state; /// parser state machine state 66 | 67 | uint16_t parse_index; /// index of next parser operation 68 | uint16_t packet_start_index; /// start index for current packet 69 | uint16_t received_length; /// bytes in data reported for current packet 70 | 71 | uint16_t expected_crc; /// crc calculated for recieved data 72 | uint16_t received_crc; /// crc received in packet footer 73 | uint16_t data_bytes; /// bytes of type+data read in current packet 74 | 75 | uint8_t buffer[PACKET_BUFFER_SIZE]; /// buffer of recieved packet data 76 | uint8_t out_buffer[MAX_PACKET_SIZE]; /// fixed output buffer for contiguous access 77 | 78 | struct ByteQueue* packet_indices; 79 | // maintain queue of indices in buffer at which to find complete packets 80 | // each index gives the location of a packet's length byte in buffer 81 | // length bytes of type+data always follow contiguously after 82 | }; 83 | 84 | /// Initialize a PacketFinder state struct 85 | /// @param pf Pointer to an uninitialized PacketFinder struct. 86 | void InitPacketFinder(struct PacketFinder *pf, struct ByteQueue *bq); 87 | 88 | /// Add a data byte array to the packet extractor queue. 89 | /// @param pf Pointer to PacketFinder struct. 90 | /// @param data Pointer to new data bytes. 91 | /// @param length Number of bytes to read from data 92 | /// @return Returns 0 on success, 93 | /// -1 on buffer overflow (data loss), 94 | /// -2 for fatal error 95 | int8_t PutBytes(struct PacketFinder *pf, const uint8_t *data, uint16_t length); 96 | 97 | /// Peek at the next available packet in queue. If a packet is ready, pointer 98 | /// 'packet' will point to the first byte (the type) and 'length' will give the 99 | /// length of packet type+data, which may be read as a contiguous array. 100 | /// Arguments 'packet' and 'length' are ignored if no packet is ready. Repeated 101 | /// calls to PeekPacket will return pointers to the same packet until DropPacket 102 | /// is used. 103 | /// @param pf Pointer to PacketFinder struct. 104 | /// @param packet Reference to a pointer to data, function redirects pointer. 105 | /// @param length Reference to an integer byte length, function changes value. 106 | /// @return Returns 1 if packet peek available, 107 | /// 0 if no packet ready to peak 108 | int8_t PeekPacket(struct PacketFinder *pf, uint8_t **packet, uint8_t *length); 109 | 110 | /// Drop the next available packet from queue. Usually called after PeekPacket. 111 | /// @param pf Pointer to PacketFinder struct 112 | /// @return Returns 1 if packet removed, 113 | /// 0 if no packet ready to remove, 114 | int8_t DropPacket(struct PacketFinder *pf); 115 | 116 | /// Copy the next available completed packet and remove from queue. Output 117 | /// argument 'packet' must reserve enough space to copy the packet. Output 118 | /// argument 'length' is of type+data. Use of the Peek/Drop functions will 119 | /// typically yield better performance with less copying. 120 | /// @param pf Pointer to PacketFinder struct. 121 | /// @param packet Pointer to byte data, function changes data. 122 | /// @param length Reference to an integer byte length, function changes value. 123 | /// @return Returns 1 if packet removed, 124 | /// 0 if no packet ready to pop 125 | int8_t GetPacketCopy(struct PacketFinder *pf, uint8_t *packet, uint8_t *length); 126 | 127 | /// Embed a byte data string into a packet with start header, type, and CRC 128 | /// footer. The generated packet copied to out_data is in_len+5 bytes long, and 129 | /// sufficient space in out_data must be reserved! 130 | /// @param type Message type byte. 131 | /// @param in_data Pointer to data for packet. 132 | /// @param in_length Number of bytes of data. 133 | /// @param out_data Pointer to location for function to create packet. 134 | /// @param out_len Pointer to integer packet length, function changes value. 135 | int8_t FormPacket(uint8_t type, 136 | const uint8_t *in_data, uint8_t in_len, 137 | uint8_t *out_data, uint8_t *out_len); 138 | 139 | #ifdef __cplusplus 140 | } 141 | #endif // __cplusplus 142 | 143 | #endif // PACKET_FINDER_H 144 | -------------------------------------------------------------------------------- /inc/system_control_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: system_control_client.hpp 11 | Last update: 2023/05/24 by Ben Quan 12 | Author: Matthew Piccoli 13 | Contributors: Ben Quan, Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef SYSTEM_CONTROL_CLIENT_H 17 | #define SYSTEM_CONTROL_CLIENT_H 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeSystemControl = 5; 22 | 23 | class SystemControlClient : public ClientAbstract { 24 | public: 25 | SystemControlClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeSystemControl, obj_idn), 27 | reboot_program_(kTypeSystemControl, obj_idn, kSubRebootProgram), 28 | reboot_boot_loader_(kTypeSystemControl, obj_idn, kSubRebootBootLoader), 29 | dev_id_(kTypeSystemControl, obj_idn, kSubDevId), 30 | rev_id_(kTypeSystemControl, obj_idn, kSubRevId), 31 | uid1_(kTypeSystemControl, obj_idn, kSubUid1), 32 | uid2_(kTypeSystemControl, obj_idn, kSubUid2), 33 | uid3_(kTypeSystemControl, obj_idn, kSubUid3), 34 | mem_size_(kTypeSystemControl, obj_idn, kSubMemSize), 35 | build_year_(kTypeSystemControl, obj_idn, kSubBuildYear), 36 | build_month_(kTypeSystemControl, obj_idn, kSubBuildMonth), 37 | build_day_(kTypeSystemControl, obj_idn, kSubBuildDay), 38 | build_hour_(kTypeSystemControl, obj_idn, kSubBuildHour), 39 | build_minute_(kTypeSystemControl, obj_idn, kSubBuildMinuite), 40 | build_second_(kTypeSystemControl, obj_idn, kSubBuildSecond), 41 | module_id_(kTypeSystemControl, obj_idn, kSubModuleId), 42 | time_(kTypeSystemControl, obj_idn, kSubTime), 43 | firmware_version_(kTypeSystemControl, obj_idn, kSubFirmwareVersion), 44 | hardware_version_(kTypeSystemControl, obj_idn, kSubHardwareVersion), 45 | electronics_version_(kTypeSystemControl, obj_idn, kSubElectronicsVersion), 46 | firmware_valid_(kTypeSystemControl, obj_idn, kSubFirmwareValid), 47 | applications_present_(kTypeSystemControl, obj_idn_, kSubApplicationsPresent), 48 | bootloader_version_(kTypeSystemControl, obj_idn_, kSubApplicationsPresent), 49 | upgrade_version_(kTypeSystemControl, obj_idn_, kSubUpgradeVersion), 50 | system_clock_(kTypeSystemControl, obj_idn_, kSubSystemClock), 51 | control_flags_(kTypeSystemControl, obj_idn_, kSubControlFlags), 52 | pcb_version_(kTypeSystemControl, obj_idn_, kSubPcbVersion){}; 53 | 54 | // Client Entries 55 | ClientEntryVoid reboot_program_; 56 | ClientEntryVoid reboot_boot_loader_; 57 | ClientEntry dev_id_; 58 | ClientEntry rev_id_; 59 | ClientEntry uid1_; 60 | ClientEntry uid2_; 61 | ClientEntry uid3_; 62 | ClientEntry mem_size_; 63 | ClientEntry build_year_; 64 | ClientEntry build_month_; 65 | ClientEntry build_day_; 66 | ClientEntry build_hour_; 67 | ClientEntry build_minute_; 68 | ClientEntry build_second_; 69 | ClientEntry module_id_; 70 | ClientEntry time_; 71 | ClientEntry firmware_version_; 72 | ClientEntry hardware_version_; 73 | ClientEntry electronics_version_; 74 | ClientEntry firmware_valid_; 75 | ClientEntry applications_present_; 76 | ClientEntry bootloader_version_; 77 | ClientEntry upgrade_version_; 78 | ClientEntry system_clock_; 79 | ClientEntry control_flags_; 80 | ClientEntry pcb_version_; 81 | 82 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 83 | static const uint8_t kEntryLength = kSubPcbVersion + 1; 84 | ClientEntryAbstract* entry_array[kEntryLength] = { 85 | &reboot_program_, // 0 86 | &reboot_boot_loader_, // 1 87 | &dev_id_, // 2 88 | &rev_id_, // 3 89 | &uid1_, // 4 90 | &uid2_, // 5 91 | &uid3_, // 6 92 | &mem_size_, // 7 93 | &build_year_, // 8 94 | &build_month_, // 9 95 | &build_day_, // 10 96 | &build_hour_, // 11 97 | &build_minute_, // 12 98 | &build_second_, // 13 99 | &module_id_, // 14 100 | &time_, // 15 101 | &firmware_version_, // 16 102 | &hardware_version_, // 17 103 | &electronics_version_, // 18 104 | &firmware_valid_, // 19 105 | &applications_present_, // 20 106 | &bootloader_version_, // 21 107 | &upgrade_version_, // 22 108 | &system_clock_, // 23 109 | &control_flags_, // 24 110 | &pcb_version_ // 25 111 | }; 112 | 113 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 114 | } 115 | 116 | private: 117 | static const uint8_t kSubRebootProgram = 0; 118 | static const uint8_t kSubRebootBootLoader = 1; 119 | static const uint8_t kSubDevId = 2; 120 | static const uint8_t kSubRevId = 3; 121 | static const uint8_t kSubUid1 = 4; 122 | static const uint8_t kSubUid2 = 5; 123 | static const uint8_t kSubUid3 = 6; 124 | static const uint8_t kSubMemSize = 7; 125 | static const uint8_t kSubBuildYear = 8; 126 | static const uint8_t kSubBuildMonth = 9; 127 | static const uint8_t kSubBuildDay = 10; 128 | static const uint8_t kSubBuildHour = 11; 129 | static const uint8_t kSubBuildMinuite = 12; 130 | static const uint8_t kSubBuildSecond = 13; 131 | static const uint8_t kSubModuleId = 14; 132 | static const uint8_t kSubTime = 15; 133 | static const uint8_t kSubFirmwareVersion = 16; 134 | static const uint8_t kSubHardwareVersion = 17; 135 | static const uint8_t kSubElectronicsVersion = 18; 136 | static const uint8_t kSubFirmwareValid = 19; 137 | static const uint8_t kSubApplicationsPresent = 20; 138 | static const uint8_t kSubBootloaderVersion = 21; 139 | static const uint8_t kSubUpgradeVersion = 22; 140 | static const uint8_t kSubSystemClock = 23; 141 | static const uint8_t kSubControlFlags = 24; 142 | static const uint8_t kSubPcbVersion = 25; 143 | }; 144 | 145 | #endif // SYSTEM_CONTROL_CLIENT_H 146 | -------------------------------------------------------------------------------- /tests/test_api_vertiq8108_speed_F1_0_2_0.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This C++ script tests the updated client entries of various clients for firmware v1.0.2.0 3 | * The serial port setup for windows is based on the example provided by microsoft: 4 | * https://learn.microsoft.com/en-us/windows/win32/devio/configuring-a-communications-resource 5 | * 6 | * Name: test_api_vertiq8108_speed_F1_0_2_0.cpp 7 | * Last update: 2025/08/26 by Ben Quan 8 | * Author: Ben Quan 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../inc/arming_handler_client.hpp" 16 | #include "../inc/brushless_drive_client.hpp" 17 | #include "../inc/client_communication.cpp" 18 | #include "../inc/esc_propeller_input_parser_client.hpp" 19 | #include "../inc/generic_interface.hpp" 20 | #include "../inc/hobby_input_client.hpp" 21 | #include "../inc/multi_turn_angle_control_client.hpp" 22 | #include "../inc/propeller_motor_control_client.hpp" 23 | 24 | using namespace std; 25 | 26 | HANDLE comPort; // Handler for COM port 27 | TCHAR *pcCommPort = TEXT("COM4"); // Change COM4 to whichever port your motor is connected to 28 | GenericInterface com; // Interface used by com port to communicate with motor 29 | 30 | ArmingHandlerClient armingHandler(0); // Initialize Arming Handler Client 31 | BrushlessDriveClient brushlessDrive(0); // Initialize Brushless Drive Client 32 | EscPropellerInputParserClient escPropellerInputParser(0); // Initialize Esc Propeller Input Parser Client 33 | HobbyInputClient hobbyInput(0); 34 | MultiTurnAngleControlClient multiTurnAngleControl(0); // Initialize Mult Turn Angle Control Client 35 | PropellerMotorControlClient propellerMotorControl(0); // Initialize Propeller Motor Control Client 36 | 37 | // Initialize clientList to make it easier to call ReadMsg for each client 38 | ClientAbstract *clientList[6] = { &armingHandler, 39 | &brushlessDrive, 40 | &escPropellerInputParser, 41 | &hobbyInput, 42 | &multiTurnAngleControl, 43 | &propellerMotorControl 44 | }; 45 | 46 | // Send out any message data we have over the serial interface 47 | int handleComTx() { 48 | uint8_t packetBuffer[64]; 49 | uint8_t length = 0; 50 | DWORD bytesWritten; 51 | 52 | // Get the packet from the com interface and place it into the packet buffer 53 | if (com.GetTxBytes(packetBuffer, length)) { 54 | WriteFile(comPort, packetBuffer, length, &bytesWritten, NULL); 55 | } 56 | 57 | return bytesWritten; 58 | } 59 | 60 | // Grab any received data on the serial interface 61 | int handleComRx() { 62 | uint8_t recvBytes[64]; 63 | DWORD dwBytesReceived; 64 | 65 | ReadFile(comPort, &recvBytes, 64, &dwBytesReceived, 0); 66 | com.SetRxBytes(recvBytes, dwBytesReceived); 67 | 68 | return dwBytesReceived; 69 | } 70 | 71 | // Hand off any received data to each module so they can handle it 72 | void updateModules() { 73 | // Temporary Pointer to the packet data location 74 | uint8_t *packetData; 75 | uint8_t packetLength; 76 | 77 | // Loads the packet data buffer with data receieved from the motor 78 | while (com.PeekPacket(&packetData, &packetLength)) { 79 | for (auto &client : clientList) { 80 | client->ReadMsg(packetData, packetLength); 81 | }; 82 | com.DropPacket(); 83 | } 84 | } 85 | 86 | // Handles communication with motor 87 | void sendMessageAndProcessReply(){ 88 | handleComTx(); 89 | handleComRx(); 90 | updateModules(); 91 | } 92 | 93 | uint8_t getPlayArmingSongOnArm(){ 94 | armingHandler.play_arming_song_on_arm_.get(com); 95 | sendMessageAndProcessReply(); 96 | return armingHandler.play_arming_song_on_arm_.get_reply(); 97 | } 98 | 99 | uint32_t getScalingCommutationCyclesPerErev(){ 100 | brushlessDrive.scaling_commutation_cycles_per_erev_.get(com); 101 | sendMessageAndProcessReply(); 102 | return brushlessDrive.scaling_commutation_cycles_per_erev_.get_reply(); 103 | } 104 | 105 | uint32_t getScalingCommutationHzFloor(){ 106 | brushlessDrive.scaling_commutation_hz_floor_.get(com); 107 | sendMessageAndProcessReply(); 108 | return brushlessDrive.scaling_commutation_hz_floor_.get_reply(); 109 | } 110 | 111 | uint32_t getScalingCommutationHzCeiling(){ 112 | brushlessDrive.scaling_commutation_hz_ceiling_.get(com); 113 | sendMessageAndProcessReply(); 114 | return brushlessDrive.scaling_commutation_hz_ceiling_.get_reply(); 115 | } 116 | 117 | uint16_t getHobbyTelemetryFrequency(){ 118 | hobbyInput.hobby_telemetry_frequency_.get(com); 119 | sendMessageAndProcessReply(); 120 | return hobbyInput.hobby_telemetry_frequency_.get_reply(); 121 | } 122 | 123 | uint8_t getHobbyTelemetrySpeedStyle(){ 124 | hobbyInput.hobby_telemetry_speed_style_.get(com); 125 | sendMessageAndProcessReply(); 126 | return hobbyInput.hobby_telemetry_speed_style_.get_reply(); 127 | } 128 | 129 | uint8_t getAllowDshotDisarmingMessage(){ 130 | hobbyInput.allow_dshot_disarming_message_.get(com); 131 | sendMessageAndProcessReply(); 132 | return hobbyInput.allow_dshot_disarming_message_.get_reply(); 133 | } 134 | 135 | float getLowPowerHoldAllowedTargetError(){ 136 | multiTurnAngleControl.low_power_hold_allowed_target_error_.get(com); 137 | sendMessageAndProcessReply(); 138 | return multiTurnAngleControl.low_power_hold_allowed_target_error_.get_reply(); 139 | } 140 | 141 | float getLowPowerHoldMaxBrakeError(){ 142 | multiTurnAngleControl.low_power_hold_max_brake_error_.get(com); 143 | sendMessageAndProcessReply(); 144 | return multiTurnAngleControl.low_power_hold_max_brake_error_.get_reply(); 145 | } 146 | 147 | int main() { 148 | comPort = CreateFile(pcCommPort, GENERIC_READ | GENERIC_WRITE, 149 | 0, // must be opened with exclusive-access 150 | NULL, // default security attributes 151 | OPEN_EXISTING, // must use OPEN_EXISTING 152 | 0, // not overlapped I/O 153 | NULL); // hTemplate must be NULL for comm devices 154 | 155 | cout << comPort << endl; 156 | 157 | if (comPort == INVALID_HANDLE_VALUE) 158 | cout << "Error in opening serial port" << endl; 159 | else 160 | cout << "opening serial port successful" << endl; 161 | 162 | DCB dcb = {0}; // Device-control block used to configure serial communications 163 | dcb.DCBlength = sizeof(DCB); 164 | GetCommState(comPort, &dcb); 165 | dcb.BaudRate = CBR_115200; // Set baud rate to 115200 166 | dcb.ByteSize = 8; 167 | SetCommState(comPort, &dcb); 168 | 169 | // Set up a read timeout 170 | COMMTIMEOUTS timeouts; 171 | GetCommTimeouts(comPort, &timeouts); 172 | timeouts.ReadIntervalTimeout = 5; 173 | SetCommTimeouts(comPort, &timeouts); 174 | 175 | cout << "starting tests..." << endl; 176 | 177 | uint8_t playArmingSongOnArm = getPlayArmingSongOnArm(); 178 | cout << "play_arming_song_on_arm: " << to_string(playArmingSongOnArm) << endl; 179 | 180 | uint16_t hobby_telemetry_frequency = getHobbyTelemetryFrequency(); 181 | cout << "hobby_telemetry_frequency: " << to_string(hobby_telemetry_frequency) << endl; 182 | 183 | uint8_t hobby_telemetry_speed_style = getHobbyTelemetrySpeedStyle(); 184 | cout << "hobby_telemetry_speed_style: " << to_string(hobby_telemetry_speed_style) << endl; 185 | 186 | uint8_t allow_dshot_disarming_message = getAllowDshotDisarmingMessage(); 187 | cout << "allow_dshot_disarming_message: " << to_string(allow_dshot_disarming_message) << endl; 188 | 189 | float low_power_hold_allowed_target_error = getLowPowerHoldAllowedTargetError(); 190 | cout << "low_power_hold_allowed_target_error: " << to_string(low_power_hold_allowed_target_error) << endl; 191 | 192 | float low_power_hold_max_brake_error = getLowPowerHoldMaxBrakeError(); 193 | cout << "low_power_hold_max_brake_error: " << to_string(low_power_hold_max_brake_error) << endl; 194 | 195 | return 0; 196 | } -------------------------------------------------------------------------------- /inc/bipbuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003 Simon Cooke, All Rights Reserved 3 | 4 | Licensed royalty-free for commercial and non-commercial 5 | use, without warranty or guarantee of suitability for any purpose. 6 | All that I ask is that you send me an email 7 | telling me that you're using my code. It'll make me 8 | feel warm and fuzzy inside. spectecjr@gmail.com 9 | 10 | */ 11 | 12 | /* 13 | Name: bibuffer.h 14 | Last update: 3/7/2019 by Raphael Van Hoffelen 15 | Author: Simon Cooke 16 | Contributors: Matthew Piccoli, Raphael Van Hoffelen 17 | */ 18 | 19 | /* 20 | Changed header gaurd from pragma once to ifndef BipBuffer_H. 21 | Chaning types to fixed width integers. 22 | Removed destructor, AllocateBuffer, FreeBuffer. 23 | Constructor expects array and size to be passed in. 24 | Including stddef for NULL 25 | Matthew Piccoli, 4/1/2016 26 | */ 27 | 28 | #ifndef BipBuffer_H 29 | #define BipBuffer_H 30 | 31 | #include 32 | 33 | class BipBuffer 34 | { 35 | private: 36 | uint8_t* pBuffer; // Pointer to the data buffer 37 | uint16_t ixa; // Starting index of region A 38 | uint16_t sza; // Size of region A 39 | uint16_t ixb; // Starting index of region B 40 | uint16_t szb; // Size of region B 41 | uint16_t buflen; // Length of full buffer 42 | uint16_t ixResrv; // Starting index of reserved region 43 | uint16_t szResrv; // Size of the reserved region 44 | 45 | public: 46 | BipBuffer() : pBuffer(NULL), ixa(0), sza(0), ixb(0), szb(0), buflen(0), ixResrv(0), szResrv(0) 47 | { 48 | 49 | } 50 | BipBuffer(uint8_t* buffer_in, uint16_t buffer_length_in) : ixa(0), sza(0), ixb(0), szb(0), ixResrv(0), szResrv(0) 51 | { 52 | pBuffer = buffer_in; 53 | buflen = buffer_length_in; 54 | } 55 | 56 | /// 57 | /// \brief Clears the buffer of any allocations. 58 | /// 59 | /// Clears the buffer of any allocations or reservations. Note; it 60 | /// does not wipe the buffer memory; it merely resets all pointers, 61 | /// returning the buffer to a completely empty state ready for new 62 | /// allocations. 63 | /// 64 | void Clear() 65 | { 66 | ixa = sza = ixb = szb = ixResrv = szResrv = 0; 67 | } 68 | 69 | // Reserve 70 | // 71 | // Reserves space in the buffer for a memory write operation 72 | // 73 | // Parameters: 74 | // int size amount of space to reserve 75 | // uint16_t& reserved size of space actually reserved 76 | // 77 | // Returns: 78 | // uint8_t* pointer to the reserved block 79 | // 80 | // Notes: 81 | // Will return NULL for the pointer if no space can be allocated. 82 | // Can return any value from 1 to size in reserved. 83 | // Will return NULL if a previous reservation has not been committed. 84 | uint8_t* Reserve(uint16_t size, uint16_t& reserved) 85 | { 86 | // We always allocate on B if B exists; this means we have two blocks and our buffer is filling. 87 | if (szb) 88 | { 89 | uint16_t freespace = GetBFreeSpace(); 90 | 91 | if (size < freespace) freespace = size; 92 | 93 | if (freespace == 0) return NULL; 94 | 95 | szResrv = freespace; 96 | reserved = freespace; 97 | ixResrv = ixb + szb; 98 | return pBuffer + ixResrv; 99 | } 100 | else 101 | { 102 | // Block b does not exist, so we can check if the space AFTER a is bigger than the space 103 | // before A, and allocate the bigger one. 104 | uint16_t freespace = GetSpaceAfterA(); 105 | if (freespace >= ixa) // If space after A > space before 106 | { 107 | if (freespace == 0) return NULL; 108 | if (size < freespace) freespace = size; 109 | 110 | szResrv = freespace; 111 | reserved = freespace; 112 | ixResrv = ixa + sza; 113 | return pBuffer + ixResrv; 114 | } 115 | else // space before A > space after A 116 | { 117 | if (ixa == 0) return NULL; 118 | if (ixa < size) size = ixa; 119 | szResrv = size; 120 | reserved = size; 121 | ixResrv = 0; 122 | return pBuffer; 123 | } 124 | } 125 | } 126 | 127 | // Commit 128 | // 129 | // Commits space that has been written to in the buffer 130 | // 131 | // Parameters: 132 | // uint16_t size number of bytes to commit 133 | // 134 | // Notes: 135 | // Committing a size > than the reserved size will cause an assert in a debug build; 136 | // in a release build, the actual reserved size will be used. 137 | // Committing a size < than the reserved size will commit that amount of data, and release 138 | // the rest of the space. 139 | // Committing a size of 0 will release the reservation. 140 | void Commit(uint16_t size) 141 | { 142 | if (size == 0) 143 | { 144 | // decommit any reservation 145 | szResrv = ixResrv = 0; 146 | return; 147 | } 148 | 149 | CommitPartial(size); 150 | 151 | // Decommit rest of reservation 152 | ixResrv = 0; 153 | szResrv = 0; 154 | } 155 | 156 | // CommitPartial 157 | // 158 | // Commits space that has been written to in the buffer, but does not cancel the rest of the reservation 159 | // 160 | // Parameters: 161 | // uint16_t size number of bytes to commit 162 | // 163 | // Returns: 164 | // uint16_t number of bytes actually committed 165 | // 166 | // Notes: 167 | // Committing a size > than the reserved size will cause an assert in a debug build; 168 | // in a release build, the actual reserved size will be used. 169 | // Committing a size < than the reserved size will commit that amount of data, but will not realese the remaining reservation 170 | // Committing a size of 0 does nothing (space is still reserved) 171 | uint16_t CommitPartial(uint16_t size) 172 | { 173 | // If we try to commit more space than we asked for, clip to the size we asked for. 174 | if (size > szResrv) 175 | { 176 | size = szResrv; 177 | } 178 | 179 | // If we have no blocks being used currently, we create one in A. 180 | if (sza == 0 && szb == 0) 181 | { 182 | ixa = ixResrv; 183 | } 184 | 185 | // If the reserve index is at the end of block A 186 | if (ixResrv == sza + ixa) 187 | { 188 | sza += size; // Grow A by committed size 189 | } 190 | else 191 | { 192 | szb += size; // Otherwise grow B by committed size 193 | } 194 | 195 | // Advance the reserved index 196 | ixResrv += size; 197 | // Update reserved size 198 | szResrv -= size; 199 | 200 | return size; 201 | } 202 | 203 | // GetContiguousBlock 204 | // 205 | // Gets a pointer to the first contiguous block in the buffer, and returns the size of that block. 206 | // 207 | // Parameters: 208 | // uint16_t & size returns the size of the first contiguous block 209 | // 210 | // Returns: 211 | // uint8_t* pointer to the first contiguous block, or NULL if empty. 212 | uint8_t* GetContiguousBlock(uint16_t& size) 213 | { 214 | if (sza == 0) 215 | { 216 | size = 0; 217 | return NULL; 218 | } 219 | 220 | size = sza; 221 | return pBuffer + ixa; 222 | 223 | } 224 | 225 | // DecommitBlock 226 | // 227 | // Decommits space from the first contiguous block 228 | // 229 | // Parameters: 230 | // int size amount of memory to decommit 231 | // 232 | // Returns: 233 | // nothing 234 | void DecommitBlock(uint16_t size) 235 | { 236 | if (size >= sza) 237 | { 238 | ixa = ixb; 239 | sza = szb; 240 | ixb = 0; 241 | szb = 0; 242 | } 243 | else 244 | { 245 | sza -= size; 246 | ixa += size; 247 | } 248 | } 249 | 250 | // GetCommittedSize 251 | // 252 | // Queries how much data (in total) has been committed in the buffer 253 | // 254 | // Parameters: 255 | // none 256 | // 257 | // Returns: 258 | // uint16_t total amount of committed data in the buffer 259 | uint16_t GetCommittedSize() const 260 | { 261 | return sza + szb; 262 | } 263 | 264 | // GetReservationSize 265 | // 266 | // Queries how much space has been reserved in the buffer. 267 | // 268 | // Parameters: 269 | // none 270 | // 271 | // Returns: 272 | // uint16_t number of bytes that have been reserved 273 | // 274 | // Notes: 275 | // A return value of 0 indicates that no space has been reserved 276 | uint16_t GetReservationSize() const 277 | { 278 | return szResrv; 279 | } 280 | 281 | // GetBufferSize 282 | // 283 | // Queries the maximum total size of the buffer 284 | // 285 | // Parameters: 286 | // none 287 | // 288 | // Returns: 289 | // uint16_t total size of buffer 290 | uint16_t GetBufferSize() const 291 | { 292 | return buflen; 293 | } 294 | 295 | // IsInitialized 296 | // 297 | // Queries whether or not the buffer has been allocated 298 | // 299 | // Parameters: 300 | // none 301 | // 302 | // Returns: 303 | // uint8_t true if the buffer has been allocated 304 | uint8_t IsInitialized() const 305 | { 306 | return pBuffer != NULL; 307 | } 308 | 309 | private: 310 | uint16_t GetSpaceAfterA() const 311 | { 312 | return buflen - ixa - sza; 313 | } 314 | 315 | uint16_t GetBFreeSpace() const 316 | { 317 | return ixa - ixb - szb; 318 | } 319 | }; 320 | 321 | #endif // BipBuffer_H -------------------------------------------------------------------------------- /inc/multi_turn_angle_control_client.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: multi_turn_angle_control_client.hpp 11 | Last update: 2025-08-26 by Ben Quan 12 | Author: Matthew Piccoli 13 | Contributors: Ben Quan, Raphael Van Hoffelen 14 | */ 15 | 16 | #ifndef MULTI_TURN_ANGLE_CONTROL_CLIENT_HPP_ 17 | #define MULTI_TURN_ANGLE_CONTROL_CLIENT_HPP_ 18 | 19 | #include "client_communication.hpp" 20 | 21 | const uint8_t kTypeAngleMotorControl = 59; 22 | 23 | class MultiTurnAngleControlClient : public ClientAbstract { 24 | public: 25 | MultiTurnAngleControlClient(uint8_t obj_idn) 26 | : ClientAbstract(kTypeAngleMotorControl, obj_idn), 27 | ctrl_mode_(kTypeAngleMotorControl, obj_idn, kSubCtrlMode), 28 | ctrl_brake_(kTypeAngleMotorControl, obj_idn, kSubCtrlBrake), 29 | ctrl_coast_(kTypeAngleMotorControl, obj_idn, kSubCtrlCoast), 30 | ctrl_pwm_(kTypeAngleMotorControl, obj_idn, kSubCtrlPwm), 31 | ctrl_volts_(kTypeAngleMotorControl, obj_idn, kSubCtrlVolts), 32 | ctrl_angle_(kTypeAngleMotorControl, obj_idn, kSubCtrlAngle), 33 | ctrl_velocity_(kTypeAngleMotorControl, obj_idn, kSubCtrlVelocity), 34 | angle_Kp_(kTypeAngleMotorControl, obj_idn, kSubAngleKp), 35 | angle_Ki_(kTypeAngleMotorControl, obj_idn, kSubAngleKi), 36 | angle_Kd_(kTypeAngleMotorControl, obj_idn, kSubAngleKd), 37 | timeout_(kTypeAngleMotorControl, obj_idn, kSubTimeout), 38 | obs_angular_displacement_(kTypeAngleMotorControl, obj_idn, kSubObsAngularDisplacement), 39 | obs_angular_velocity_(kTypeAngleMotorControl, obj_idn, kSubObsAngularVelocity), 40 | meter_per_rad_(kTypeAngleMotorControl, obj_idn, kSubMeterPerRad), 41 | ctrl_linear_displacement_(kTypeAngleMotorControl, obj_idn, kSubCtrlLinearDisplacement), 42 | ctrl_linear_velocity_(kTypeAngleMotorControl, obj_idn, kSubCtrlLinearVelocity), 43 | obs_linear_displacement_(kTypeAngleMotorControl, obj_idn, kSubObsLinearDisplacement), 44 | obs_linear_velocity_(kTypeAngleMotorControl, obj_idn, kSubObsLinearVelocity), 45 | angular_speed_max_(kTypeAngleMotorControl, obj_idn, kSubAngularSpeedMax), 46 | trajectory_angular_displacement_(kTypeAngleMotorControl, obj_idn, 47 | kSubTrajectoryAngularDisplacement), 48 | trajectory_angular_velocity_(kTypeAngleMotorControl, obj_idn, kSubTrajectoryAngularVelocity), 49 | trajectory_angular_acceleration_(kTypeAngleMotorControl, obj_idn, 50 | kSubTrajectoryAngularAcceleration), 51 | trajectory_duration_(kTypeAngleMotorControl, obj_idn, kSubTrajectoryDuration), 52 | trajectory_linear_displacement_(kTypeAngleMotorControl, obj_idn, kSubTrajectoryLinearDisplacement), 53 | trajectory_linear_velocity_(kTypeAngleMotorControl, obj_idn, kSubTrajectoryLinearVelocity), 54 | trajectory_linear_acceleration_(kTypeAngleMotorControl, obj_idn, kSubTrajectoryLinearAcceleration), 55 | trajectory_average_speed_(kTypeAngleMotorControl, obj_idn, kSubTrajectoryAverageSpeed), 56 | trajectory_queue_mode_(kTypeAngleMotorControl, obj_idn, kSubTrajectoryQueueMode), 57 | ff_(kTypeAngleMotorControl, obj_idn, kSubFF), 58 | sample_zero_angle_(kTypeAngleMotorControl, obj_idn, kSubSampleZeroAngle), 59 | zero_angle_(kTypeAngleMotorControl, obj_idn, kSubZeroAngle), 60 | additional_velocity_(kTypeAngleMotorControl, obj_idn, kSubAdditionalVelocity), 61 | low_power_hold_allowed_target_error_(kTypeAngleMotorControl, obj_idn, kSubLowPowerHoldAllowedTargetError), 62 | low_power_hold_max_brake_error_(kTypeAngleMotorControl, obj_idn, kSubLowPowerHoldMaxBrakeError), 63 | ctrl_angle_low_power_(kTypeAngleMotorControl, obj_idn, kSubCtrlAngleLowPower) 64 | {}; 65 | 66 | // Client Entries 67 | // Control commands 68 | ClientEntry ctrl_mode_; 69 | ClientEntryVoid ctrl_brake_; 70 | ClientEntryVoid ctrl_coast_; 71 | ClientEntry ctrl_pwm_; 72 | ClientEntry ctrl_volts_; 73 | ClientEntry ctrl_angle_; 74 | ClientEntry ctrl_velocity_; 75 | // Angle control 76 | ClientEntry angle_Kp_; 77 | ClientEntry angle_Ki_; 78 | ClientEntry angle_Kd_; 79 | // Timeout 80 | ClientEntry timeout_; 81 | // Angular values 82 | ClientEntry obs_angular_displacement_; 83 | ClientEntry obs_angular_velocity_; 84 | // Linear conversion 85 | ClientEntry meter_per_rad_; 86 | ClientEntry ctrl_linear_displacement_; 87 | ClientEntry ctrl_linear_velocity_; 88 | ClientEntry obs_linear_displacement_; 89 | ClientEntry obs_linear_velocity_; 90 | // Limits 91 | ClientEntry angular_speed_max_; 92 | // Trajectory 93 | ClientEntry trajectory_angular_displacement_; 94 | ClientEntry trajectory_angular_velocity_; 95 | ClientEntry trajectory_angular_acceleration_; 96 | ClientEntry trajectory_duration_; 97 | ClientEntry trajectory_linear_displacement_; 98 | ClientEntry trajectory_linear_velocity_; 99 | ClientEntry trajectory_linear_acceleration_; 100 | ClientEntry trajectory_average_speed_; 101 | ClientEntry trajectory_queue_mode_; 102 | ClientEntry ff_; 103 | ClientEntryVoid sample_zero_angle_; 104 | ClientEntry zero_angle_; 105 | //Additional Velocity 106 | ClientEntry additional_velocity_; 107 | ClientEntry low_power_hold_allowed_target_error_; 108 | ClientEntry low_power_hold_max_brake_error_; 109 | ClientEntry ctrl_angle_low_power_; 110 | 111 | void ReadMsg(uint8_t* rx_data, uint8_t rx_length) { 112 | static const uint8_t kEntryLength = kSubCtrlAngleLowPower + 1; 113 | ClientEntryAbstract* entry_array[kEntryLength] = { 114 | &ctrl_mode_, // 0 115 | &ctrl_brake_, // 1 116 | &ctrl_coast_, // 2 117 | &ctrl_angle_, // 3 118 | &ctrl_velocity_, // 4 119 | &angle_Kp_, // 5 120 | &angle_Ki_, // 6 121 | &angle_Kd_, // 7 122 | &timeout_, // 8 123 | &ctrl_pwm_, // 9 124 | &ctrl_volts_, // 10 125 | &obs_angular_displacement_, // 11 126 | &obs_angular_velocity_, // 12 127 | &meter_per_rad_, // 13 128 | &ctrl_linear_displacement_, // 14 129 | &ctrl_linear_velocity_, // 15 130 | &obs_linear_displacement_, // 16 131 | &obs_linear_velocity_, // 17 132 | &angular_speed_max_, // 18 133 | &trajectory_angular_displacement_, // 19 134 | &trajectory_angular_velocity_, // 20 135 | &trajectory_angular_acceleration_, // 21 136 | &trajectory_duration_, // 22 137 | &trajectory_linear_displacement_, // 23 138 | &trajectory_linear_velocity_, // 24 139 | &trajectory_linear_acceleration_, // 25 140 | &trajectory_average_speed_, // 26 141 | &trajectory_queue_mode_, // 27 142 | nullptr, // 28 143 | &ff_, // 29 144 | &sample_zero_angle_, // 30 145 | &zero_angle_, // 31 146 | &additional_velocity_, // 32 147 | &low_power_hold_allowed_target_error_, // 33 148 | &low_power_hold_max_brake_error_, // 34 149 | &ctrl_angle_low_power_ // 35 150 | }; 151 | 152 | ParseMsg(rx_data, rx_length, entry_array, kEntryLength); 153 | } 154 | 155 | private: 156 | static const uint8_t kSubCtrlMode = 0; 157 | static const uint8_t kSubCtrlBrake = 1; 158 | static const uint8_t kSubCtrlCoast = 2; 159 | static const uint8_t kSubCtrlAngle = 3; 160 | static const uint8_t kSubCtrlVelocity = 4; 161 | static const uint8_t kSubAngleKp = 5; 162 | static const uint8_t kSubAngleKi = 6; 163 | static const uint8_t kSubAngleKd = 7; 164 | static const uint8_t kSubTimeout = 8; 165 | static const uint8_t kSubCtrlPwm = 9; 166 | static const uint8_t kSubCtrlVolts = 10; 167 | static const uint8_t kSubObsAngularDisplacement = 11; 168 | static const uint8_t kSubObsAngularVelocity = 12; 169 | static const uint8_t kSubMeterPerRad = 13; 170 | static const uint8_t kSubCtrlLinearDisplacement = 14; 171 | static const uint8_t kSubCtrlLinearVelocity = 15; 172 | static const uint8_t kSubObsLinearDisplacement = 16; 173 | static const uint8_t kSubObsLinearVelocity = 17; 174 | static const uint8_t kSubAngularSpeedMax = 18; 175 | static const uint8_t kSubTrajectoryAngularDisplacement = 19; 176 | static const uint8_t kSubTrajectoryAngularVelocity = 20; 177 | static const uint8_t kSubTrajectoryAngularAcceleration = 21; 178 | static const uint8_t kSubTrajectoryDuration = 22; 179 | static const uint8_t kSubTrajectoryLinearDisplacement = 23; 180 | static const uint8_t kSubTrajectoryLinearVelocity = 24; 181 | static const uint8_t kSubTrajectoryLinearAcceleration = 25; 182 | static const uint8_t kSubTrajectoryAverageSpeed = 26; 183 | static const uint8_t kSubTrajectoryQueueMode = 27; 184 | static const uint8_t kSubFF = 29; 185 | static const uint8_t kSubSampleZeroAngle = 30; 186 | static const uint8_t kSubZeroAngle = 31; 187 | static const uint8_t kSubAdditionalVelocity = 32; 188 | static const uint8_t kSubLowPowerHoldAllowedTargetError = 33; 189 | static const uint8_t kSubLowPowerHoldMaxBrakeError = 34; 190 | static const uint8_t kSubCtrlAngleLowPower = 35; 191 | }; 192 | 193 | #endif /* MULTI_TURN_ANGLE_CONTROL_CLIENT_HPP_ */ 194 | -------------------------------------------------------------------------------- /tests/2306_pulsing_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * The serial port setup for windows is based on the example provided by microsoft: 3 | * https://learn.microsoft.com/en-us/windows/win32/devio/configuring-a-communications-resource 4 | * 5 | * Name: 2306_pulsing_test.cpp 6 | * Last update: 2023/04/19 by Ben Quan 7 | * Author: Ben Quan 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | // #include 15 | 16 | #include "../inc/brushless_drive_client.hpp" 17 | #include "../inc/client_communication.cpp" 18 | #include "../inc/coil_temperature_estimator_client.hpp" 19 | #include "../inc/esc_propeller_input_parser_client.hpp" 20 | #include "../inc/generic_interface.hpp" 21 | #include "../inc/iquart_flight_controller_interface_client.hpp" 22 | #include "../inc/persistent_memory_client.hpp" 23 | #include "../inc/power_monitor_client.hpp" 24 | #include "../inc/power_safety_client.hpp" 25 | #include "../inc/propeller_motor_control_client.hpp" 26 | #include "../inc/pulsing_rectangular_input_parser_client.hpp" 27 | #include "../inc/serial_interface_client.hpp" 28 | #include "../inc/system_control_client.hpp" 29 | #include "../inc/temperature_estimator_client.hpp" 30 | #include "../inc/temperature_monitor_uc_client.hpp" 31 | #include "../inc/voltage_superposition_client.hpp" 32 | 33 | using namespace std; 34 | 35 | HANDLE comPort; // Handler for COM port 36 | TCHAR *pcCommPort = TEXT("COM4"); // Change COM4 to whichever port your motor is connected to 37 | GenericInterface com; // Interface used by com port to communicate with motor 38 | 39 | BrushlessDriveClient brushlessDrive(0); // Initialize Brushless Drive Client 40 | CoilTemperatureEstimatorClient coilTemperatureEstimator(0); // Initialize Coil Temperature Estimator Client 41 | EscPropellerInputParserClient escPropellerInputParser(0); // Initialize Esc Propeller Input Parser Client 42 | IQUartFlightControllerInterfaceClient iquartFlightControllerInterface( 43 | 0); // Initialize IQUart Flight Controller Interface Client 44 | PersistentMemoryClient persistentMemory(0); // Initialize Persistent Memory Client 45 | PowerMonitorClient powerMonitor(0); // Initialize Power Monitor Client 46 | PowerSafetyClient powerSafety(0); // Initialize Power Safety Client 47 | PropellerMotorControlClient propellerMotorControl(0); // Initialize Propeller Motor Control Client 48 | PulsingRectangularInputParserClient pulsingRectangularInputParser( 49 | 0); // Initialize Pulsing Rectangulat Input Parser Client 50 | SerialInterfaceClient serialInterface(0); // Initialize Serial Interface Client 51 | SystemControlClient systemControl(0); // Initialize System Control Client 52 | TemperatureEstimatorClient temperatureEstimator(0); // Initialize Temperature Estimator Client 53 | TemperatureMonitorUcClient temperatureMonitorUc(0); // Initialize Temperature Monitor Uc Client 54 | VoltageSuperPositionClient voltageSuperposition(0); // Initialize Voltage Superposition Client 55 | 56 | // Initialize clientList to make it easier to call ReadMsg for each client 57 | ClientAbstract *clientList[14] = {&brushlessDrive, 58 | &coilTemperatureEstimator, 59 | &escPropellerInputParser, 60 | &iquartFlightControllerInterface, 61 | &persistentMemory, 62 | &powerMonitor, 63 | &powerSafety, 64 | &propellerMotorControl, 65 | &pulsingRectangularInputParser, 66 | &serialInterface, 67 | &systemControl, 68 | &temperatureEstimator, 69 | &temperatureMonitorUc, 70 | &voltageSuperposition}; 71 | 72 | // Send out any message data we have over the serial interface 73 | int handleComTx() { 74 | uint8_t packetBuffer[64]; 75 | uint8_t length = 0; 76 | DWORD bytesWritten; 77 | 78 | // Get the packet from the com interface and place it into the packet buffer 79 | if (com.GetTxBytes(packetBuffer, length)) { 80 | WriteFile(comPort, packetBuffer, length, &bytesWritten, NULL); 81 | } 82 | 83 | return bytesWritten; 84 | } 85 | 86 | // Grab any received data on the serial interface 87 | int handleComRx() { 88 | uint8_t recvBytes[64]; 89 | DWORD dwBytesReceived; 90 | 91 | ReadFile(comPort, &recvBytes, 64, &dwBytesReceived, 0); 92 | com.SetRxBytes(recvBytes, dwBytesReceived); 93 | 94 | return dwBytesReceived; 95 | } 96 | 97 | // Hand off any received data to each module so they can handle it 98 | void updateModules() { 99 | // Temporary Pointer to the packet data location 100 | uint8_t *packetData; 101 | uint8_t packetLength; 102 | 103 | // Loads the packet data buffer with data receieved from the motor 104 | while (com.PeekPacket(&packetData, &packetLength)) { 105 | for (auto &client : clientList) { 106 | client->ReadMsg(packetData, packetLength); 107 | }; 108 | com.DropPacket(); 109 | } 110 | } 111 | 112 | // Handles communication with motor 113 | void sendMessageAndProcessReply() { 114 | handleComTx(); 115 | handleComRx(); 116 | updateModules(); 117 | } 118 | 119 | uint8_t getDriveMode() { 120 | brushlessDrive.drive_mode_.get(com); 121 | sendMessageAndProcessReply(); 122 | return brushlessDrive.drive_mode_.get_reply(); 123 | } 124 | 125 | float getTCoil() { 126 | coilTemperatureEstimator.t_coil_.get(com); 127 | sendMessageAndProcessReply(); 128 | return coilTemperatureEstimator.t_coil_.get_reply(); 129 | } 130 | 131 | float getZeroSpinThrottle() { 132 | escPropellerInputParser.zero_spin_throttle_.get(com); 133 | sendMessageAndProcessReply(); 134 | return escPropellerInputParser.zero_spin_throttle_.get_reply(); 135 | } 136 | 137 | IFCITelemetryData getTelemetry() { 138 | iquartFlightControllerInterface.telemetry_.get(com); 139 | sendMessageAndProcessReply(); 140 | IFCITelemetryData tele = iquartFlightControllerInterface.telemetry_.get_reply(); 141 | return tele; 142 | } 143 | 144 | uint32_t getFormatKey1() { 145 | persistentMemory.format_key_1_.get(com); 146 | sendMessageAndProcessReply(); 147 | return persistentMemory.format_key_1_.get_reply(); 148 | } 149 | 150 | float getVolts() { 151 | powerMonitor.volts_.get(com); 152 | sendMessageAndProcessReply(); 153 | return powerMonitor.volts_.get_reply(); 154 | } 155 | 156 | float getVoltInputLow() { 157 | powerSafety.volt_input_low_.get(com); 158 | sendMessageAndProcessReply(); 159 | return powerSafety.volt_input_low_.get_reply(); 160 | } 161 | 162 | uint8_t getTimeoutSongOption() { 163 | propellerMotorControl.timeout_song_option_.get(com); 164 | sendMessageAndProcessReply(); 165 | return propellerMotorControl.timeout_song_option_.get_reply(); 166 | } 167 | 168 | uint8_t getPulsingVoltageMode() { 169 | pulsingRectangularInputParser.pulsing_voltage_mode_.get(com); 170 | sendMessageAndProcessReply(); 171 | return pulsingRectangularInputParser.pulsing_voltage_mode_.get_reply(); 172 | } 173 | 174 | uint32_t getBaudRate() { 175 | serialInterface.baud_rate_.get(com); 176 | sendMessageAndProcessReply(); 177 | return serialInterface.baud_rate_.get_reply(); 178 | } 179 | 180 | uint32_t getUid1() { 181 | systemControl.uid1_.get(com); 182 | sendMessageAndProcessReply(); 183 | return systemControl.uid1_.get_reply(); 184 | } 185 | 186 | uint32_t getControlFlags() { 187 | systemControl.control_flags_.get(com); 188 | sendMessageAndProcessReply(); 189 | return systemControl.control_flags_.get_reply(); 190 | } 191 | 192 | float getTemp() { 193 | temperatureEstimator.temp_.get(com); 194 | sendMessageAndProcessReply(); 195 | return temperatureEstimator.temp_.get_reply(); 196 | } 197 | 198 | float getUcTemp() { 199 | temperatureMonitorUc.uc_temp_.get(com); 200 | sendMessageAndProcessReply(); 201 | return temperatureMonitorUc.uc_temp_.get_reply(); 202 | } 203 | 204 | uint8_t getFrequency() { 205 | voltageSuperposition.frequency_.get(com); 206 | sendMessageAndProcessReply(); 207 | return voltageSuperposition.frequency_.get_reply(); 208 | } 209 | 210 | int main() { 211 | comPort = CreateFile(pcCommPort, GENERIC_READ | GENERIC_WRITE, 212 | 0, // must be opened with exclusive-access 213 | NULL, // default security attributes 214 | OPEN_EXISTING, // must use OPEN_EXISTING 215 | 0, // not overlapped I/O 216 | NULL); // hTemplate must be NULL for comm devices 217 | 218 | cout << comPort << endl; 219 | 220 | if (comPort == INVALID_HANDLE_VALUE) 221 | cout << "Error in opening serial port" << endl; 222 | else 223 | cout << "opening serial port successful" << endl; 224 | 225 | DCB dcb = {0}; // Device-control block used to configure serial communications 226 | dcb.DCBlength = sizeof(DCB); 227 | GetCommState(comPort, &dcb); 228 | dcb.BaudRate = CBR_115200; // Set baud rate to 115200 229 | dcb.ByteSize = 8; 230 | SetCommState(comPort, &dcb); 231 | 232 | // Set up a read timeout 233 | COMMTIMEOUTS timeouts; 234 | GetCommTimeouts(comPort, &timeouts); 235 | timeouts.ReadIntervalTimeout = 5; 236 | SetCommTimeouts(comPort, &timeouts); 237 | 238 | uint8_t driveMode = getDriveMode(); 239 | cout << "drive mode: " << to_string(driveMode) << endl; 240 | 241 | float tCoil = getTCoil(); 242 | cout << "t_coil: " << to_string(tCoil) << endl; 243 | 244 | float zeroSpinThrottle = getZeroSpinThrottle(); 245 | cout << "zero spin throttle: " << to_string(zeroSpinThrottle) << endl; 246 | 247 | IFCITelemetryData telemetry = getTelemetry(); 248 | cout << "telemetry coil_temp: " << telemetry.coil_temp << endl; 249 | cout << "telemetry consumption: " << telemetry.consumption << endl; 250 | cout << "telemetry current: " << telemetry.current << endl; 251 | cout << "telemetry mcu temp: " << telemetry.mcu_temp << endl; 252 | cout << "telemetry speed: " << telemetry.speed << endl; 253 | cout << "telemetry uptime: " << telemetry.uptime << endl; 254 | cout << "telemetry voltage: " << telemetry.voltage << endl; 255 | 256 | uint32_t formatKey1 = getFormatKey1(); 257 | cout << "format key 1: " << to_string(formatKey1) << endl; 258 | 259 | float volts = getVolts(); 260 | cout << "volts: " << to_string(volts) << endl; 261 | 262 | float voltInputLow = getVoltInputLow(); 263 | cout << "volt input low: " << to_string(voltInputLow) << endl; 264 | 265 | uint8_t timeoutSongOption = getTimeoutSongOption(); 266 | cout << "timeout song option: " << to_string(timeoutSongOption) << endl; 267 | 268 | uint8_t pulsingVoltageMode = getPulsingVoltageMode(); 269 | cout << "pulsing voltage mode: " << to_string(pulsingVoltageMode) << endl; 270 | 271 | uint32_t baudRate = getBaudRate(); 272 | cout << "baud rate: " << to_string(baudRate) << endl; 273 | 274 | uint32_t uid1 = getUid1(); 275 | cout << "uid1: " << to_string(uid1) << endl; 276 | 277 | uint32_t controlFlags = getControlFlags(); 278 | cout << "control flags: " << to_string(controlFlags) << endl; 279 | 280 | // float temp = getTemp(); 281 | // cout << "temp: " << to_string(temp) << endl; 282 | 283 | float ucTemp = getUcTemp(); 284 | cout << "uc temp: " << to_string(ucTemp) << endl; 285 | 286 | uint8_t frequency = getFrequency(); 287 | cout << "frequency: " << to_string(frequency) << endl; 288 | 289 | return 0; 290 | } -------------------------------------------------------------------------------- /src/packet_finder.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2019 IQinetics Technologies, Inc support@iq-control.com 3 | 4 | This file is part of the IQ C++ API. 5 | 6 | This code is licensed under the MIT license (see LICENSE or https://opensource.org/licenses/MIT for details) 7 | */ 8 | 9 | /* 10 | Name: packet_finder.c 11 | Last update: 3/7/2019 by Raphael Van Hoffelen 12 | Author: James Paulos 13 | Contributors: Matthew Piccoli, Raphael Van Hoffelen 14 | */ 15 | 16 | // http://xkcd.com/1421 17 | 18 | #include "packet_finder.h" 19 | #include "crc_helper.h" 20 | #include "string.h" 21 | 22 | //#define DEBUG 23 | #ifdef DEBUG 24 | #include 25 | void PrintFromBuffer(struct PacketFinder *pf, uint16_t index, uint16_t length); 26 | #define DEBUG_PRINT_TXT(arg) printf(arg); 27 | #else 28 | #define DEBUG_PRINT_TXT(arg) 29 | #endif 30 | 31 | 32 | 33 | const uint8_t kMaxPacketSize = MAX_PACKET_SIZE; /// max packet size 34 | const uint8_t kMaxPacketDataSize = MAX_PACKET_DATA_SIZE; /// max size data 35 | const uint8_t kStartByte = 0x55; /// special start byte 36 | 37 | void IncrementParseIndex(struct PacketFinder* pf); 38 | void FlushUnusedBytes(struct PacketFinder* pf); 39 | 40 | #define SUCCESS (0) 41 | #define BUFFER_OVERFLOW (-1) 42 | #define FATAL_ERROR (-2) 43 | 44 | 45 | void InitPacketFinder(struct PacketFinder *pf, struct ByteQueue *bq) { 46 | 47 | // parser state machine 48 | pf->state = kStart; 49 | pf->parse_index = 0; 50 | pf->packet_start_index = 0; // index of length byte in the buffer, type and data follow 51 | pf->received_length = 0; 52 | pf->packet_indices = bq; 53 | 54 | // circular buffer in storage array 'buffer', size 'PACKET_BUFFER_SIZE' 55 | pf->start_data = pf->buffer; // pointer to first data byte 56 | pf->end_data = pf->buffer; // pointer to byte following last data byte 57 | } 58 | 59 | 60 | int8_t PutBytes(struct PacketFinder *pf, const uint8_t *bytes, uint16_t bytes_length) { 61 | 62 | // flush any bytes in parser that are no longer needed 63 | FlushUnusedBytes(pf); 64 | 65 | /////////////////////////////////////////////////// 66 | // copy new data to buffer 67 | 68 | int8_t buffer_status = BUFFER_OVERFLOW; // put failure, data loss 69 | 70 | // if end_data comes before start_data, the buffer is wrapped around 71 | // and the available storage is guarenteed continuous 72 | if(pf->end_data < pf->start_data) { 73 | uint16_t space = pf->start_data - pf->end_data - 1; // space available 74 | 75 | uint16_t copy_size = space; // calculate copy_size 76 | if(copy_size > bytes_length) 77 | copy_size = bytes_length; 78 | 79 | memcpy(pf->end_data, bytes, copy_size); // do copy 80 | pf->end_data += copy_size; 81 | 82 | if(copy_size == bytes_length) // check for data loss 83 | buffer_status = SUCCESS; // success 84 | } 85 | 86 | // otherwise available storage might be broken into two pieces 87 | else { 88 | // if first data byte is occupied, last data byte must not be filled 89 | uint8_t* current_end = pf->buffer + PACKET_BUFFER_SIZE; 90 | if(pf->start_data == pf->buffer) 91 | current_end--; 92 | 93 | // calculate amount of space near end and near beginning 94 | uint16_t start_space, end_space; 95 | end_space = current_end - pf->end_data; 96 | if(pf->start_data == pf->buffer) 97 | start_space = 0; 98 | else 99 | start_space = pf->start_data - pf->buffer - 1; 100 | 101 | // calculate first_half and second_half copy sizes (near end and at beginning) 102 | uint16_t first_half = end_space; 103 | if(first_half > bytes_length) 104 | first_half = bytes_length; 105 | uint16_t second_half = start_space; 106 | if(second_half > bytes_length - first_half) 107 | second_half = bytes_length - first_half; 108 | 109 | // copy first half, then second half 110 | memcpy(pf->end_data, bytes, first_half); 111 | if(second_half == 0) { 112 | pf->end_data += first_half; 113 | if(pf->end_data > &(pf->buffer[PACKET_BUFFER_SIZE-1])) 114 | pf->end_data = pf->buffer; 115 | } 116 | else { 117 | memcpy(pf->buffer, &(bytes[first_half]), second_half); 118 | pf->end_data = pf->buffer + second_half; 119 | } 120 | 121 | // check for data loss 122 | if(first_half + second_half == bytes_length) 123 | buffer_status = SUCCESS; // success 124 | } 125 | 126 | 127 | /////////////////////////////////////////////////// 128 | // run parser to exhaustion 129 | 130 | uint16_t end_data_index = pf->end_data - pf->buffer; 131 | while( pf->parse_index != end_data_index) { // parser incrementing 132 | 133 | switch(pf->state) { 134 | 135 | case kStart: 136 | // if start symbol, advance state 137 | if(pf->buffer[pf->parse_index] == kStartByte) { 138 | pf->state = kLen; 139 | } 140 | // always advance parse index and start index 141 | IncrementParseIndex(pf); 142 | pf->packet_start_index = pf->parse_index; 143 | break; 144 | 145 | case kLen: 146 | pf->packet_start_index = pf->parse_index; 147 | 148 | // if length is reasonable 149 | if(pf->buffer[pf->parse_index] <= kMaxPacketDataSize) { 150 | // store index location, store length, start CRC calculation 151 | pf->received_length = pf->buffer[pf->parse_index]; 152 | pf->expected_crc = MakeCrc(&pf->buffer[pf->parse_index], 1); 153 | // increment parse index and parse state 154 | pf->state = kType; 155 | IncrementParseIndex(pf); 156 | } 157 | // else length unreasonable 158 | else { 159 | // start over at this index 160 | pf->state = kStart; 161 | } 162 | break; 163 | 164 | case kType: 165 | pf->expected_crc = ByteUpdateCrc(pf->expected_crc, pf->buffer[pf->parse_index]); 166 | 167 | if(pf->received_length > 0) 168 | pf->state = kData; 169 | else 170 | pf->state = kCRCL; 171 | 172 | pf->data_bytes = 0; //? 173 | IncrementParseIndex(pf); 174 | break; 175 | 176 | case kData: 177 | pf->expected_crc = ByteUpdateCrc(pf->expected_crc, pf->buffer[pf->parse_index]); 178 | pf->data_bytes++; 179 | if(pf->data_bytes >= pf->received_length) 180 | pf->state = kCRCL; 181 | IncrementParseIndex(pf); 182 | break; 183 | 184 | case kCRCL: 185 | pf->received_crc = pf->buffer[pf->parse_index]; 186 | pf->state = kCRCH; 187 | IncrementParseIndex(pf); 188 | break; 189 | 190 | case kCRCH: 191 | pf->received_crc = pf->received_crc + 256*pf->buffer[pf->parse_index]; 192 | // if pass the CRC check 193 | if(pf->expected_crc == pf->received_crc) { 194 | // add packet to outgoing queue 195 | PutByteBQ(pf->packet_indices, pf->packet_start_index); 196 | 197 | #ifdef DEBUG 198 | printf("Found: "); 199 | PrintFromBuffer(pf, pf->packet_start_index+1, pf->received_length+1); 200 | printf("\n"); 201 | #endif 202 | 203 | IncrementParseIndex(pf); 204 | pf->state = kStart; 205 | } 206 | // else fail the CRC check 207 | else { 208 | // restart parser at assumed length byte 209 | pf->parse_index = pf->packet_start_index; 210 | pf->state = kStart; 211 | } 212 | break; 213 | 214 | default: 215 | return(FATAL_ERROR); 216 | } // switch(pf->state) 217 | } // while( pf->parse_index...) 218 | 219 | return(buffer_status); 220 | } 221 | 222 | 223 | int8_t PeekPacket(struct PacketFinder *pf, uint8_t **packet, uint8_t *length) { 224 | 225 | if(!IsEmptyBQ(pf->packet_indices)) { 226 | 227 | // get return index and length 228 | uint16_t start_index = PeekByteBQ(pf->packet_indices); 229 | uint16_t return_index = start_index + 1; 230 | if(return_index >= PACKET_BUFFER_SIZE) 231 | return_index = 0; 232 | *length = pf->buffer[start_index] + 1; 233 | 234 | #ifdef DEBUG 235 | printf("Peek: "); 236 | PrintFromBuffer(pf, return_index, *length); 237 | printf("\n"); 238 | #endif 239 | 240 | // if packet is contiguous, return direct pointer into buffer 241 | if(return_index + *length < PACKET_BUFFER_SIZE) { 242 | *packet = &(pf->buffer[return_index]); 243 | } 244 | 245 | // else copy to out_buffer and return pointer to that 246 | else { 247 | uint16_t length_at_end = PACKET_BUFFER_SIZE - return_index; 248 | 249 | memcpy( &(pf->out_buffer[0]), 250 | &(pf->buffer[return_index]), 251 | length_at_end); // overflow out would cause a segfault 252 | 253 | 254 | memcpy( &(pf->out_buffer[length_at_end]), 255 | pf->buffer, 256 | *length - length_at_end); 257 | 258 | *packet = pf->out_buffer; 259 | } 260 | return(1); 261 | } 262 | return(0); 263 | } 264 | 265 | 266 | int8_t DropPacket(struct PacketFinder *pf) { 267 | 268 | if(!IsEmptyBQ(pf->packet_indices)) { 269 | 270 | // get previous return index and length 271 | uint16_t prev_start_index = GetByteBQ(pf->packet_indices); 272 | uint16_t prev_return_index = prev_start_index + 1; 273 | if(prev_return_index >= PACKET_BUFFER_SIZE) 274 | prev_return_index = 0; 275 | uint8_t prev_length = pf->buffer[prev_start_index] + 1; 276 | 277 | // if still more packets, dump up to next packet start 278 | if(!IsEmptyBQ(pf->packet_indices)) { 279 | pf->start_data = &(pf->buffer[PeekByteBQ(pf->packet_indices)]); 280 | } 281 | // otherwise dump only used up bytes 282 | else { 283 | 284 | // if packet was contiguous 285 | if(prev_return_index + prev_length <= PACKET_BUFFER_SIZE) { 286 | 287 | uint16_t new_start_index = prev_return_index + prev_length; 288 | if(new_start_index >= PACKET_BUFFER_SIZE) 289 | new_start_index = 0; 290 | pf->start_data = &(pf->buffer[new_start_index]); 291 | } 292 | 293 | // not contiguous 294 | else { 295 | uint16_t length_at_end = PACKET_BUFFER_SIZE - prev_return_index; 296 | pf->start_data = &(pf->buffer[prev_length - length_at_end]); 297 | } 298 | } 299 | 300 | return(1); 301 | } 302 | return(0); 303 | } 304 | 305 | 306 | int8_t GetPacketCopy(struct PacketFinder *pf, uint8_t *packet_copy, uint8_t *length) { 307 | 308 | uint8_t *packet_original; 309 | int8_t status = PeekPacket(pf, &packet_original, length); 310 | if(1 == status) { 311 | memcpy( packet_copy, packet_original, *length); 312 | DropPacket(pf); 313 | return(1); 314 | } 315 | return(0); 316 | } 317 | 318 | 319 | void IncrementParseIndex(struct PacketFinder* pf) { 320 | pf->parse_index++; 321 | if(pf->parse_index >= PACKET_BUFFER_SIZE) 322 | pf->parse_index = pf->parse_index - PACKET_BUFFER_SIZE; 323 | } 324 | 325 | 326 | void FlushUnusedBytes(struct PacketFinder* pf) { 327 | // if no out bytes are queued 328 | if(IsEmptyBQ(pf->packet_indices)) { 329 | // start of data is start of working packet 330 | pf->start_data = &(pf->buffer[pf->packet_start_index]); 331 | } 332 | else { 333 | // start of data is start of stored packet 334 | pf->start_data = &(pf->buffer[PeekByteBQ(pf->packet_indices)]); 335 | } 336 | } 337 | 338 | 339 | int8_t FormPacket(uint8_t type, 340 | const uint8_t *in_data, uint8_t in_len, 341 | uint8_t *out_data, uint8_t *out_len) { 342 | 343 | out_data[0] = kStartByte; 344 | out_data[1] = in_len; 345 | out_data[2] = type; 346 | 347 | // memcpy( &(out_data[i+3]), in_data, in_len); // untested, faster alternative 348 | uint8_t i = 0; 349 | for(i=0; i> 8; 356 | 357 | *out_len = in_len+5; 358 | return(1); 359 | } 360 | 361 | 362 | #ifdef DEBUG 363 | void PrintFromBuffer(struct PacketFinder *pf, uint16_t index, uint16_t length) { 364 | printf("[ "); 365 | uint8_t i = 0; 366 | for(i=0; ibuffer[index]); 368 | index++; 369 | if(index >= PACKET_BUFFER_SIZE) 370 | index = 0; 371 | } 372 | printf("]"); 373 | } 374 | #endif 375 | --------------------------------------------------------------------------------