POSIX: STM32: Handle re-enumeration when changing modes

pull/35/head
Paul Hollinsky 2021-04-27 21:12:59 -04:00
parent 5733300de6
commit 622c5ee57a
4 changed files with 61 additions and 9 deletions

View File

@ -40,6 +40,8 @@ public:
bool isDisconnected();
virtual void spawnThreads();
virtual void joinThreads();
void modeChangeIncoming() { driver->modeChangeIncoming(); }
void awaitModeChangeComplete() { driver->awaitModeChangeComplete(); }
bool rawWrite(const std::vector<uint8_t>& bytes) { return driver->write(bytes); }
virtual bool sendPacket(std::vector<uint8_t>& bytes);
bool redirectRead(std::function<void(std::vector<uint8_t>&&)> redirectTo);

View File

@ -20,6 +20,8 @@ public:
virtual ~Driver() {}
virtual bool open() = 0;
virtual bool isOpen() = 0;
virtual void modeChangeIncoming() {}
virtual void awaitModeChangeComplete() {}
virtual bool isDisconnected() { return disconnected; };
virtual bool close() = 0;
virtual bool read(std::vector<uint8_t>& bytes, size_t limit = 0);

View File

@ -24,21 +24,28 @@ public:
* 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() { if(isOpen()) close(); }
~STM32();
static std::vector<neodevice_t> FindByProduct(int product);
bool open();
bool isOpen();
bool close();
bool open() override;
bool isOpen() override;
bool close() override;
void modeChangeIncoming() override;
void awaitModeChangeComplete() override;
private:
neodevice_t& device;
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);
void readTask();
void writeTask();
void readTask() override;
void writeTask() override;
bool fdIsValid();
};

View File

@ -14,6 +14,12 @@
using namespace icsneo;
STM32::~STM32() {
awaitModeChangeComplete();
if(isOpen())
close();
}
bool STM32::open() {
if(isOpen()) {
report(APIEvent::Type::DeviceCurrentlyOpen, APIEvent::Severity::Error);
@ -112,6 +118,12 @@ bool STM32::close() {
while (readQueue.try_dequeue(flush)) {}
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) {
return true;
} 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() {
constexpr size_t READ_BUFFER_SIZE = 2048;
uint8_t readbuf[READ_BUFFER_SIZE];
@ -131,10 +155,27 @@ void STM32::readTask() {
tv.tv_usec = 50000; // 50ms
::select(fd + 1, &rfds, NULL, NULL, &tv);
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);
else {
if(!fdIsValid() && !isDisconnected()) {
} else {
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;
report(APIEvent::Type::DeviceDisconnected, APIEvent::Severity::Error);
}