POSIX: STM32: Handle re-enumeration when changing modes
parent
5733300de6
commit
622c5ee57a
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue