From 40777012df05ca9c37698c9a31939f9c12b7430f Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 11 Sep 2022 19:35:28 +0800 Subject: [PATCH 01/35] re-added gyro similar to hitechnic-compass --- CMakeLists.txt | 3 +++ lib/gyro-sensor/gyro.hpp | 33 +++++++++++++++++++++++++++++++++ lib/utilities/utilities.hpp | 5 +++++ 3 files changed, 41 insertions(+) create mode 100644 lib/gyro-sensor/gyro.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 67c2372..d261a05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,9 @@ add_library( lib/motor/motor.cpp + lib/color-sensor/color-sensor.hpp + lib/gyro-sensor/gyro.hpp + lib/omni/omni.cpp lib/vector/vector.cpp diff --git a/lib/gyro-sensor/gyro.hpp b/lib/gyro-sensor/gyro.hpp new file mode 100644 index 0000000..d10257d --- /dev/null +++ b/lib/gyro-sensor/gyro.hpp @@ -0,0 +1,33 @@ +#include +#ifndef EV3WRAPGYRO_HPP_ +#define EV3WRAPGYRO_HPP_ + +namespace Ev3Wrap { +using namespace ev3dev; + +class GyroSensor : public normal_sensor { + public: + int offset; + static GyroSensor bind(address_type addr = INPUT_AUTO) { + return GyroSensor(addr); + }; + using normal_sensor::INPUT_1; + using normal_sensor::INPUT_2; + using normal_sensor::INPUT_3; + using normal_sensor::INPUT_4; + int getAbsoluteDirection() { + set_mode("GYRO-ANG"); + return (value(0) % 360) - 180; + } + int getRelativeDirection() { + return this->getAbsoluteDirection() - this->offset; + } + void setZero() { + this->offset = this->getAbsoluteDirection(); + } + private: + GyroSensor(address_type addr = INPUT_AUTO) : normal_sensor(addr, { ev3_gyro }) { this->offset = 0; }; +}; +} // namespace Ev3Wrap + +#endif \ No newline at end of file diff --git a/lib/utilities/utilities.hpp b/lib/utilities/utilities.hpp index d139749..2f68088 100644 --- a/lib/utilities/utilities.hpp +++ b/lib/utilities/utilities.hpp @@ -52,6 +52,11 @@ namespace Beeper { args << " -d " << std::to_string(beepRepeatDelay); ev3dev::sound::beep(args.str(), block); } + static void quickBeep(int hz = 750, int milliseconds = 100) { + setBeepHertz(hz); + setBeepDuration(milliseconds); + beep(false); + } } From 9abc99437691cbc7070fc9c8b416aef8c1193a0b Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 18 Sep 2022 11:44:10 +0800 Subject: [PATCH 02/35] constructor try catching --- lib/bbr-irseeker/bbr-irseeker.cpp | 8 +++++--- lib/color-sensor/color-sensor.hpp | 9 ++++++++- lib/ev3dev.cpp | 2 +- lib/hitechnic-compass/hitechnic-compass.cpp | 6 +++++- lib/hitechnic-irseeker/hitechnic-irseeker.cpp | 9 ++++++++- lib/motor/motor.cpp | 9 ++++++++- lib/ultrasonic-sensor/ultrasonic-sensor.hpp | 9 ++++++++- lib/utilities/utilities.hpp | 5 +++++ 8 files changed, 48 insertions(+), 9 deletions(-) diff --git a/lib/bbr-irseeker/bbr-irseeker.cpp b/lib/bbr-irseeker/bbr-irseeker.cpp index fa2b2e5..ff11b46 100644 --- a/lib/bbr-irseeker/bbr-irseeker.cpp +++ b/lib/bbr-irseeker/bbr-irseeker.cpp @@ -50,10 +50,12 @@ __s32 BBRIrSeeker::i2cReadInt(int fd, __u8 address) void BBRIrSeeker::i2cReadBlockData(int fd, __u8 address, __u8 length, __u8 *values) { - if (0 > i2c_smbus_read_i2c_block_data(fd, address,length,values)) + int potentialError = i2c_smbus_read_i2c_block_data(fd, address, length, values); + if (0 > potentialError) { + std::string msg = "BBR IrSeeker encountered an error while reading. Error code: " + std::to_string(potentialError); close(fd); - exit(4); + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); } } @@ -61,7 +63,7 @@ void BBRIrSeeker::getBoth(int* direction = nullptr, int* strength = nullptr) { int fd = this->begin(); __u8 values[2]; this->i2cReadBlockData(fd, 0x08, 2, values); - close (fd); + close(fd); if (strength != nullptr) { *strength = (int)values[1]; } diff --git a/lib/color-sensor/color-sensor.hpp b/lib/color-sensor/color-sensor.hpp index 839519e..69ac41f 100644 --- a/lib/color-sensor/color-sensor.hpp +++ b/lib/color-sensor/color-sensor.hpp @@ -16,6 +16,7 @@ */ #include +#include #ifndef EV3WRAPCOLOR_HPP_ #define EV3WRAPCOLOR_HPP_ @@ -64,7 +65,13 @@ class ColorSensor : public normal_sensor { return value(0); } private: - ColorSensor(address_type addr = INPUT_AUTO) : normal_sensor(addr, { ev3_color }) {} + ColorSensor(address_type addr = INPUT_AUTO) try : normal_sensor(addr, { ev3_color }) { + + } + catch(...) { + std::string msg = "Color sensor failed to initialise at port " + addr; + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); + } }; } diff --git a/lib/ev3dev.cpp b/lib/ev3dev.cpp index 3e19bc6..ddd5b1d 100644 --- a/lib/ev3dev.cpp +++ b/lib/ev3dev.cpp @@ -217,7 +217,7 @@ int device::device_index() const { using namespace std; if (_path.empty()) - throw system_error(make_error_code(errc::function_not_supported), "no device connected"); + throw system_error(make_error_code(errc::function_not_supported), "Device undetected: path not found?"); if (_device_index < 0) { unsigned f = 1; diff --git a/lib/hitechnic-compass/hitechnic-compass.cpp b/lib/hitechnic-compass/hitechnic-compass.cpp index 1a8b5e7..2556aac 100644 --- a/lib/hitechnic-compass/hitechnic-compass.cpp +++ b/lib/hitechnic-compass/hitechnic-compass.cpp @@ -19,9 +19,13 @@ #include using namespace Ev3Wrap; -HiTechnicCompass::HiTechnicCompass(ev3dev::address_type addr) : ev3dev::i2c_sensor(addr, { "ht-nxt-compass" }) { +HiTechnicCompass::HiTechnicCompass(ev3dev::address_type addr) try : ev3dev::i2c_sensor(addr, { "ht-nxt-compass" }) { this->setZero(); } +catch(...) { + std::string msg = "HiTechnic Compass failed to initialise at port " + addr; + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); +} HiTechnicCompass Ev3Wrap::HiTechnicCompass::bind(ev3dev::address_type addr) { return HiTechnicCompass(addr); diff --git a/lib/hitechnic-irseeker/hitechnic-irseeker.cpp b/lib/hitechnic-irseeker/hitechnic-irseeker.cpp index 13c2818..ea351f4 100644 --- a/lib/hitechnic-irseeker/hitechnic-irseeker.cpp +++ b/lib/hitechnic-irseeker/hitechnic-irseeker.cpp @@ -17,9 +17,16 @@ #include #include +#include using namespace Ev3Wrap; -HiTechnicIrSeeker::HiTechnicIrSeeker(ev3dev::address_type addr) : ev3dev::i2c_sensor(addr, { "ht-nxt-ir-seek-v2" }) {} +HiTechnicIrSeeker::HiTechnicIrSeeker(ev3dev::address_type addr) try : ev3dev::i2c_sensor(addr, { "ht-nxt-ir-seek-v2" }) { + +} +catch(...) { + std::string msg = "HiTechnic IrSeeker failed to initialise at port " + addr; + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); +} HiTechnicIrSeeker HiTechnicIrSeeker::bind(ev3dev::address_type addr) { return HiTechnicIrSeeker(addr); } diff --git a/lib/motor/motor.cpp b/lib/motor/motor.cpp index c0c22b1..6d3066c 100644 --- a/lib/motor/motor.cpp +++ b/lib/motor/motor.cpp @@ -21,6 +21,7 @@ #include #include #include +#include using namespace Ev3Wrap; @@ -38,7 +39,13 @@ Motor Motor::bind(ev3dev::address_type addr) { } void Motor::initialize(ev3dev::address_type addr) { - connect({{ "address", { addr } }}); + try { + connect({{ "address", { addr } }}); + } + catch(...) { + std::string msg = "Motor failed to initialise at port " + addr; + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); + } } Motor::Motor(ev3dev::address_type addr) { diff --git a/lib/ultrasonic-sensor/ultrasonic-sensor.hpp b/lib/ultrasonic-sensor/ultrasonic-sensor.hpp index 3b458a4..07654fb 100644 --- a/lib/ultrasonic-sensor/ultrasonic-sensor.hpp +++ b/lib/ultrasonic-sensor/ultrasonic-sensor.hpp @@ -16,6 +16,7 @@ */ #include +#include #ifndef EV3WRAPULTRASONIC_HPP_ #define EV3WRAPULTRASONIC_HPP_ using namespace ev3dev; @@ -40,7 +41,13 @@ class UltrasonicSensor : private normal_sensor { } private: - UltrasonicSensor(address_type addr) : normal_sensor(addr, { ev3dev::sensor::ev3_ultrasonic, ev3dev::sensor::nxt_ultrasonic }) {} + UltrasonicSensor(address_type addr) try : normal_sensor(addr, { ev3dev::sensor::ev3_ultrasonic, ev3dev::sensor::nxt_ultrasonic }) { + + } + catch(...) { + std::string msg = "Ultrasonic sensor failed to initialise at port " + addr; + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); + } }; } // namespace Ev3Wrap diff --git a/lib/utilities/utilities.hpp b/lib/utilities/utilities.hpp index d139749..a2deb07 100644 --- a/lib/utilities/utilities.hpp +++ b/lib/utilities/utilities.hpp @@ -17,6 +17,7 @@ #include #include +#include #ifndef EV3WRAPUTILITIES_HPP_ #define EV3WRAPUTILITIES_HPP_ namespace Ev3Wrap { @@ -52,6 +53,10 @@ namespace Beeper { args << " -d " << std::to_string(beepRepeatDelay); ev3dev::sound::beep(args.str(), block); } + static void speak(std::string text) { + std::string commandText = "espeak \"" + text + "\" --stdout | aplay"; + std::system(commandText); + } } From 8731b8405178ffc45d2af5d74777e7bee981b7ae Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 18 Sep 2022 12:12:42 +0800 Subject: [PATCH 03/35] errors for when reading / writing commands or data --- lib/color-sensor/color-sensor.hpp | 6 +++++- lib/hitechnic-compass/hitechnic-compass.hpp | 6 +++++- lib/hitechnic-irseeker/hitechnic-irseeker.hpp | 18 +++++++++++++++--- lib/motor/motor.cpp | 6 +++++- lib/ultrasonic-sensor/ultrasonic-sensor.hpp | 6 +++++- 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/lib/color-sensor/color-sensor.hpp b/lib/color-sensor/color-sensor.hpp index 69ac41f..f998471 100644 --- a/lib/color-sensor/color-sensor.hpp +++ b/lib/color-sensor/color-sensor.hpp @@ -52,10 +52,14 @@ class ColorSensor : public normal_sensor { // - 5: Red // - 6: White // - 7: Brown - int getColor() { + int getColor() try { set_mode("COL-COLOR"); return value(0); } + catch(...) { + std::string msg = "Colour sensor failed to read colour"; + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); + } int getReflectedLightIntensity() { set_mode("COL-REFLECT"); return value(0); diff --git a/lib/hitechnic-compass/hitechnic-compass.hpp b/lib/hitechnic-compass/hitechnic-compass.hpp index f2cea69..2c0bed6 100644 --- a/lib/hitechnic-compass/hitechnic-compass.hpp +++ b/lib/hitechnic-compass/hitechnic-compass.hpp @@ -34,10 +34,14 @@ class HiTechnicCompass : private ev3dev::i2c_sensor { static constexpr char INPUT_3[] = "ev3-ports:in3:i2c1"; static constexpr char INPUT_4[] = "ev3-ports:in4:i2c1"; static HiTechnicCompass bind(ev3dev::address_type addr = ev3dev::INPUT_AUTO); - int getAbsoluteDirection() { + int getAbsoluteDirection() try { set_mode("COMPASS"); return this->value(0); } + catch(...) { + std::string msg = "HiTechnic Compass failed to read absolute direction"; + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); + } void beginCalibration(){ set_command("BEGIN-CAL"); } void endCalibration(){ set_command("END-CAL"); } diff --git a/lib/hitechnic-irseeker/hitechnic-irseeker.hpp b/lib/hitechnic-irseeker/hitechnic-irseeker.hpp index 4ceb106..a69a8e6 100644 --- a/lib/hitechnic-irseeker/hitechnic-irseeker.hpp +++ b/lib/hitechnic-irseeker/hitechnic-irseeker.hpp @@ -33,11 +33,15 @@ class HiTechnicIrSeeker : private ev3dev::i2c_sensor { static constexpr char INPUT_3[] = "ev3-ports:in3:i2c8"; static constexpr char INPUT_4[] = "ev3-ports:in4:i2c8"; static HiTechnicIrSeeker bind(ev3dev::address_type addr = ev3dev::INPUT_AUTO); - int getDirection() { + int getDirection() try { set_mode("AC"); return value(0); } - std::vector getAll() { + catch(...) { + std::string msg = "HiTechnic IrSeeker failed to get AC direction"; + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); + } + std::vector getAll() try { set_mode("AC-ALL"); return { value(0), @@ -48,7 +52,11 @@ class HiTechnicIrSeeker : private ev3dev::i2c_sensor { value(5) }; } - int getACStrength(int IrDirection = USE_SPECIFIC_IR_DIRECTION) { + catch(...) { + std::string msg = "HiTechnic IrSeeker failed to get all directional strengths"; + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); + } + int getACStrength(int IrDirection = USE_SPECIFIC_IR_DIRECTION) try { int dir; if(IrDirection != FALSE) { dir = IrDirection; @@ -75,6 +83,10 @@ class HiTechnicIrSeeker : private ev3dev::i2c_sensor { return values[sensorNum]; } } + catch(...) { + std::string msg = "HiTechnic IrSeeker failed to get AC strength"; + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); + } private: HiTechnicIrSeeker(ev3dev::address_type addr = ev3dev::INPUT_AUTO); }; diff --git a/lib/motor/motor.cpp b/lib/motor/motor.cpp index 6d3066c..b0c2728 100644 --- a/lib/motor/motor.cpp +++ b/lib/motor/motor.cpp @@ -66,12 +66,16 @@ bool Motor::connect(const std::map> &match) n return false; } -void Motor::runRpm(float rpm) { +void Motor::runRpm(float rpm) try { // set the speed to tachos per minute (tachos in a rotation * rotations per minute) set_attr_int("speed_sp", this->getTachosPerRotation() * rpm / 60); // start running motor forever set_attr_string("command", "run-forever"); } +catch(...) { + std::string msg = "Motor failed to run at rpm: " + std::to_string(rpm); + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); +} void Motor::stop(std::string stopAction) { set_attr_string("stop_action", stopAction); diff --git a/lib/ultrasonic-sensor/ultrasonic-sensor.hpp b/lib/ultrasonic-sensor/ultrasonic-sensor.hpp index 07654fb..1ba0e66 100644 --- a/lib/ultrasonic-sensor/ultrasonic-sensor.hpp +++ b/lib/ultrasonic-sensor/ultrasonic-sensor.hpp @@ -31,10 +31,14 @@ class UltrasonicSensor : private normal_sensor { static UltrasonicSensor bind(ev3dev::address_type addr = ev3dev::INPUT_AUTO) { return UltrasonicSensor(addr); } - float getCentimetres() { + float getCentimetres() try { set_mode("US-DIST-CM"); return float_value(0); } + catch(...) { + std::string msg = "Ultrasonic sensor failed to get distance"; + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); + } bool getSensorsNearby() { set_mode("US-LISTEN"); return value(0); From 0c84ccde48ceb7c4dfd8b5c24e833a5b32a74d5b Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 18 Sep 2022 12:26:02 +0800 Subject: [PATCH 04/35] fix compile issues --- lib/hitechnic-compass/hitechnic-compass.hpp | 1 + lib/hitechnic-irseeker/hitechnic-irseeker.cpp | 1 + lib/hitechnic-irseeker/hitechnic-irseeker.hpp | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/hitechnic-compass/hitechnic-compass.hpp b/lib/hitechnic-compass/hitechnic-compass.hpp index 2c0bed6..99325b2 100644 --- a/lib/hitechnic-compass/hitechnic-compass.hpp +++ b/lib/hitechnic-compass/hitechnic-compass.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #ifndef EV3WRAPCOMPASS_HPP_ #define EV3WRAPCOMPASS_HPP_ diff --git a/lib/hitechnic-irseeker/hitechnic-irseeker.cpp b/lib/hitechnic-irseeker/hitechnic-irseeker.cpp index ea351f4..331297e 100644 --- a/lib/hitechnic-irseeker/hitechnic-irseeker.cpp +++ b/lib/hitechnic-irseeker/hitechnic-irseeker.cpp @@ -18,6 +18,7 @@ #include #include #include +#include using namespace Ev3Wrap; HiTechnicIrSeeker::HiTechnicIrSeeker(ev3dev::address_type addr) try : ev3dev::i2c_sensor(addr, { "ht-nxt-ir-seek-v2" }) { diff --git a/lib/hitechnic-irseeker/hitechnic-irseeker.hpp b/lib/hitechnic-irseeker/hitechnic-irseeker.hpp index a69a8e6..dd34f11 100644 --- a/lib/hitechnic-irseeker/hitechnic-irseeker.hpp +++ b/lib/hitechnic-irseeker/hitechnic-irseeker.hpp @@ -22,6 +22,7 @@ #define USE_SPECIFIC_IR_DIRECTION FALSE #include #include +#include namespace Ev3Wrap { From 738a5e7f846bbe09d5534d5f72008303cdaba918 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 18 Sep 2022 12:37:20 +0800 Subject: [PATCH 05/35] fixed crashing problems --- lib/gyro-sensor/gyro.hpp | 12 ++++++++++-- lib/utilities/utilities.hpp | 3 ++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/gyro-sensor/gyro.hpp b/lib/gyro-sensor/gyro.hpp index d10257d..ecbd499 100644 --- a/lib/gyro-sensor/gyro.hpp +++ b/lib/gyro-sensor/gyro.hpp @@ -15,10 +15,14 @@ class GyroSensor : public normal_sensor { using normal_sensor::INPUT_2; using normal_sensor::INPUT_3; using normal_sensor::INPUT_4; - int getAbsoluteDirection() { + int getAbsoluteDirection() try { set_mode("GYRO-ANG"); return (value(0) % 360) - 180; } + catch(...) { + std::string msg = "Gyro Sensor failed to read absolute direction"; + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); + } int getRelativeDirection() { return this->getAbsoluteDirection() - this->offset; } @@ -26,7 +30,11 @@ class GyroSensor : public normal_sensor { this->offset = this->getAbsoluteDirection(); } private: - GyroSensor(address_type addr = INPUT_AUTO) : normal_sensor(addr, { ev3_gyro }) { this->offset = 0; }; + GyroSensor(address_type addr = INPUT_AUTO) try : normal_sensor(addr, { ev3_gyro }) { this->offset = 0; } + catch(...) { + std::string msg = "Gyro Sensor failed to initialise at port " + addr; + throw std::system_error(std::make_error_code(std::errc::no_such_device), msg); + } }; } // namespace Ev3Wrap diff --git a/lib/utilities/utilities.hpp b/lib/utilities/utilities.hpp index 676aae4..d842643 100644 --- a/lib/utilities/utilities.hpp +++ b/lib/utilities/utilities.hpp @@ -60,7 +60,8 @@ namespace Beeper { } static void speak(std::string text) { std::string commandText = "espeak \"" + text + "\" --stdout | aplay"; - std::system(commandText); + std::system(commandText.c_str()); // this is ok because std::system is blocking, so commandText doesn't get + // destroyed before the pointer is used } } From 6212be9bd0517e8fcf7927e2114104b7a7ad5ad4 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sat, 24 Sep 2022 20:53:22 +0800 Subject: [PATCH 06/35] support for robot to robot communication using bluetooth --- .github/workflows/compile-test-actions.yml | 2 +- CMakeLists.txt | 7 + docker/Dockerfile | 9 +- lib/bluetooth-socket/bluetooth-socket.cpp | 156 +++++++++++++++++++++ lib/bluetooth-socket/bluetooth-socket.hpp | 48 +++++++ scripts/compile.sh | 6 +- 6 files changed, 223 insertions(+), 5 deletions(-) create mode 100644 lib/bluetooth-socket/bluetooth-socket.cpp create mode 100644 lib/bluetooth-socket/bluetooth-socket.hpp diff --git a/.github/workflows/compile-test-actions.yml b/.github/workflows/compile-test-actions.yml index 955b216..5b76fb4 100644 --- a/.github/workflows/compile-test-actions.yml +++ b/.github/workflows/compile-test-actions.yml @@ -19,7 +19,7 @@ jobs: compile-inside-container: runs-on: ubuntu-latest container: - image: eisverygoodletter/debian-stretch-cross:latest + image: eisverygoodletter/debian-stretch-cross:bluetooth options: --user root steps: - uses: actions/checkout@v3 diff --git a/CMakeLists.txt b/CMakeLists.txt index d261a05..98667dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,9 @@ project(${LIBNAME} VERSION 3.0.0) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) message(STATUS ${OPTIMIZATION_LEVEL}) add_compile_options(${OPTIMIZATION_LEVEL}) +# unfortunately there are problems in +# libbluetooth so we must use -fpermissive +add_compile_options(-fpermissive) add_definitions(-DDEBUG_MODE_ENABLED) add_library( ${LIBNAME} @@ -50,6 +53,8 @@ add_library( lib/vector/vector.cpp + lib/bluetooth-socket/bluetooth-socket.cpp + lib/ev3dev.cpp lib/smbus.cpp ) @@ -75,6 +80,8 @@ foreach(subdir ${SUBDIRS}) message(STATUS ${subdir}) target_include_directories(${LIBNAME} PUBLIC ${PROJECT_SOURCE_DIR}/lib/${subdir}) endforeach() +target_include_directories(${LIBNAME} PUBLIC ~/crossCompileLibraries/libbluetooth/include/) +target_link_libraries(${LIBNAME} PRIVATE /home/compiler/crossCompileLibraries/libbluetooth/lib/arm-linux-gnueabi/libbluetooth.a) set_target_properties(${LIBNAME} PROPERTIES diff --git a/docker/Dockerfile b/docker/Dockerfile index 5af000d..613b989 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -10,4 +10,11 @@ RUN cd cmake-3.24.0 && \ make -j $(nproc) && \ sudo apt-get remove --purge cmake -y && \ sudo make install && \ - rm -r * \ No newline at end of file + rm -r * +# install libbluetooth-dev for cross compiling +RUN wget http://security.debian.org/debian-security/pool/updates/main/b/bluez/libbluetooth-dev_5.43-2+deb9u5_armel.deb +RUN dpkg -x libbluetooth-dev_5.43-2+deb9u5_armel.deb ./temp && \ + mkdir ./crossCompileLibraries && \ + mkdir ./crossCompileLibraries/libbluetooth && \ + cp -r ./temp/usr/. ./crossCompileLibraries/libbluetooth && \ + rm -r ./temp \ No newline at end of file diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp new file mode 100644 index 0000000..7ad234d --- /dev/null +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Ev3Wrap; + +BluetoothSocket BluetoothSocket::CreateBluetoothSocket(std::string dest = "", bool awokenFirst = true) { + return BluetoothSocket(dest, awokenFirst); +} + +BluetoothSocket::BluetoothSocket(std::string dest, bool awokenFirst) { + this->awokenFirst = awokenFirst; + this->hasDisconnected = false; + if (awokenFirst) { + // initialise into a server like thing + struct sockaddr_rc localAddr = { 0 }; + struct sockaddr_rc remoteAddr = { 0 }; + socklen_t opt = sizeof(remoteAddr); + this->mySocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + localAddr.rc_family = AF_BLUETOOTH; + localAddr.rc_bdaddr = *BDADDR_ANY; + localAddr.rc_channel = (uint8_t) BLUETOOTH_PORT; + bind(this->mySocket, (struct sockaddr *)&localAddr, sizeof(localAddr)); + listen(this->mySocket, BLUETOOTH_PORT); + + this->otherSocket = accept(this->mySocket, (struct sockaddr *)&remoteAddr, &opt); + ba2str(&remoteAddr.rc_bdaddr, this->otherSocketMAC); + std::cout << this->otherSocketMAC << " successfully connected\n"; + } + else { + if (dest == "") { + std::string msg = "destionation bluetooth MAC address was not given!\n"; + throw std::system_error(std::make_error_code(std::errc::no_such_device_or_address), msg); + } + struct sockaddr_rc addr = { 0 }; + char destination[18]; + strcpy(destination, dest.c_str()); + this->mySocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + addr.rc_family = AF_BLUETOOTH; + addr.rc_channel = (uint8_t) BLUETOOTH_PORT; + str2ba(destination, &addr.rc_bdaddr); + int success = connect(this->mySocket, (struct sockaddr*)&addr, sizeof(addr)); + if (success < 0) { + std::string msg = "client socket connection failed with code " + std::to_string(success); + throw std::system_error(std::make_error_code(std::errc::connection_refused), msg); + } + this->otherSocket = this->mySocket; + } +} + +BluetoothSocket::~BluetoothSocket() { + if (this->awokenFirst) { + // otherSocket and mySocket are 2 different individual sockets which need to be closed + close(this->otherSocket); + close(this->mySocket); + } + else { + // otherSocket and mySocket refer to the same thing + close(this->mySocket); + } +} + +bool BluetoothSocket::send(char* msg, int size) { + int status = write(this->otherSocket, msg, size); + return (status >= 0); +} + +bool BluetoothSocket::readValue(char* msg, int size) { + //char* buffer = (char*)malloc(sizeof(*msg)); + struct pollfd *pfds; + int nfds = 1; + pfds = (pollfd*)calloc(nfds, sizeof(*pfds)); + if (pfds == NULL) { + std::string msg = "Calloc failed: pfds is equal to NULL\n"; + throw std::system_error(std::make_error_code(std::errc::not_enough_memory), msg); + } + pfds[0].fd = this->otherSocket; + pfds[0].events = POLLIN; + int ready; + // block for 5 milliseconds + ready = poll(pfds, nfds, 5); + if (ready == 0) { + // timed out, not ready + free(pfds); + return false; + } + else { + if (pfds[0].revents & POLLERR) { + std::cout << "POLLERR\n"; + return false; + } + if (pfds[0].revents & POLLHUP) { + // communication ended + this->hasDisconnected = true; + free(pfds); + return false; + } + if (pfds[0].revents & POLLIN) { + // read values + int bytesRead; + bytesRead = read(this->otherSocket, msg, size); + std::cout << bytesRead << " bytes read\n"; + if (bytesRead <= 0) { + std::string msg = "POLLIN was detected however 0 bytes were read\n"; + throw std::system_error(std::make_error_code(std::errc::bad_message), msg); + } + free(pfds); + return true; + } + } +} + +void BluetoothSocket::listDetectedDevices() { + int deviceId = hci_get_route(NULL); + if (deviceId < 0) { + std::string msg = "bluetooth adapter not found\n"; + throw std::system_error(std::make_error_code(std::errc::address_not_available), msg); + } + // find nearby devices + int len = 8; + int maxRsp = 255; + int flags = IREQ_CACHE_FLUSH; + inquiry_info* iInfs = (inquiry_info*)malloc(maxRsp * sizeof(inquiry_info)); + int numRsp = hci_inquiry(deviceId, len, maxRsp, NULL, &iInfs, flags); + if (numRsp < 0) { + std::string msg = "hci_inquiry failed.\n"; + throw std::system_error(std::make_error_code(std::errc::network_unreachable), msg); + } + std::cout << "Found " << numRsp << " devices\n"; + int socket = hci_open_dev(deviceId); + if (socket < 0) { + std::string msg = "Failed to open socket\n"; + throw std::system_error(std::make_error_code(std::errc::network_unreachable), msg); + } + int i; + for (i = 0; i < numRsp; i++) { + char deviceAddress[20], deviceName[300]; + inquiry_info* currentDevice = iInfs + i; + ba2str(&(currentDevice->bdaddr), deviceAddress); + memset(deviceName, 0, sizeof(deviceName)); + if (hci_read_remote_name(socket, &(currentDevice->bdaddr), sizeof(deviceName), deviceName, 0) < 0) { + strcpy(deviceName, ""); + } + std::cout << deviceAddress << " | " << deviceName << '\n'; + } + close(socket); + free(iInfs); +} \ No newline at end of file diff --git a/lib/bluetooth-socket/bluetooth-socket.hpp b/lib/bluetooth-socket/bluetooth-socket.hpp new file mode 100644 index 0000000..c746a5f --- /dev/null +++ b/lib/bluetooth-socket/bluetooth-socket.hpp @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifndef EV3WRAPBLUETOOTH_SOCKET_HPP_ +#define EV3WRAPBLUETOOTH_SOCKET_HPP_ +#define BLUETOOTH_PORT 20 +#define CHAR_ARRAY_SIZE 32 +namespace Ev3Wrap { + +class BluetoothSocket { +public: + // file descriptors for sockets + // otherSocket is used for sending and receiving messages. + // mySocket is the one initialised for binding and listening etc. + // they are equal if awokenFirst = false + int mySocket, otherSocket; + // the MAC address of the other socket. Here for debugging purposes only + char otherSocketMAC[18]; + // send a char* buffer of data to the address. + // It is recommended that the msg char* be of length CHAR_ARRAY_SIZE. + // If the char* buffer size is above CHAR_ARRAY_SIZE, a custom size must be given + bool send(char* msg, int size = CHAR_ARRAY_SIZE); + // read the value of a socket and copy it into a char array. + // It is recommended that the msg char* be of length CHAR_ARRAY_SIZE. + // readValue returns false when there is no valid data to be read. + // readValue will not throw an error if the socket is disconnected; check hasDisconnected for that + // if the char* buffer size should NOT be under CHAR_ARRAY_SIZE (unless the sender is sending smaller messages) + bool readValue(char* msg, int size = CHAR_ARRAY_SIZE); + // if the socket has been disconnected + bool hasDisconnected; + // if this is true, it is a server socket which is meant to be turned on first, so that a client can connect to it + bool awokenFirst; + static void listDetectedDevices(); + // Create a bluetooth socket. dest (destination) is not required if it is a server socket (awokenFirst = true) + static BluetoothSocket CreateBluetoothSocket(std::string dest = "", bool awokenFirst = true); + ~BluetoothSocket(); +private: + BluetoothSocket(std::string dest = "", bool awokenFirst = true); +}; + +} // namespace Ev3Wrap + +#endif \ No newline at end of file diff --git a/scripts/compile.sh b/scripts/compile.sh index ba38833..762ee8e 100644 --- a/scripts/compile.sh +++ b/scripts/compile.sh @@ -23,12 +23,12 @@ entrypointCMD="/${scriptDir}/runWithinContainer.sh" if [[ "$OSTYPE" == "linux-gnu"* ]]; then docker rm ${containerName} - docker run --entrypoint ${entrypointCMD} --name ${containerName} -v /${srcDir}:/${srcDir} -w /${srcDir} eisverygoodletter/debian-stretch-cross $@ + docker run --entrypoint ${entrypointCMD} --name ${containerName} -v /${srcDir}:/${srcDir} -w /${srcDir} eisverygoodletter/debian-stretch-cross:bluetooth $@ elif [[ "$OSTYPE" == "darwin"* ]]; then docker rm ${containerName} - docker run --entrypoint ${entrypointCMD} --name ${containerName} -v /${srcDir}:/${srcDir} -w /${srcDir} eisverygoodletter/debian-stretch-cross $@ + docker run --entrypoint ${entrypointCMD} --name ${containerName} -v /${srcDir}:/${srcDir} -w /${srcDir} eisverygoodletter/debian-stretch-cross:bluetooth $@ else winpty docker rm ${containerName} - winpty docker run --entrypoint ${entrypointCMD} --name ${containerName} -v /${srcDir}:/${srcDir} -w /${srcDir} eisverygoodletter/debian-stretch-cross $@ + winpty docker run --entrypoint ${entrypointCMD} --name ${containerName} -v /${srcDir}:/${srcDir} -w /${srcDir} eisverygoodletter/debian-stretch-cross:bluetooth $@ fi $SHELL \ No newline at end of file From b8f7518cec87dbf460ae74d54b5f4a24fea36b16 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sat, 24 Sep 2022 21:01:31 +0800 Subject: [PATCH 07/35] update dockersetup.sh to get the new image version --- scripts/dockersetup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/dockersetup.sh b/scripts/dockersetup.sh index dfa59da..64bc8f4 100644 --- a/scripts/dockersetup.sh +++ b/scripts/dockersetup.sh @@ -14,5 +14,5 @@ # You should have received a copy of the GNU General Public License # along with The Ev3dev C++ Wrapper Library. If not, see . -docker pull eisverygoodletter/debian-stretch-cross:latest +docker pull eisverygoodletter/debian-stretch-cross:bluetooth echo "done pulling" \ No newline at end of file From ef181e121b5cc2c46ecfc833f486df51fd30c0b9 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sat, 24 Sep 2022 21:19:04 +0800 Subject: [PATCH 08/35] default optimization level fix --- scripts/runWithinContainer.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/runWithinContainer.sh b/scripts/runWithinContainer.sh index 8adb490..3f43adc 100644 --- a/scripts/runWithinContainer.sh +++ b/scripts/runWithinContainer.sh @@ -30,6 +30,8 @@ wipeBin=false # making it verbose may make the build slower verbose=false +optimizationLevel="-Os" + while getopts 'nwO:v' flag; do case "${flag}" in n) newFile=true ;; From 0de642997e9d6109b6df7f0e150aea8aac12ec40 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 07:17:54 +0800 Subject: [PATCH 09/35] attempted compile fix --- lib/bluetooth-socket/bluetooth-socket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index 7ad234d..063799d 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +//#include #include #include #include From 944f9dee1cb6d3e03e23eaf8f030e414885b4651 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 07:21:13 +0800 Subject: [PATCH 10/35] fixing compile errors --- .github/workflows/compile-test-actions.yml | 1 + lib/bluetooth-socket/bluetooth-socket.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compile-test-actions.yml b/.github/workflows/compile-test-actions.yml index 5b76fb4..8082c5f 100644 --- a/.github/workflows/compile-test-actions.yml +++ b/.github/workflows/compile-test-actions.yml @@ -27,6 +27,7 @@ jobs: path: ./ - name: compile it run: | + tree ~ sudo chmod +x ./scripts/runWithinContainer.sh sudo bash ./scripts/runWithinContainer.sh -w shell: bash diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index 063799d..6acb1bb 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -2,7 +2,6 @@ #include #include #include -//#include #include #include #include From 5bbfedef4bc8d48bb4b8eef00fe91d42ad465a59 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 07:25:33 +0800 Subject: [PATCH 11/35] potential difference in where ~ points to? --- .github/workflows/compile-test-actions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compile-test-actions.yml b/.github/workflows/compile-test-actions.yml index 8082c5f..1823efb 100644 --- a/.github/workflows/compile-test-actions.yml +++ b/.github/workflows/compile-test-actions.yml @@ -27,7 +27,7 @@ jobs: path: ./ - name: compile it run: | - tree ~ + tree . sudo chmod +x ./scripts/runWithinContainer.sh sudo bash ./scripts/runWithinContainer.sh -w shell: bash From 9ff53339e17774c408458b0ce11871c1e9ca5f3a Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 07:38:06 +0800 Subject: [PATCH 12/35] fix: ~ (pwd) was set to library directory, so libbluetooth needed an absolute path --- CMakeLists.txt | 2 +- scripts/compile.sh | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 98667dd..e1b223e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,7 +80,7 @@ foreach(subdir ${SUBDIRS}) message(STATUS ${subdir}) target_include_directories(${LIBNAME} PUBLIC ${PROJECT_SOURCE_DIR}/lib/${subdir}) endforeach() -target_include_directories(${LIBNAME} PUBLIC ~/crossCompileLibraries/libbluetooth/include/) +target_include_directories(${LIBNAME} PUBLIC /home/compiler/crossCompileLibraries/libbluetooth/include/) target_link_libraries(${LIBNAME} PRIVATE /home/compiler/crossCompileLibraries/libbluetooth/lib/arm-linux-gnueabi/libbluetooth.a) set_target_properties(${LIBNAME} diff --git a/scripts/compile.sh b/scripts/compile.sh index 762ee8e..3f5687c 100644 --- a/scripts/compile.sh +++ b/scripts/compile.sh @@ -20,7 +20,6 @@ scriptDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" srcDir=${scriptDir}/../ entrypointCMD="/${scriptDir}/runWithinContainer.sh" - if [[ "$OSTYPE" == "linux-gnu"* ]]; then docker rm ${containerName} docker run --entrypoint ${entrypointCMD} --name ${containerName} -v /${srcDir}:/${srcDir} -w /${srcDir} eisverygoodletter/debian-stretch-cross:bluetooth $@ From 8dbf7bcaf568de60e6e5fb826fdf3a1080407868 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 07:43:29 +0800 Subject: [PATCH 13/35] move default parameters to declaration and fixed some warnings --- lib/bluetooth-socket/bluetooth-socket.cpp | 7 +++++-- lib/bluetooth-socket/bluetooth-socket.hpp | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index 6acb1bb..b574707 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -15,7 +15,10 @@ BluetoothSocket BluetoothSocket::CreateBluetoothSocket(std::string dest = "", bo return BluetoothSocket(dest, awokenFirst); } -BluetoothSocket::BluetoothSocket(std::string dest, bool awokenFirst) { +// equivalent to *BDADDR_ANY, but won't make compiler warnings +#define DEREF_BDADDR_ANY (bdaddr_t) {{0, 0, 0, 0, 0, 0}} + +BluetoothSocket::BluetoothSocket(std::string dest = "", bool awokenFirst = true) { this->awokenFirst = awokenFirst; this->hasDisconnected = false; if (awokenFirst) { @@ -25,7 +28,7 @@ BluetoothSocket::BluetoothSocket(std::string dest, bool awokenFirst) { socklen_t opt = sizeof(remoteAddr); this->mySocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); localAddr.rc_family = AF_BLUETOOTH; - localAddr.rc_bdaddr = *BDADDR_ANY; + localAddr.rc_bdaddr = DEREF_BDADDR_ANY; localAddr.rc_channel = (uint8_t) BLUETOOTH_PORT; bind(this->mySocket, (struct sockaddr *)&localAddr, sizeof(localAddr)); listen(this->mySocket, BLUETOOTH_PORT); diff --git a/lib/bluetooth-socket/bluetooth-socket.hpp b/lib/bluetooth-socket/bluetooth-socket.hpp index c746a5f..c3538a1 100644 --- a/lib/bluetooth-socket/bluetooth-socket.hpp +++ b/lib/bluetooth-socket/bluetooth-socket.hpp @@ -37,10 +37,10 @@ class BluetoothSocket { bool awokenFirst; static void listDetectedDevices(); // Create a bluetooth socket. dest (destination) is not required if it is a server socket (awokenFirst = true) - static BluetoothSocket CreateBluetoothSocket(std::string dest = "", bool awokenFirst = true); + static BluetoothSocket CreateBluetoothSocket(std::string dest, bool awokenFirst); ~BluetoothSocket(); private: - BluetoothSocket(std::string dest = "", bool awokenFirst = true); + BluetoothSocket(std::string dest, bool awokenFirst); }; } // namespace Ev3Wrap From 6c2aa82dbe1a2c5fbe5eddc6d78bacc3a7a6931c Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 10:22:53 +0800 Subject: [PATCH 14/35] you can now create a bluetooth socket by hostname --- lib/bluetooth-socket/bluetooth-socket.cpp | 79 ++++++++++++++++++++--- lib/bluetooth-socket/bluetooth-socket.hpp | 6 +- 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index b574707..e5304a2 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -11,14 +11,14 @@ using namespace Ev3Wrap; -BluetoothSocket BluetoothSocket::CreateBluetoothSocket(std::string dest = "", bool awokenFirst = true) { +BluetoothSocket BluetoothSocket::CreateBluetoothSocket(std::string dest, bool awokenFirst) { return BluetoothSocket(dest, awokenFirst); } // equivalent to *BDADDR_ANY, but won't make compiler warnings #define DEREF_BDADDR_ANY (bdaddr_t) {{0, 0, 0, 0, 0, 0}} -BluetoothSocket::BluetoothSocket(std::string dest = "", bool awokenFirst = true) { +BluetoothSocket::BluetoothSocket(std::string dest, bool awokenFirst) { this->awokenFirst = awokenFirst; this->hasDisconnected = false; if (awokenFirst) { @@ -42,17 +42,25 @@ BluetoothSocket::BluetoothSocket(std::string dest = "", bool awokenFirst = true) std::string msg = "destionation bluetooth MAC address was not given!\n"; throw std::system_error(std::make_error_code(std::errc::no_such_device_or_address), msg); } - struct sockaddr_rc addr = { 0 }; + char destination[18]; strcpy(destination, dest.c_str()); this->mySocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - addr.rc_family = AF_BLUETOOTH; - addr.rc_channel = (uint8_t) BLUETOOTH_PORT; - str2ba(destination, &addr.rc_bdaddr); - int success = connect(this->mySocket, (struct sockaddr*)&addr, sizeof(addr)); - if (success < 0) { - std::string msg = "client socket connection failed with code " + std::to_string(success); - throw std::system_error(std::make_error_code(std::errc::connection_refused), msg); + while (true) { + struct sockaddr_rc addr = { 0 }; + addr.rc_family = AF_BLUETOOTH; + addr.rc_channel = (uint8_t) BLUETOOTH_PORT; + str2ba(destination, &addr.rc_bdaddr); + int success = connect(this->mySocket, (struct sockaddr*)&addr, sizeof(addr)); + if (success >= 0) { + std::cout << "Bluetooth socket connection succeeded\n"; + break; + } + else { + std::cout << "Bluetooth socket connection refused. Retrying...\n"; + close(this->mySocket); + this->mySocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + } } this->otherSocket = this->mySocket; } @@ -120,6 +128,57 @@ bool BluetoothSocket::readValue(char* msg, int size) { } } +BluetoothSocket BluetoothSocket::CreateBluetoothSocketByHostname(std::string hostname) { + int deviceId = hci_get_route(NULL); + if (deviceId < 0) { + std::string msg = "bluetooth adapter not found\n"; + throw std::system_error(std::make_error_code(std::errc::address_not_available), msg); + } + // find nearby devices + int len = 8; + int maxRsp = 255; + int flags = IREQ_CACHE_FLUSH; + inquiry_info* iInfs = (inquiry_info*)malloc(maxRsp * sizeof(inquiry_info)); + int socket = hci_open_dev(deviceId); + if (socket < 0) { + std::string msg = "Failed to open socket\n"; + throw std::system_error(std::make_error_code(std::errc::network_unreachable), msg); + } + while (true) { + memset(iInfs, 0, maxRsp * sizeof(inquiry_info)); + int numRsp = hci_inquiry(deviceId, len, maxRsp, NULL, &iInfs, flags); + if (numRsp < 0) { + std::string msg = "hci_inquiry failed.\n"; + throw std::system_error(std::make_error_code(std::errc::network_unreachable), msg); + } + if (numRsp != 0) { + // some are detected + std::cout << "Found " << numRsp << " devices\n"; + int i; + for (i = 0; i < numRsp; i++) { + char deviceAddress[20], deviceName[300]; + inquiry_info* currentDevice = iInfs + i; + memset(deviceAddress, 0, sizeof(deviceAddress)); + ba2str(&(currentDevice->bdaddr), deviceAddress); + memset(deviceName, 0, sizeof(deviceName)); + if (hci_read_remote_name(socket, &(currentDevice->bdaddr), sizeof(deviceName), deviceName, 0) < 0) { + continue; + } + else { + std::cout << deviceAddress << " | " << deviceName << " found\n"; + std::string strDeviceName(deviceName, hostname.length()); + if (strDeviceName == hostname) { + std::cout << "required address found. Connecting\n"; + close(socket); + free(iInfs); + return BluetoothSocket(std::string(deviceAddress), false); + } + } + } + } + } +} + void BluetoothSocket::listDetectedDevices() { int deviceId = hci_get_route(NULL); if (deviceId < 0) { diff --git a/lib/bluetooth-socket/bluetooth-socket.hpp b/lib/bluetooth-socket/bluetooth-socket.hpp index c3538a1..90fbcd4 100644 --- a/lib/bluetooth-socket/bluetooth-socket.hpp +++ b/lib/bluetooth-socket/bluetooth-socket.hpp @@ -37,10 +37,12 @@ class BluetoothSocket { bool awokenFirst; static void listDetectedDevices(); // Create a bluetooth socket. dest (destination) is not required if it is a server socket (awokenFirst = true) - static BluetoothSocket CreateBluetoothSocket(std::string dest, bool awokenFirst); + static BluetoothSocket CreateBluetoothSocket(std::string dest = "", bool awokenFirst = true); + // create a awokenFirst = false bluetooth socket. Searches for a list of hostnames and then connects to the one required + static BluetoothSocket CreateBluetoothSocketByHostname(std::string hostname); ~BluetoothSocket(); private: - BluetoothSocket(std::string dest, bool awokenFirst); + BluetoothSocket(std::string dest = "", bool awokenFirst = true); }; } // namespace Ev3Wrap From 2d3934a2c76b41fab3913f0a66ce32522a028567 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 10:34:38 +0800 Subject: [PATCH 15/35] client sockets should now correctly detect disconnects --- lib/bluetooth-socket/bluetooth-socket.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index e5304a2..4185841 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -80,6 +80,9 @@ BluetoothSocket::~BluetoothSocket() { bool BluetoothSocket::send(char* msg, int size) { int status = write(this->otherSocket, msg, size); + if (status == -1) { + this->hasDisconnected = true; + } return (status >= 0); } From 520fff74d6cd96b2a6566b9e8ffe8820ee246224 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 11:22:22 +0800 Subject: [PATCH 16/35] minor bug fixes --- lib/bluetooth-socket/bluetooth-socket.cpp | 11 ++++++----- lib/bluetooth-socket/bluetooth-socket.hpp | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index 4185841..5b1a2ec 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -32,7 +32,7 @@ BluetoothSocket::BluetoothSocket(std::string dest, bool awokenFirst) { localAddr.rc_channel = (uint8_t) BLUETOOTH_PORT; bind(this->mySocket, (struct sockaddr *)&localAddr, sizeof(localAddr)); listen(this->mySocket, BLUETOOTH_PORT); - + std::cout << "waiting for other side to attempt connection\n"; this->otherSocket = accept(this->mySocket, (struct sockaddr *)&remoteAddr, &opt); ba2str(&remoteAddr.rc_bdaddr, this->otherSocketMAC); std::cout << this->otherSocketMAC << " successfully connected\n"; @@ -87,12 +87,11 @@ bool BluetoothSocket::send(char* msg, int size) { } bool BluetoothSocket::readValue(char* msg, int size) { - //char* buffer = (char*)malloc(sizeof(*msg)); struct pollfd *pfds; int nfds = 1; pfds = (pollfd*)calloc(nfds, sizeof(*pfds)); if (pfds == NULL) { - std::string msg = "Calloc failed: pfds is equal to NULL\n"; + std::string msg = "Calloc failed: unexpected behavior; pfds is equal to NULL\n"; throw std::system_error(std::make_error_code(std::errc::not_enough_memory), msg); } pfds[0].fd = this->otherSocket; @@ -108,6 +107,8 @@ bool BluetoothSocket::readValue(char* msg, int size) { else { if (pfds[0].revents & POLLERR) { std::cout << "POLLERR\n"; + this->hasDisconnected = true; + free(pfds); return false; } if (pfds[0].revents & POLLHUP) { @@ -120,7 +121,6 @@ bool BluetoothSocket::readValue(char* msg, int size) { // read values int bytesRead; bytesRead = read(this->otherSocket, msg, size); - std::cout << bytesRead << " bytes read\n"; if (bytesRead <= 0) { std::string msg = "POLLIN was detected however 0 bytes were read\n"; throw std::system_error(std::make_error_code(std::errc::bad_message), msg); @@ -164,7 +164,8 @@ BluetoothSocket BluetoothSocket::CreateBluetoothSocketByHostname(std::string hos memset(deviceAddress, 0, sizeof(deviceAddress)); ba2str(&(currentDevice->bdaddr), deviceAddress); memset(deviceName, 0, sizeof(deviceName)); - if (hci_read_remote_name(socket, &(currentDevice->bdaddr), sizeof(deviceName), deviceName, 0) < 0) { + if (hci_read_remote_name(socket, &(currentDevice->bdaddr), sizeof(deviceName), deviceName, 0) == -1) { + std::cout << "could not get remote name errno: " << errno << '\n'; continue; } else { diff --git a/lib/bluetooth-socket/bluetooth-socket.hpp b/lib/bluetooth-socket/bluetooth-socket.hpp index 90fbcd4..eccded3 100644 --- a/lib/bluetooth-socket/bluetooth-socket.hpp +++ b/lib/bluetooth-socket/bluetooth-socket.hpp @@ -41,6 +41,8 @@ class BluetoothSocket { // create a awokenFirst = false bluetooth socket. Searches for a list of hostnames and then connects to the one required static BluetoothSocket CreateBluetoothSocketByHostname(std::string hostname); ~BluetoothSocket(); + // reconnect with the same address provided. will throw an error if hasDisconnect = false + // if the socket is a client socket, attempts to connect to the server private: BluetoothSocket(std::string dest = "", bool awokenFirst = true); }; From 2f3f6cf15e05b6fd188731abcdce8fa60a189b46 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 13:08:57 +0800 Subject: [PATCH 17/35] memory leak fixes --- lib/bluetooth-socket/bluetooth-socket.cpp | 38 ++++++++++++++++++++--- lib/bluetooth-socket/bluetooth-socket.hpp | 3 ++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index 5b1a2ec..651f96f 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -33,7 +33,20 @@ BluetoothSocket::BluetoothSocket(std::string dest, bool awokenFirst) { bind(this->mySocket, (struct sockaddr *)&localAddr, sizeof(localAddr)); listen(this->mySocket, BLUETOOTH_PORT); std::cout << "waiting for other side to attempt connection\n"; + // loop until a connection is ready + struct pollfd *pfd = (pollfd*)calloc(1, sizeof(*pfd)); + pfd[0].fd = this->mySocket; + pfd[0].events = POLLIN; + int res = poll(pfd, 1, 5); + std::cout << res << '\n'; + while (res == 0) { + res = poll(pfd, 1, 5); + std::cout << "No connection attempt has been made yet...\n"; + } + free(pfd); + this->otherSocket = accept(this->mySocket, (struct sockaddr *)&remoteAddr, &opt); + this->otherSocketMAC = (char*)malloc(sizeof(char) * 18); ba2str(&remoteAddr.rc_bdaddr, this->otherSocketMAC); std::cout << this->otherSocketMAC << " successfully connected\n"; } @@ -57,12 +70,14 @@ BluetoothSocket::BluetoothSocket(std::string dest, bool awokenFirst) { break; } else { - std::cout << "Bluetooth socket connection refused. Retrying...\n"; + std::cout << "Bluetooth socket server refused connection. Retrying...\n"; close(this->mySocket); this->mySocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); } } this->otherSocket = this->mySocket; + this->otherSocketMAC = (char*)malloc(sizeof(char) * 18) + strcpy(this->otherSocketMAC, destination); } } @@ -81,7 +96,7 @@ BluetoothSocket::~BluetoothSocket() { bool BluetoothSocket::send(char* msg, int size) { int status = write(this->otherSocket, msg, size); if (status == -1) { - this->hasDisconnected = true; + this->fireDisconnect(); } return (status >= 0); } @@ -106,14 +121,16 @@ bool BluetoothSocket::readValue(char* msg, int size) { } else { if (pfds[0].revents & POLLERR) { + // error when polling + // very likely due to socket closed std::cout << "POLLERR\n"; - this->hasDisconnected = true; + this->fireDisconnect(); free(pfds); return false; } if (pfds[0].revents & POLLHUP) { // communication ended - this->hasDisconnected = true; + this->fireDisconnect(); free(pfds); return false; } @@ -218,4 +235,17 @@ void BluetoothSocket::listDetectedDevices() { } close(socket); free(iInfs); +} + +void BluetoothSocket::fireDisconnect() { + if (this->awokenFirst) { + close(this->mySocket); + close(this->otherSocket); + } + else { + close(this->otherSocket); + } + this->mySocket = 0; + this->otherSocket = 0; + this->hasDisconnected = true; } \ No newline at end of file diff --git a/lib/bluetooth-socket/bluetooth-socket.hpp b/lib/bluetooth-socket/bluetooth-socket.hpp index eccded3..8de3525 100644 --- a/lib/bluetooth-socket/bluetooth-socket.hpp +++ b/lib/bluetooth-socket/bluetooth-socket.hpp @@ -44,7 +44,10 @@ class BluetoothSocket { // reconnect with the same address provided. will throw an error if hasDisconnect = false // if the socket is a client socket, attempts to connect to the server private: + // actual constructor BluetoothSocket(std::string dest = "", bool awokenFirst = true); + // deactivate mySocket and otherSocket + void fireDisconnect(); }; } // namespace Ev3Wrap From dc636e94c443dff37c415c17080a1606e6b44cdf Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 13:11:26 +0800 Subject: [PATCH 18/35] misread my own code --- lib/bluetooth-socket/bluetooth-socket.cpp | 2 -- lib/bluetooth-socket/bluetooth-socket.hpp | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index 651f96f..4e8ce13 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -46,7 +46,6 @@ BluetoothSocket::BluetoothSocket(std::string dest, bool awokenFirst) { free(pfd); this->otherSocket = accept(this->mySocket, (struct sockaddr *)&remoteAddr, &opt); - this->otherSocketMAC = (char*)malloc(sizeof(char) * 18); ba2str(&remoteAddr.rc_bdaddr, this->otherSocketMAC); std::cout << this->otherSocketMAC << " successfully connected\n"; } @@ -76,7 +75,6 @@ BluetoothSocket::BluetoothSocket(std::string dest, bool awokenFirst) { } } this->otherSocket = this->mySocket; - this->otherSocketMAC = (char*)malloc(sizeof(char) * 18) strcpy(this->otherSocketMAC, destination); } } diff --git a/lib/bluetooth-socket/bluetooth-socket.hpp b/lib/bluetooth-socket/bluetooth-socket.hpp index 8de3525..0747e53 100644 --- a/lib/bluetooth-socket/bluetooth-socket.hpp +++ b/lib/bluetooth-socket/bluetooth-socket.hpp @@ -33,6 +33,8 @@ class BluetoothSocket { bool readValue(char* msg, int size = CHAR_ARRAY_SIZE); // if the socket has been disconnected bool hasDisconnected; + // if the socket is ready to attempt a reconnect + bool readyAttemptReconnect; // if this is true, it is a server socket which is meant to be turned on first, so that a client can connect to it bool awokenFirst; static void listDetectedDevices(); From d07e0ce78bac7f7c5bc8d139dbbda86248449857 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 13:47:30 +0800 Subject: [PATCH 19/35] splitted large functions into smaller ones --- lib/bluetooth-socket/bluetooth-socket.cpp | 111 +++++++++++++++------- lib/bluetooth-socket/bluetooth-socket.hpp | 13 +++ 2 files changed, 88 insertions(+), 36 deletions(-) diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index 4e8ce13..6fe0627 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -15,36 +15,76 @@ BluetoothSocket BluetoothSocket::CreateBluetoothSocket(std::string dest, bool aw return BluetoothSocket(dest, awokenFirst); } +BluetoothSocket BluetoothSocket::CreateServerSocket() { + return BluetoothSocket(); +} + // equivalent to *BDADDR_ANY, but won't make compiler warnings #define DEREF_BDADDR_ANY (bdaddr_t) {{0, 0, 0, 0, 0, 0}} +void BluetoothSocket::constructServerSocket() { + this->mySocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + struct sockaddr_rc localAddr = { 0 }; + localAddr.rc_family = AF_BLUETOOTH; + localAddr.rc_bdaddr = DEREF_BDADDR_ANY; + localAddr.rc_channel = (uint8_t) BLUETOOTH_PORT; + bind(this->mySocket, (struct sockaddr *)&localAddr, sizeof(localAddr)); + listen(this->mySocket, BLUETOOTH_PORT); +} + +void BluetoothSocket::constructClientSocket(std::string dest) { + this->mySocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + strcpy(this->otherSocketMAC, dest.c_str()); +} + +bool BluetoothSocket::attemptClientConnection(std::string dest) { + std::string destination = dest; + if (dest == "") { + destination = std::string(this->otherSocketMAC); + } + else { + strcpy(this->otherSocketMAC, destination.c_str()); + } + struct sockaddr_rc addr = { 0 }; + addr.rc_family = AF_BLUETOOTH; + addr.rc_channel = (uint8_t) BLUETOOTH_PORT; + str2ba(this->otherSocketMAC, &addr.rc_bdaddr); + int status = connect(this->mySocket, (struct sockaddr*)&addr, sizeof(addr)); + if (status >= 0) { + std::cout << "Bluetooth socket connection succeeded\n"; + this->otherSocket = this->mySocket; + this->hasDisconnected = false; + return true; + } + else { + close(this->mySocket); + this->mySocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + return false; + } +} + +bool BluetoothSocket::pollServerConnectionReady() { + struct pollfd *pfd = (pollfd*)calloc(1, sizeof(*pfd)); + pfd[0].fd = this->mySocket; + pfd[0].events = POLLIN; + bool ret = (poll(pfd, 1, 5) != 0); + free(pfd); + return ret; +} + BluetoothSocket::BluetoothSocket(std::string dest, bool awokenFirst) { this->awokenFirst = awokenFirst; this->hasDisconnected = false; if (awokenFirst) { // initialise into a server like thing - struct sockaddr_rc localAddr = { 0 }; - struct sockaddr_rc remoteAddr = { 0 }; - socklen_t opt = sizeof(remoteAddr); - this->mySocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - localAddr.rc_family = AF_BLUETOOTH; - localAddr.rc_bdaddr = DEREF_BDADDR_ANY; - localAddr.rc_channel = (uint8_t) BLUETOOTH_PORT; - bind(this->mySocket, (struct sockaddr *)&localAddr, sizeof(localAddr)); - listen(this->mySocket, BLUETOOTH_PORT); + this->constructServerSocket(); std::cout << "waiting for other side to attempt connection\n"; // loop until a connection is ready - struct pollfd *pfd = (pollfd*)calloc(1, sizeof(*pfd)); - pfd[0].fd = this->mySocket; - pfd[0].events = POLLIN; - int res = poll(pfd, 1, 5); - std::cout << res << '\n'; - while (res == 0) { - res = poll(pfd, 1, 5); + while (!this->pollServerConnectionReady()) { std::cout << "No connection attempt has been made yet...\n"; } - free(pfd); - + struct sockaddr_rc remoteAddr = { 0 }; + socklen_t opt = sizeof(remoteAddr); this->otherSocket = accept(this->mySocket, (struct sockaddr *)&remoteAddr, &opt); ba2str(&remoteAddr.rc_bdaddr, this->otherSocketMAC); std::cout << this->otherSocketMAC << " successfully connected\n"; @@ -54,28 +94,12 @@ BluetoothSocket::BluetoothSocket(std::string dest, bool awokenFirst) { std::string msg = "destionation bluetooth MAC address was not given!\n"; throw std::system_error(std::make_error_code(std::errc::no_such_device_or_address), msg); } - - char destination[18]; - strcpy(destination, dest.c_str()); - this->mySocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + this->constructClientSocket(dest); while (true) { - struct sockaddr_rc addr = { 0 }; - addr.rc_family = AF_BLUETOOTH; - addr.rc_channel = (uint8_t) BLUETOOTH_PORT; - str2ba(destination, &addr.rc_bdaddr); - int success = connect(this->mySocket, (struct sockaddr*)&addr, sizeof(addr)); - if (success >= 0) { - std::cout << "Bluetooth socket connection succeeded\n"; + if (this->attemptClientConnection(dest)) { break; } - else { - std::cout << "Bluetooth socket server refused connection. Retrying...\n"; - close(this->mySocket); - this->mySocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - } } - this->otherSocket = this->mySocket; - strcpy(this->otherSocketMAC, destination); } } @@ -246,4 +270,19 @@ void BluetoothSocket::fireDisconnect() { this->mySocket = 0; this->otherSocket = 0; this->hasDisconnected = true; + this->readyAttemptReconnect = false; +} + +void BluetoothSocket::attemptReconnect() { + if (this->hasDisconnected == false) { + std::string msg = "Bluetooth socket was told to reconnect even though it is already connected\n"; + throw std::system_error(std::make_error_code(std::errc::invalid_argument), msg); + } + if (this->readyAttemptReconnect) { + + } + else { + this->readyAttemptReconnect = true; + + } } \ No newline at end of file diff --git a/lib/bluetooth-socket/bluetooth-socket.hpp b/lib/bluetooth-socket/bluetooth-socket.hpp index 0747e53..88822c0 100644 --- a/lib/bluetooth-socket/bluetooth-socket.hpp +++ b/lib/bluetooth-socket/bluetooth-socket.hpp @@ -35,6 +35,11 @@ class BluetoothSocket { bool hasDisconnected; // if the socket is ready to attempt a reconnect bool readyAttemptReconnect; + // attempt to reconnect + // if hasDisconnected = false, this function will throw an error. + // if readyAttemptReconnect = true, this function will not attempt to reset this->mysocket, + // only trying to check if it can connect + void attemptReconnect(); // if this is true, it is a server socket which is meant to be turned on first, so that a client can connect to it bool awokenFirst; static void listDetectedDevices(); @@ -42,6 +47,8 @@ class BluetoothSocket { static BluetoothSocket CreateBluetoothSocket(std::string dest = "", bool awokenFirst = true); // create a awokenFirst = false bluetooth socket. Searches for a list of hostnames and then connects to the one required static BluetoothSocket CreateBluetoothSocketByHostname(std::string hostname); + // create a awokenFirst = true bluetooth socket. Blocks until another robot connects to the socket + static BluetoothSocket CreateServerSocket(); ~BluetoothSocket(); // reconnect with the same address provided. will throw an error if hasDisconnect = false // if the socket is a client socket, attempts to connect to the server @@ -50,6 +57,12 @@ class BluetoothSocket { BluetoothSocket(std::string dest = "", bool awokenFirst = true); // deactivate mySocket and otherSocket void fireDisconnect(); + + void constructServerSocket(); + void constructClientSocket(std::string dest); + bool pollServerConnectionReady(); + + bool attemptClientConnection(std::string dest = ""); }; } // namespace Ev3Wrap From 87e39652b15e2691ea0dba686988085b8e49e9ad Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 18:54:31 +0800 Subject: [PATCH 20/35] finalise --- lib/bluetooth-socket/bluetooth-socket.cpp | 25 +++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index 6fe0627..89ac3bd 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -279,10 +279,31 @@ void BluetoothSocket::attemptReconnect() { throw std::system_error(std::make_error_code(std::errc::invalid_argument), msg); } if (this->readyAttemptReconnect) { - + if (this->awokenFirst) { + // reactivate a server socket + if (this->pollServerConnectionReady()) { + // accept a socket + struct sockaddr_rc remoteAddr = { 0 }; + socklen_t opt = sizeof(remoteAddr); + this->otherSocket = accept(this->mySocket, (struct sockaddr *)&remoteAddr, &opt); + ba2str(&remoteAddr.rc_bdaddr, this->otherSocketMAC); + std::cout << this->otherSocketMAC << " reconnected\n"; + } + } + else { + // reactivate a client socket + this->attemptClientConnection(std::string(this->otherSocketMAC)); + } } else { this->readyAttemptReconnect = true; - + if (this->awokenFirst) { + // reactivate a server socket + this->constructServerSocket(); + } + else { + // reactivate a client socket + this->constructClientSocket(std::string(this->otherSocketMAC)); + } } } \ No newline at end of file From 73b86fc6ed62375ae27bddd12f979026afd3f4fc Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 20:11:21 +0800 Subject: [PATCH 21/35] documentation and some extra functions --- docStructure.yml | 2 + docs/documentation/bluetooth-socket.md | 46 +++++++++++++++++++++++ lib/bluetooth-socket/bluetooth-socket.cpp | 13 +++++-- lib/bluetooth-socket/bluetooth-socket.hpp | 6 ++- 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 docs/documentation/bluetooth-socket.md diff --git a/docStructure.yml b/docStructure.yml index d10b8ea..b8d151a 100644 --- a/docStructure.yml +++ b/docStructure.yml @@ -54,6 +54,8 @@ FileSystem: tag: "Utilities" - Vector: tag: "Vector" + - BluetoothSocket: + tag: "bluetooth-socket" - contributing: tag: "contribute" child_folder_reqs: diff --git a/docs/documentation/bluetooth-socket.md b/docs/documentation/bluetooth-socket.md new file mode 100644 index 0000000..5c02c46 --- /dev/null +++ b/docs/documentation/bluetooth-socket.md @@ -0,0 +1,46 @@ +--- +title: "BluetoothSocket" +tag: "bluetooth-socket" +--- + +# `BluetoothSocket` class + +### Description +`BluetoothSocket` is built for 1 to 1 bluetooth communication between 2 ev3 bricks. If your goal is to have multicast/broadcast related functions, either create many `BluetoothSocket`s or you're out of luck. + +A `BluetoothSocket` can either be a "server socket" or a "client socket". Server sockets wait for client sockets to connect to them when created. Client sockets are initialised with a goal bluetooth `MAC` address that they attempt to connect to. + +`BluetoothSocket`s can be reconnected if the connection is broken. However, the `BluetoothSocket` cannot reconnect to a different robot. + +## Initialization +To initialise a Server socket, use `BluetoothSocket::CreateServerSocket()` +To initialise a Client socket, use `BluetoothSocket::CreateClientSocketByHostname(std::string hostname)` +or +`BluetoothSocket::CreateClientSocketByMAC(std::string MAC)` +Using the `MAC` address is recommended since no time is wasted on device detection. you can use the static function `BluetoothSocket::listDetectedDevices()` to print detected device hostnames and their `MAC` addresses. + +> Warning: normally, inquiry scans are disabled on the ev3 bluetooth adapter. to enable them, use a putty console and run `hciconfig hci0 piscan`, or put `system("hciconfig hci0 piscan")` as your first line in your `main()` function. This allows other robots to detect and connect with your robot. This property is reset every time the robot is rebooted. + +## Sending data +to send data, use the `BluetoothSocket.send(char* msg, int size = CHAR_ARRAY_SIZE)` method. This takes in a `char*` buffer and the size of it. The library assumes that your buffer will be 32 bytes, (defined as `CHAR_ARRAY_SIZE`). You can have a custom size, but you will have to make sure the receiving end can handle that many bytes in 1 message. +Sending a large number of bytes increases the potential number of `write()` calls required. For simplicity, this library assumes that 1 `write()` call is enough for 1 message, hence the byte restriction at 32. + +> Tip: It is completely fine if your buffer is under 32 bytes. + +> Warning: do not do something like `mysocket.send(std::string("epic message").c_str())`. the string goes out of scope before the pointer is accessed, leading to dangling pointer problems and undefined behaviour. Properly define a `char*` buffer first. + + +## Reading data +to read data, use the `BluetoothSocket.readValue(char* msg, int size = CHAR_ARRAY_SIZE)` method. If you had sent over 32 bytes of data, make sure you have allocated enough memory for reading, otherwise the data will be split up and read in 2 separate occasions. + +> Warning: watch out for memory leaks! remember to `free()` your `malloc()` buffers + +## Detecting disconnections +both `send` and `readValue` methods return `bool`s. These represent whether the operation succeeded or not. If they are false, it is very likely that the socket had been disconnected. Check the `BluetoothSocket.hasDisconnected` property for if it had been disconnected. + +## Reconnecting after being disconnected +If the other end of the socket is disconnected for whatever reason, (such as a program crash; ended by stop button etc.) You can use `BluetoothSocket.attemptReconnect();` to try reconnect with the other robot. This is a **non-blocking** method. If it fails to reconnect, it will return `false`. Call this in your event loop or repeatedly in your program until the socket is reconnected. + +> Warning: if `BluetoothSocket.hasDisconnected` is `false` when you attempt to reconnect, it will throw an error (you're already connected!) + + diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index 89ac3bd..4698683 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -72,6 +72,10 @@ bool BluetoothSocket::pollServerConnectionReady() { return ret; } +BluetoothSocket BluetoothSocket::CreateClientSocketByMAC(std::string MAC) { + return BluetoothSocket(MAC, false); +} + BluetoothSocket::BluetoothSocket(std::string dest, bool awokenFirst) { this->awokenFirst = awokenFirst; this->hasDisconnected = false; @@ -170,7 +174,7 @@ bool BluetoothSocket::readValue(char* msg, int size) { } } -BluetoothSocket BluetoothSocket::CreateBluetoothSocketByHostname(std::string hostname) { +BluetoothSocket BluetoothSocket::CreateClientSocketByHostname(std::string hostname) { int deviceId = hci_get_route(NULL); if (deviceId < 0) { std::string msg = "bluetooth adapter not found\n"; @@ -273,7 +277,7 @@ void BluetoothSocket::fireDisconnect() { this->readyAttemptReconnect = false; } -void BluetoothSocket::attemptReconnect() { +bool BluetoothSocket::attemptReconnect() { if (this->hasDisconnected == false) { std::string msg = "Bluetooth socket was told to reconnect even though it is already connected\n"; throw std::system_error(std::make_error_code(std::errc::invalid_argument), msg); @@ -288,11 +292,13 @@ void BluetoothSocket::attemptReconnect() { this->otherSocket = accept(this->mySocket, (struct sockaddr *)&remoteAddr, &opt); ba2str(&remoteAddr.rc_bdaddr, this->otherSocketMAC); std::cout << this->otherSocketMAC << " reconnected\n"; + return true; } + return false; } else { // reactivate a client socket - this->attemptClientConnection(std::string(this->otherSocketMAC)); + return this->attemptClientConnection(std::string(this->otherSocketMAC)); } } else { @@ -305,5 +311,6 @@ void BluetoothSocket::attemptReconnect() { // reactivate a client socket this->constructClientSocket(std::string(this->otherSocketMAC)); } + return false; } } \ No newline at end of file diff --git a/lib/bluetooth-socket/bluetooth-socket.hpp b/lib/bluetooth-socket/bluetooth-socket.hpp index 88822c0..15dfe61 100644 --- a/lib/bluetooth-socket/bluetooth-socket.hpp +++ b/lib/bluetooth-socket/bluetooth-socket.hpp @@ -39,14 +39,16 @@ class BluetoothSocket { // if hasDisconnected = false, this function will throw an error. // if readyAttemptReconnect = true, this function will not attempt to reset this->mysocket, // only trying to check if it can connect - void attemptReconnect(); + bool attemptReconnect(); // if this is true, it is a server socket which is meant to be turned on first, so that a client can connect to it bool awokenFirst; static void listDetectedDevices(); // Create a bluetooth socket. dest (destination) is not required if it is a server socket (awokenFirst = true) static BluetoothSocket CreateBluetoothSocket(std::string dest = "", bool awokenFirst = true); // create a awokenFirst = false bluetooth socket. Searches for a list of hostnames and then connects to the one required - static BluetoothSocket CreateBluetoothSocketByHostname(std::string hostname); + static BluetoothSocket CreateClientSocketByHostname(std::string hostname); + // create a awokenFirst = false bluetooth socket. directly uses the given MAC address + static BluetoothSocket CreateClientSocketByMAC(std::string MAC); // create a awokenFirst = true bluetooth socket. Blocks until another robot connects to the socket static BluetoothSocket CreateServerSocket(); ~BluetoothSocket(); From 99c69fa363778f0c5057b8cfb469e7093c5ec87b Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 20:33:22 +0800 Subject: [PATCH 22/35] complete documentation --- docs/documentation/bluetooth-socket.md | 78 ++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/docs/documentation/bluetooth-socket.md b/docs/documentation/bluetooth-socket.md index 5c02c46..dd76432 100644 --- a/docs/documentation/bluetooth-socket.md +++ b/docs/documentation/bluetooth-socket.md @@ -44,3 +44,81 @@ If the other end of the socket is disconnected for whatever reason, (such as a p > Warning: if `BluetoothSocket.hasDisconnected` is `false` when you attempt to reconnect, it will throw an error (you're already connected!) +## Examples + +```cpp +// bluetooth-server.cpp +// to be run on "robot2" +#include + +using namespace Ev3Wrap; +int main() { + system("hciconfig hci0 piscan"); + BluetoothSocket serverSocket = BluetoothSocket::CreateBluetoothSocket("", true); + while (true) { + if (!serverSocket.hasDisconnected) { + char* msg = new char[CHAR_ARRAY_SIZE]; + strcpy(msg, "Hello!\n"); + //std::cout << msg << '\n'; + bool res = serverSocket.send(msg); + free(msg); + } + else { + serverSocket.attemptReconnect(); + } + } + return 0; +} +``` + +```cpp +// bluetooth-client.cpp +// to be run on "robot1" +#include + +using namespace Ev3Wrap; +int main() { + system("hciconfig hci0 piscan"); + BluetoothSocket clientSocket = BluetoothSocket::CreateClientSocketByHostname("robot2"); + while (true) { + if (!clientSocket.hasDisconnected) { + char* buffer = malloc(sizeof(char) * CHAR_ARRAY_SIZE); + bool res = clientSocket.readValue(buffer); + if (res) { + std::cout << buffer << '\n'; + } + free(buffer); + } + else { + clientSocket.attemptReconnect(); + } + } + return 0; +} +``` +The above 2 programs uses the `BluetoothSocket` to communicate with each other. They will continuously attempt to reconnect with each other if disconnected. Note that server sockets and client sockets have no difference outside of initialisation. Both can send data and read data to the other. In this example, the server socket is sending messages to the client socket. + +--- +# Advanced Usage +Most of the time, `char` is not the data type we want to send. Something like `int` would be far more helpful. Given that `int`s are 4 bytes on the EV3, we can designate the first 4 bytes of our `char*` buffer as an `int`, the next 4 bytes as the next `int`, etc. +```cpp +char* myBuffer = (char*)malloc(sizeof(char) * CHAR_ARRAY_SIZE); +int firstInt = 123; +int secondInt = 456; +memcpy(myBuffer, &firstInt, sizeof(firstInt)); +memcpy(myBuffer + sizeof(firstInt), &secondInt, sizeof(secondInt)); +myBluetoothSocket.send(myBuffer); +free(myBuffer); +``` +and on the receiving end: +```cpp +char* recvBuffer = (char*)malloc(sizeof(char) * CHAR_ARRAY_SIZE); +myBluetoothSocket.readValue(buffer); +int firstInt, secondInt; +memcpy(&firstInt, recvBuffer, sizeof(int)); +memcpy(&secondInt, recvBuffer + sizeof(firstInt), sizeof(int)); +free(recvBuffer); +// now use firstInt and secondInt for whatever you want +``` + +refer to https://stackoverflow.com/questions/1522994/store-an-int-in-a-char-array for more alternative ways to solve this problem. From aef920ecfdabfed7cff5b3895f06aaf130fcb6a8 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 20:52:33 +0800 Subject: [PATCH 23/35] fix error in example --- docs/documentation/bluetooth-socket.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/documentation/bluetooth-socket.md b/docs/documentation/bluetooth-socket.md index dd76432..9f0162d 100644 --- a/docs/documentation/bluetooth-socket.md +++ b/docs/documentation/bluetooth-socket.md @@ -54,7 +54,7 @@ If the other end of the socket is disconnected for whatever reason, (such as a p using namespace Ev3Wrap; int main() { system("hciconfig hci0 piscan"); - BluetoothSocket serverSocket = BluetoothSocket::CreateBluetoothSocket("", true); + BluetoothSocket serverSocket = BluetoothSocket::CreateServerSocket(); while (true) { if (!serverSocket.hasDisconnected) { char* msg = new char[CHAR_ARRAY_SIZE]; From 1b04f7964f5d659d6074a724f571d46098e3e5f6 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 20:53:50 +0800 Subject: [PATCH 24/35] fix example malloc() problems --- docs/documentation/bluetooth-socket.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/documentation/bluetooth-socket.md b/docs/documentation/bluetooth-socket.md index 9f0162d..b9e7fdc 100644 --- a/docs/documentation/bluetooth-socket.md +++ b/docs/documentation/bluetooth-socket.md @@ -57,7 +57,7 @@ int main() { BluetoothSocket serverSocket = BluetoothSocket::CreateServerSocket(); while (true) { if (!serverSocket.hasDisconnected) { - char* msg = new char[CHAR_ARRAY_SIZE]; + char* msg = (char*)malloc(sizeof(char) * CHAR_ARRAY_SIZE); strcpy(msg, "Hello!\n"); //std::cout << msg << '\n'; bool res = serverSocket.send(msg); @@ -82,7 +82,7 @@ int main() { BluetoothSocket clientSocket = BluetoothSocket::CreateClientSocketByHostname("robot2"); while (true) { if (!clientSocket.hasDisconnected) { - char* buffer = malloc(sizeof(char) * CHAR_ARRAY_SIZE); + char* buffer = (char*)malloc(sizeof(char) * CHAR_ARRAY_SIZE); bool res = clientSocket.readValue(buffer); if (res) { std::cout << buffer << '\n'; From 64f57ad827bbb7a0a54e712405bef940e0909259 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 21:13:08 +0800 Subject: [PATCH 25/35] added a check for if the BluetoothSocket had been disconnected in the advanced usage example --- docs/documentation/bluetooth-socket.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/documentation/bluetooth-socket.md b/docs/documentation/bluetooth-socket.md index b9e7fdc..8bb642a 100644 --- a/docs/documentation/bluetooth-socket.md +++ b/docs/documentation/bluetooth-socket.md @@ -113,12 +113,17 @@ free(myBuffer); and on the receiving end: ```cpp char* recvBuffer = (char*)malloc(sizeof(char) * CHAR_ARRAY_SIZE); -myBluetoothSocket.readValue(buffer); -int firstInt, secondInt; -memcpy(&firstInt, recvBuffer, sizeof(int)); -memcpy(&secondInt, recvBuffer + sizeof(firstInt), sizeof(int)); -free(recvBuffer); -// now use firstInt and secondInt for whatever you want +if (myBluetoothSocket.readValue(buffer)) { + int firstInt, secondInt; + memcpy(&firstInt, recvBuffer, sizeof(int)); + memcpy(&secondInt, recvBuffer + sizeof(firstInt), sizeof(int)); + free(recvBuffer); + // now use firstInt and secondInt for whatever you want +} +else { + // read value failed. check myBluetoothSocket.hasDisconnected + // ... +} ``` refer to https://stackoverflow.com/questions/1522994/store-an-int-in-a-char-array for more alternative ways to solve this problem. From 231eadad5b9b0e8293274317e06c019f1fadedb5 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 21:42:55 +0800 Subject: [PATCH 26/35] try green label --- docs/documentation/bluetooth-socket.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/documentation/bluetooth-socket.md b/docs/documentation/bluetooth-socket.md index 8bb642a..17ca2e4 100644 --- a/docs/documentation/bluetooth-socket.md +++ b/docs/documentation/bluetooth-socket.md @@ -6,6 +6,7 @@ tag: "bluetooth-socket" # `BluetoothSocket` class ### Description +{ .label .label-green } `BluetoothSocket` is built for 1 to 1 bluetooth communication between 2 ev3 bricks. If your goal is to have multicast/broadcast related functions, either create many `BluetoothSocket`s or you're out of luck. A `BluetoothSocket` can either be a "server socket" or a "client socket". Server sockets wait for client sockets to connect to them when created. Client sockets are initialised with a goal bluetooth `MAC` address that they attempt to connect to. @@ -22,7 +23,7 @@ Using the `MAC` address is recommended since no time is wasted on device detecti > Warning: normally, inquiry scans are disabled on the ev3 bluetooth adapter. to enable them, use a putty console and run `hciconfig hci0 piscan`, or put `system("hciconfig hci0 piscan")` as your first line in your `main()` function. This allows other robots to detect and connect with your robot. This property is reset every time the robot is rebooted. ## Sending data -to send data, use the `BluetoothSocket.send(char* msg, int size = CHAR_ARRAY_SIZE)` method. This takes in a `char*` buffer and the size of it. The library assumes that your buffer will be 32 bytes, (defined as `CHAR_ARRAY_SIZE`). You can have a custom size, but you will have to make sure the receiving end can handle that many bytes in 1 message. +To send data, use the `BluetoothSocket.send(char* msg, int size = CHAR_ARRAY_SIZE)` method. This takes in a `char*` buffer and the size of it. The library assumes that your buffer will be 32 bytes, (defined as `CHAR_ARRAY_SIZE`). You can have a custom size, but you will have to make sure the receiving end can handle that many bytes in 1 message. Sending a large number of bytes increases the potential number of `write()` calls required. For simplicity, this library assumes that 1 `write()` call is enough for 1 message, hence the byte restriction at 32. > Tip: It is completely fine if your buffer is under 32 bytes. @@ -31,12 +32,12 @@ Sending a large number of bytes increases the potential number of `write()` call ## Reading data -to read data, use the `BluetoothSocket.readValue(char* msg, int size = CHAR_ARRAY_SIZE)` method. If you had sent over 32 bytes of data, make sure you have allocated enough memory for reading, otherwise the data will be split up and read in 2 separate occasions. +To read data, use the `BluetoothSocket.readValue(char* msg, int size = CHAR_ARRAY_SIZE)` method. If you had sent over 32 bytes of data, make sure you have allocated enough memory for reading, otherwise the data will be split up and read in 2 separate occasions. > Warning: watch out for memory leaks! remember to `free()` your `malloc()` buffers ## Detecting disconnections -both `send` and `readValue` methods return `bool`s. These represent whether the operation succeeded or not. If they are false, it is very likely that the socket had been disconnected. Check the `BluetoothSocket.hasDisconnected` property for if it had been disconnected. +Both `send` and `readValue` methods return `bool`s. These represent whether the operation succeeded or not. If they are false, it is very likely that the socket had been disconnected. Check the `BluetoothSocket.hasDisconnected` property for if it had been disconnected. ## Reconnecting after being disconnected If the other end of the socket is disconnected for whatever reason, (such as a program crash; ended by stop button etc.) You can use `BluetoothSocket.attemptReconnect();` to try reconnect with the other robot. This is a **non-blocking** method. If it fails to reconnect, it will return `false`. Call this in your event loop or repeatedly in your program until the socket is reconnected. From bf212e27066fcf682105e493e36018b08e03eb52 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Sun, 25 Sep 2022 21:47:59 +0800 Subject: [PATCH 27/35] missed colon --- docs/documentation/bluetooth-socket.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/documentation/bluetooth-socket.md b/docs/documentation/bluetooth-socket.md index 17ca2e4..0180a83 100644 --- a/docs/documentation/bluetooth-socket.md +++ b/docs/documentation/bluetooth-socket.md @@ -6,7 +6,7 @@ tag: "bluetooth-socket" # `BluetoothSocket` class ### Description -{ .label .label-green } +{: .label .label-green } `BluetoothSocket` is built for 1 to 1 bluetooth communication between 2 ev3 bricks. If your goal is to have multicast/broadcast related functions, either create many `BluetoothSocket`s or you're out of luck. A `BluetoothSocket` can either be a "server socket" or a "client socket". Server sockets wait for client sockets to connect to them when created. Client sockets are initialised with a goal bluetooth `MAC` address that they attempt to connect to. From 4ff5abfbb9267aaa34aa2a947153e473e6538bac Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Mon, 26 Sep 2022 07:53:06 +0800 Subject: [PATCH 28/35] labels --- docs/documentation/bluetooth-socket.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/documentation/bluetooth-socket.md b/docs/documentation/bluetooth-socket.md index 0180a83..7fc7587 100644 --- a/docs/documentation/bluetooth-socket.md +++ b/docs/documentation/bluetooth-socket.md @@ -14,6 +14,7 @@ A `BluetoothSocket` can either be a "server socket" or a "client socket". Server `BluetoothSocket`s can be reconnected if the connection is broken. However, the `BluetoothSocket` cannot reconnect to a different robot. ## Initialization +{: .label .label-purple } To initialise a Server socket, use `BluetoothSocket::CreateServerSocket()` To initialise a Client socket, use `BluetoothSocket::CreateClientSocketByHostname(std::string hostname)` or @@ -23,6 +24,7 @@ Using the `MAC` address is recommended since no time is wasted on device detecti > Warning: normally, inquiry scans are disabled on the ev3 bluetooth adapter. to enable them, use a putty console and run `hciconfig hci0 piscan`, or put `system("hciconfig hci0 piscan")` as your first line in your `main()` function. This allows other robots to detect and connect with your robot. This property is reset every time the robot is rebooted. ## Sending data +{: .label .label-blue } To send data, use the `BluetoothSocket.send(char* msg, int size = CHAR_ARRAY_SIZE)` method. This takes in a `char*` buffer and the size of it. The library assumes that your buffer will be 32 bytes, (defined as `CHAR_ARRAY_SIZE`). You can have a custom size, but you will have to make sure the receiving end can handle that many bytes in 1 message. Sending a large number of bytes increases the potential number of `write()` calls required. For simplicity, this library assumes that 1 `write()` call is enough for 1 message, hence the byte restriction at 32. @@ -32,21 +34,24 @@ Sending a large number of bytes increases the potential number of `write()` call ## Reading data +{: .label .label-blue } To read data, use the `BluetoothSocket.readValue(char* msg, int size = CHAR_ARRAY_SIZE)` method. If you had sent over 32 bytes of data, make sure you have allocated enough memory for reading, otherwise the data will be split up and read in 2 separate occasions. > Warning: watch out for memory leaks! remember to `free()` your `malloc()` buffers ## Detecting disconnections +{: .label .label-blue } Both `send` and `readValue` methods return `bool`s. These represent whether the operation succeeded or not. If they are false, it is very likely that the socket had been disconnected. Check the `BluetoothSocket.hasDisconnected` property for if it had been disconnected. ## Reconnecting after being disconnected +{: .label .label-blue } If the other end of the socket is disconnected for whatever reason, (such as a program crash; ended by stop button etc.) You can use `BluetoothSocket.attemptReconnect();` to try reconnect with the other robot. This is a **non-blocking** method. If it fails to reconnect, it will return `false`. Call this in your event loop or repeatedly in your program until the socket is reconnected. > Warning: if `BluetoothSocket.hasDisconnected` is `false` when you attempt to reconnect, it will throw an error (you're already connected!) ## Examples - +{: .label .label-blue } ```cpp // bluetooth-server.cpp // to be run on "robot2" From 6a4e098cf7db9f346a6995f07934d1d165020c78 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Mon, 26 Sep 2022 08:31:34 +0800 Subject: [PATCH 29/35] removed labels --- docs/documentation/bluetooth-socket.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/documentation/bluetooth-socket.md b/docs/documentation/bluetooth-socket.md index 7fc7587..fcebfaf 100644 --- a/docs/documentation/bluetooth-socket.md +++ b/docs/documentation/bluetooth-socket.md @@ -6,7 +6,6 @@ tag: "bluetooth-socket" # `BluetoothSocket` class ### Description -{: .label .label-green } `BluetoothSocket` is built for 1 to 1 bluetooth communication between 2 ev3 bricks. If your goal is to have multicast/broadcast related functions, either create many `BluetoothSocket`s or you're out of luck. A `BluetoothSocket` can either be a "server socket" or a "client socket". Server sockets wait for client sockets to connect to them when created. Client sockets are initialised with a goal bluetooth `MAC` address that they attempt to connect to. @@ -14,7 +13,6 @@ A `BluetoothSocket` can either be a "server socket" or a "client socket". Server `BluetoothSocket`s can be reconnected if the connection is broken. However, the `BluetoothSocket` cannot reconnect to a different robot. ## Initialization -{: .label .label-purple } To initialise a Server socket, use `BluetoothSocket::CreateServerSocket()` To initialise a Client socket, use `BluetoothSocket::CreateClientSocketByHostname(std::string hostname)` or @@ -24,7 +22,6 @@ Using the `MAC` address is recommended since no time is wasted on device detecti > Warning: normally, inquiry scans are disabled on the ev3 bluetooth adapter. to enable them, use a putty console and run `hciconfig hci0 piscan`, or put `system("hciconfig hci0 piscan")` as your first line in your `main()` function. This allows other robots to detect and connect with your robot. This property is reset every time the robot is rebooted. ## Sending data -{: .label .label-blue } To send data, use the `BluetoothSocket.send(char* msg, int size = CHAR_ARRAY_SIZE)` method. This takes in a `char*` buffer and the size of it. The library assumes that your buffer will be 32 bytes, (defined as `CHAR_ARRAY_SIZE`). You can have a custom size, but you will have to make sure the receiving end can handle that many bytes in 1 message. Sending a large number of bytes increases the potential number of `write()` calls required. For simplicity, this library assumes that 1 `write()` call is enough for 1 message, hence the byte restriction at 32. @@ -34,24 +31,20 @@ Sending a large number of bytes increases the potential number of `write()` call ## Reading data -{: .label .label-blue } To read data, use the `BluetoothSocket.readValue(char* msg, int size = CHAR_ARRAY_SIZE)` method. If you had sent over 32 bytes of data, make sure you have allocated enough memory for reading, otherwise the data will be split up and read in 2 separate occasions. > Warning: watch out for memory leaks! remember to `free()` your `malloc()` buffers ## Detecting disconnections -{: .label .label-blue } Both `send` and `readValue` methods return `bool`s. These represent whether the operation succeeded or not. If they are false, it is very likely that the socket had been disconnected. Check the `BluetoothSocket.hasDisconnected` property for if it had been disconnected. ## Reconnecting after being disconnected -{: .label .label-blue } If the other end of the socket is disconnected for whatever reason, (such as a program crash; ended by stop button etc.) You can use `BluetoothSocket.attemptReconnect();` to try reconnect with the other robot. This is a **non-blocking** method. If it fails to reconnect, it will return `false`. Call this in your event loop or repeatedly in your program until the socket is reconnected. > Warning: if `BluetoothSocket.hasDisconnected` is `false` when you attempt to reconnect, it will throw an error (you're already connected!) ## Examples -{: .label .label-blue } ```cpp // bluetooth-server.cpp // to be run on "robot2" From 06fbdc0143a74381ddec0be21907f19cdc6c6f8f Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Mon, 26 Sep 2022 16:29:22 +0800 Subject: [PATCH 30/35] speed up templinks linking --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e1b223e..f3cadae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ set(CMAKE_CXX_COMPILER "arm-linux-gnueabi-g++") set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED true) -set(LIBNAME "ev3-cpp-template-wrapper-lib") +set(LIBNAME "ev3dev-cpp-template-wrapper-lib") project(${LIBNAME} VERSION 3.0.0) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -77,7 +77,6 @@ target_include_directories( SUBDIRLIST(SUBDIRS ${PROJECT_SOURCE_DIR}/lib/) foreach(subdir ${SUBDIRS}) - message(STATUS ${subdir}) target_include_directories(${LIBNAME} PUBLIC ${PROJECT_SOURCE_DIR}/lib/${subdir}) endforeach() target_include_directories(${LIBNAME} PUBLIC /home/compiler/crossCompileLibraries/libbluetooth/include/) From 21ead78fc3bfc035649138d9e834f5a5a26bd10d Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Tue, 27 Sep 2022 14:31:04 +0800 Subject: [PATCH 31/35] fix bluetoothsocket not getting reconnected properly --- lib/bluetooth-socket/bluetooth-socket.cpp | 9 +++++++++ lib/bluetooth-socket/bluetooth-socket.hpp | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index 4698683..4c505b4 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -76,6 +76,14 @@ BluetoothSocket BluetoothSocket::CreateClientSocketByMAC(std::string MAC) { return BluetoothSocket(MAC, false); } +BluetoothSocket::BluetoothSocket(bool useless) { + std::cout << "dummy socket created\n"; +} + +BluetoothSocket BluetoothSocket::CreateDummySocket() { + return BluetoothSocket(false); +} + BluetoothSocket::BluetoothSocket(std::string dest, bool awokenFirst) { this->awokenFirst = awokenFirst; this->hasDisconnected = false; @@ -292,6 +300,7 @@ bool BluetoothSocket::attemptReconnect() { this->otherSocket = accept(this->mySocket, (struct sockaddr *)&remoteAddr, &opt); ba2str(&remoteAddr.rc_bdaddr, this->otherSocketMAC); std::cout << this->otherSocketMAC << " reconnected\n"; + this->hasDisconnected = false; return true; } return false; diff --git a/lib/bluetooth-socket/bluetooth-socket.hpp b/lib/bluetooth-socket/bluetooth-socket.hpp index 15dfe61..f85ff13 100644 --- a/lib/bluetooth-socket/bluetooth-socket.hpp +++ b/lib/bluetooth-socket/bluetooth-socket.hpp @@ -51,12 +51,16 @@ class BluetoothSocket { static BluetoothSocket CreateClientSocketByMAC(std::string MAC); // create a awokenFirst = true bluetooth socket. Blocks until another robot connects to the socket static BluetoothSocket CreateServerSocket(); + // create a dummy non functional BluetoothSocket + static BluetoothSocket CreateDummySocket(); ~BluetoothSocket(); // reconnect with the same address provided. will throw an error if hasDisconnect = false // if the socket is a client socket, attempts to connect to the server private: // actual constructor BluetoothSocket(std::string dest = "", bool awokenFirst = true); + // dummy constructor + BluetoothSocket(bool useless); // deactivate mySocket and otherSocket void fireDisconnect(); From 0cfba959bdd165ff26c2fd4628e75269da53ae7d Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Tue, 27 Sep 2022 14:33:37 +0800 Subject: [PATCH 32/35] more bug fixes --- lib/bluetooth-socket/bluetooth-socket.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index 4c505b4..9c2c98a 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -54,6 +54,7 @@ bool BluetoothSocket::attemptClientConnection(std::string dest) { std::cout << "Bluetooth socket connection succeeded\n"; this->otherSocket = this->mySocket; this->hasDisconnected = false; + this->readyAttemptReconnect = false; return true; } else { @@ -283,6 +284,7 @@ void BluetoothSocket::fireDisconnect() { this->otherSocket = 0; this->hasDisconnected = true; this->readyAttemptReconnect = false; + std::cout << "Socket disconnected\n"; } bool BluetoothSocket::attemptReconnect() { @@ -301,6 +303,7 @@ bool BluetoothSocket::attemptReconnect() { ba2str(&remoteAddr.rc_bdaddr, this->otherSocketMAC); std::cout << this->otherSocketMAC << " reconnected\n"; this->hasDisconnected = false; + this->readyAttemptReconnect = false; return true; } return false; From a2bb6739e7bb1b67b917dc21f397ac637810ab68 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Fri, 30 Sep 2022 09:32:44 +0930 Subject: [PATCH 33/35] fix potentially uninitialised booleans --- lib/bluetooth-socket/bluetooth-socket.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/bluetooth-socket/bluetooth-socket.cpp b/lib/bluetooth-socket/bluetooth-socket.cpp index 9c2c98a..ebd33c1 100644 --- a/lib/bluetooth-socket/bluetooth-socket.cpp +++ b/lib/bluetooth-socket/bluetooth-socket.cpp @@ -79,6 +79,8 @@ BluetoothSocket BluetoothSocket::CreateClientSocketByMAC(std::string MAC) { BluetoothSocket::BluetoothSocket(bool useless) { std::cout << "dummy socket created\n"; + this->hasDisconnected = true; + this->readyAttemptReconnect = false; } BluetoothSocket BluetoothSocket::CreateDummySocket() { From 51c3dd79bd0cd92bd20a12a7b0b70ca26d0cfe6c Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Tue, 14 Nov 2023 14:11:33 +0800 Subject: [PATCH 34/35] final documentation before repository is archived --- README.md | 32 +++++++++++++++-------- docs/contributing/writingDocumentation.md | 2 ++ docs/index.md | 13 ++++----- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 5aec2fa..40afecb 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,27 @@ -# NEWS -## Why is the documentation all over the place? -### Reasons: -1. Jump to V3.0.0 was huge -2. A lot of unneeded features had to be removed. -3. Documentation system is currently too complicated and will be overhauled later -- Eisverygoodletter 28/08/2022 +# ARCHIVE NOTICE +Since the EV3 bricks are now being replaced by new Spike Prime bricks and the original developers (Eisverygoodletter, txxvgnx, NotOnAClient) have graduated and left the robotics club. This repository no longer has an active maintainer and will be archived. -# welcome to [ev3dev cpp template wrapper] -### this is a wrapper aimed for lego robotics on ev3dev +This repository will still remain available and all of its functionality will be intact, but no new features would be added unless a new maintainer is willing to implement features. If you are interested in using this repository or contributing to it, contact me (Eisverygoodletter) at yuetlongfeng@gmail.com + +# welcome to `ev3dev-cpp-template-wrapper`'s repository page. +This library doesn't require excessive tool installation and overly complicated cross-compiler setups. A guide can be found [here](https://rshs-robotics-club.github.io/ev3wrap/master/) +### This is a wrapper around [ddemidov/ev3dev-lang-cpp](https://github.com/ddemidov/ev3dev-lang-cpp). It includes classes for different sensors, with support for: +- Building Block Robotics IR Seeker +- Ev3 brick buttons +- Color Sensors +- Gyro Sensors +- HiTechnic Compass Sensors +- HiTechnic IR Seeker +- Ev3 large and medium motors +- An `Omni` class used for managing a specific motor setup +- Ultrasonic Sensors +- Beeping with ev3 speaker (and speaking words) +- Class for `Vector` math +- Bluetooth communication (both ev3-to-ev3 and ev3-to-computer are possible) + +While cross compiling has only been tested on Windows, a Github Codespace -aimed at providing support for a few other sensors (compass and irseeker etc) and wrapping around a highly modified version of `ev3dev.h` and `ev3dev.cpp` from ev3dev-lang-cpp repo -only works on windows Find the documentation [here](rshs-robotics-club.github.io) # we are currently on version V3.0.1 \ No newline at end of file diff --git a/docs/contributing/writingDocumentation.md b/docs/contributing/writingDocumentation.md index 1a279d2..d7b5e8b 100644 --- a/docs/contributing/writingDocumentation.md +++ b/docs/contributing/writingDocumentation.md @@ -7,6 +7,8 @@ tag: "writingDocumentation" ### The library's documentation relies on a [modified version of just-the-docs](https://github.com/rshs-robotics-club/just-the-docs) as its jekyll theme. The modification allows the documentation to have infinite nesting on the navigation bar, and a more centralised navigation structure management. +> A new just-the-docs version has implemented infinite nesting levels. This fork of just-the-docs will no longer be maintained. The documentation won't be switched over to the new version and will be archived instead along with the library repository. + ### The centralised file structure management The structure is stored in a file `docsStructure.yml`. It should look something like diff --git a/docs/index.md b/docs/index.md index 4ad03bc..113b831 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,7 +4,10 @@ title: "Introduction" nav_order: 1 tag: "introduction" --- -Note that this is not a completed product +# Better setup process +There is now a template available for github codespaces. Select `Use this template -> Open in a codespace` from this [template repository](https://github.com/rshs-robotics-club/ev3dev-cpp-wrapper-example) +> Please note that the rest of the documentation was written before Github Codespaces are released. Because of this, there is no mention of github codespaces anywhere else in the documentation. If you have a problem with the github codespaces setup, contact `yuetlongfeng@gmail.com` + # Introduction If you do not know what ev3dev is, go [here](https://www.ev3dev.org/). This library is a wrapper around [ev3dev's official cpp library](https://github.com/ddemidov/ev3dev-lang-cpp). We do not guarantee that this wrapper will work. @@ -49,10 +52,4 @@ We currently only have support for compiling on windows. (MacOS support not comi 5. you can find the output `.elf` files in the `bin` folder. Note that linux (ev3dev) does not care about file extensions, but since we're using windows we make it easier for ourselves by distinguishing executables with the `.elf` extension. 6. If you want to create more executables/projects, you can do so by creating a new `differentprojectName.cpp` file and running `./scripts/compile.sh` again. Now, you will find both `projectName.elf` and `differentprojectName.elf` in the `bin` folder. This is useful when you require quick prototyping in your project. ## Oh no! I ran into a problem -See the troubleshooting section (Not implemented yet) for solutions to common problems. If you can't find any, check [issues](https://github.com/rshs-robotics-club/ev3dev-cpp-template-wrapper/issues). If you still can't find a solution, open a new [issue](https://github.com/rshs-robotics-club/ev3dev-cpp-template-wrapper/issues) and we will try to help you. - ---- -# [Click here to find the Quick Start tutorials](quickstartTutorials.md) ---- -# [Click here for the documentation](documentation.md) ---- +See the troubleshooting section (Not implemented yet) for solutions to common problems. If you can't find any, check [issues](https://github.com/rshs-robotics-club/ev3dev-cpp-template-wrapper/issues). If you still can't find a solution, open a new [issue](https://github.com/rshs-robotics-club/ev3dev-cpp-template-wrapper/issues) and we will try to help you. \ No newline at end of file From 15ad5c12e900e354fcf6404b488b4c760b9ffb46 Mon Sep 17 00:00:00 2001 From: Eisverygoodletter Date: Tue, 14 Nov 2023 14:21:05 +0800 Subject: [PATCH 35/35] fix github actions error --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 40afecb..55c53d4 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Since the EV3 bricks are now being replaced by new Spike Prime bricks and the or This repository will still remain available and all of its functionality will be intact, but no new features would be added unless a new maintainer is willing to implement features. If you are interested in using this repository or contributing to it, contact me (Eisverygoodletter) at yuetlongfeng@gmail.com # welcome to `ev3dev-cpp-template-wrapper`'s repository page. -This library doesn't require excessive tool installation and overly complicated cross-compiler setups. A guide can be found [here](https://rshs-robotics-club.github.io/ev3wrap/master/) +This library doesn't require excessive tool installation and overly complicated cross-compiler setups. A guide can be found [here](https://rshs-robotics-club.github.io/ev3wrap/master/). Github Codespaces is available for this project at `https://github.com/rshs-robotics-club/ev3dev-cpp-wrapper-example` ### This is a wrapper around [ddemidov/ev3dev-lang-cpp](https://github.com/ddemidov/ev3dev-lang-cpp). It includes classes for different sensors, with support for: - Building Block Robotics IR Seeker - Ev3 brick buttons