POSIX: STM32: Handle re-enumeration when changing modes
parent
5733300de6
commit
622c5ee57a
|
|
@ -40,6 +40,8 @@ public:
|
||||||
bool isDisconnected();
|
bool isDisconnected();
|
||||||
virtual void spawnThreads();
|
virtual void spawnThreads();
|
||||||
virtual void joinThreads();
|
virtual void joinThreads();
|
||||||
|
void modeChangeIncoming() { driver->modeChangeIncoming(); }
|
||||||
|
void awaitModeChangeComplete() { driver->awaitModeChangeComplete(); }
|
||||||
bool rawWrite(const std::vector<uint8_t>& bytes) { return driver->write(bytes); }
|
bool rawWrite(const std::vector<uint8_t>& bytes) { return driver->write(bytes); }
|
||||||
virtual bool sendPacket(std::vector<uint8_t>& bytes);
|
virtual bool sendPacket(std::vector<uint8_t>& bytes);
|
||||||
bool redirectRead(std::function<void(std::vector<uint8_t>&&)> redirectTo);
|
bool redirectRead(std::function<void(std::vector<uint8_t>&&)> redirectTo);
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ public:
|
||||||
virtual ~Driver() {}
|
virtual ~Driver() {}
|
||||||
virtual bool open() = 0;
|
virtual bool open() = 0;
|
||||||
virtual bool isOpen() = 0;
|
virtual bool isOpen() = 0;
|
||||||
|
virtual void modeChangeIncoming() {}
|
||||||
|
virtual void awaitModeChangeComplete() {}
|
||||||
virtual bool isDisconnected() { return disconnected; };
|
virtual bool isDisconnected() { return disconnected; };
|
||||||
virtual bool close() = 0;
|
virtual bool close() = 0;
|
||||||
virtual bool read(std::vector<uint8_t>& bytes, size_t limit = 0);
|
virtual bool read(std::vector<uint8_t>& bytes, size_t limit = 0);
|
||||||
|
|
|
||||||
|
|
@ -24,21 +24,28 @@ public:
|
||||||
* Other POSIX systems (BSDs, QNX, etc) will need bespoke code written in the future
|
* Other POSIX systems (BSDs, QNX, etc) will need bespoke code written in the future
|
||||||
*/
|
*/
|
||||||
STM32(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err), device(forDevice) {}
|
STM32(const device_eventhandler_t& err, neodevice_t& forDevice) : Driver(err), device(forDevice) {}
|
||||||
~STM32() { if(isOpen()) close(); }
|
~STM32();
|
||||||
static std::vector<neodevice_t> FindByProduct(int product);
|
static std::vector<neodevice_t> FindByProduct(int product);
|
||||||
|
|
||||||
bool open();
|
bool open() override;
|
||||||
bool isOpen();
|
bool isOpen() override;
|
||||||
bool close();
|
bool close() override;
|
||||||
|
|
||||||
|
void modeChangeIncoming() override;
|
||||||
|
void awaitModeChangeComplete() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
neodevice_t& device;
|
neodevice_t& device;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
|
std::atomic<bool> modeChanging{false};
|
||||||
|
std::thread modeChangeThread;
|
||||||
|
std::mutex modeChangeMutex;
|
||||||
|
std::condition_variable modeChangeCV;
|
||||||
|
|
||||||
static std::string HandleToTTY(neodevice_handle_t handle);
|
static std::string HandleToTTY(neodevice_handle_t handle);
|
||||||
|
|
||||||
void readTask();
|
void readTask() override;
|
||||||
void writeTask();
|
void writeTask() override;
|
||||||
bool fdIsValid();
|
bool fdIsValid();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,12 @@
|
||||||
|
|
||||||
using namespace icsneo;
|
using namespace icsneo;
|
||||||
|
|
||||||
|
STM32::~STM32() {
|
||||||
|
awaitModeChangeComplete();
|
||||||
|
if(isOpen())
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
bool STM32::open() {
|
bool STM32::open() {
|
||||||
if(isOpen()) {
|
if(isOpen()) {
|
||||||
report(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::Error);
|
report(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::Error);
|
||||||
|
|
@ -112,6 +118,12 @@ bool STM32::close() {
|
||||||
while (readQueue.try_dequeue(flush)) {}
|
while (readQueue.try_dequeue(flush)) {}
|
||||||
while (writeQueue.try_dequeue(flushop)) {}
|
while (writeQueue.try_dequeue(flushop)) {}
|
||||||
|
|
||||||
|
if(modeChanging) {
|
||||||
|
modeChanging = false;
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
|
||||||
|
return open(); // Reopen the reenumerated device
|
||||||
|
}
|
||||||
|
|
||||||
if(ret == 0) {
|
if(ret == 0) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -120,6 +132,18 @@ bool STM32::close() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void STM32::modeChangeIncoming() {
|
||||||
|
modeChanging = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void STM32::awaitModeChangeComplete() {
|
||||||
|
std::unique_lock<std::mutex> lk(modeChangeMutex);
|
||||||
|
if(modeChanging && !modeChangeThread.joinable()) // Waiting for the thread to start
|
||||||
|
modeChangeCV.wait_for(lk, std::chrono::seconds(1), [this] { return modeChangeThread.joinable(); });
|
||||||
|
if(modeChangeThread.joinable())
|
||||||
|
modeChangeThread.join();
|
||||||
|
}
|
||||||
|
|
||||||
void STM32::readTask() {
|
void STM32::readTask() {
|
||||||
constexpr size_t READ_BUFFER_SIZE = 2048;
|
constexpr size_t READ_BUFFER_SIZE = 2048;
|
||||||
uint8_t readbuf[READ_BUFFER_SIZE];
|
uint8_t readbuf[READ_BUFFER_SIZE];
|
||||||
|
|
@ -131,10 +155,27 @@ void STM32::readTask() {
|
||||||
tv.tv_usec = 50000; // 50ms
|
tv.tv_usec = 50000; // 50ms
|
||||||
::select(fd + 1, &rfds, NULL, NULL, &tv);
|
::select(fd + 1, &rfds, NULL, NULL, &tv);
|
||||||
auto bytesRead = ::read(fd, readbuf, READ_BUFFER_SIZE);
|
auto bytesRead = ::read(fd, readbuf, READ_BUFFER_SIZE);
|
||||||
if(bytesRead > 0)
|
if(bytesRead > 0) {
|
||||||
|
#if 0 // Perhaps helpful for debugging :)
|
||||||
|
std::cout << "Read data: (" << bytesRead << ')' << std::hex << std::endl;
|
||||||
|
for(int i = 0; i < bytesRead; i += 16) {
|
||||||
|
for(int j = 0; j < std::min<int>(bytesRead - i, 16); j++)
|
||||||
|
std::cout << std::setw(2) << std::setfill('0') << uint32_t(readbuf[i+j]) << ' ';
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << std::dec << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
readQueue.enqueue_bulk(readbuf, bytesRead);
|
readQueue.enqueue_bulk(readbuf, bytesRead);
|
||||||
else {
|
} else {
|
||||||
if(!fdIsValid() && !isDisconnected()) {
|
if(modeChanging) {
|
||||||
|
// We were expecting a disconnect for reenumeration
|
||||||
|
modeChangeThread = std::thread([this] {
|
||||||
|
modeChangeCV.notify_all();
|
||||||
|
close(); // Which will trigger an open() due to modeChanging
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
} else if(!closing && !fdIsValid() && !isDisconnected()) {
|
||||||
disconnected = true;
|
disconnected = true;
|
||||||
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
|
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue