diff --git a/include/DMDUtil/DMD.h b/include/DMDUtil/DMD.h index 7f50ce5..7165023 100644 --- a/include/DMDUtil/DMD.h +++ b/include/DMDUtil/DMD.h @@ -13,7 +13,6 @@ #include #include #include -#include #if defined(__APPLE__) #include @@ -120,7 +119,6 @@ class DMDUTILAPI DMD std::thread* m_pThread; std::queue m_updates; std::mutex m_mutex; - std::condition_variable m_condVar; bool m_running; static bool m_finding; diff --git a/src/DMD.cpp b/src/DMD.cpp index 72e6c61..7378c22 100644 --- a/src/DMD.cpp +++ b/src/DMD.cpp @@ -62,22 +62,19 @@ DMD::DMD(int width, int height, bool sam, const char* name) DMD::~DMD() { if (m_pThread) { - Stop(); + m_running = false; m_pThread->join(); delete m_pThread; m_pThread = nullptr; } - { - std::lock_guard lock(m_mutex); - while (!m_updates.empty()) { - DMDUpdate* const pUpdate = m_updates.front(); - m_updates.pop(); - free(pUpdate->pData); - free(pUpdate->pData2); - delete pUpdate; - } + while (!m_updates.empty()) { + DMDUpdate* const pUpdate = m_updates.front(); + m_updates.pop(); + free(pUpdate->pData); + free(pUpdate->pData2); + delete pUpdate; } free(m_pData); @@ -109,7 +106,6 @@ bool DMD::HasDisplay() const void DMD::UpdateData(const uint8_t* pData, int depth, uint8_t r, uint8_t g, uint8_t b) { - std::lock_guard lock(m_mutex); DMDUpdate* const pUpdate = new DMDUpdate(); memset(pUpdate, 0, sizeof(DMDUpdate)); pUpdate->mode = DmdMode::Data; @@ -122,13 +118,14 @@ void DMD::UpdateData(const uint8_t* pData, int depth, uint8_t r, uint8_t g, uint pUpdate->g = g; pUpdate->b = b; - m_updates.push(pUpdate); - m_condVar.notify_one(); + { + std::lock_guard lock(m_mutex); + m_updates.push(pUpdate); + } } void DMD::UpdateRGB24Data(const uint8_t* pData, int depth, uint8_t r, uint8_t g, uint8_t b) { - std::lock_guard lock(m_mutex); DMDUpdate* const pUpdate = new DMDUpdate(); memset(pUpdate, 0, sizeof(DMDUpdate)); pUpdate->mode = DmdMode::RGB24; @@ -141,13 +138,14 @@ void DMD::UpdateRGB24Data(const uint8_t* pData, int depth, uint8_t r, uint8_t g, pUpdate->g = g; pUpdate->b = b; - m_updates.push(pUpdate); - m_condVar.notify_one(); + { + std::lock_guard lock(m_mutex); + m_updates.push(pUpdate); + } } void DMD::UpdateAlphaNumericData(AlphaNumericLayout layout, const uint16_t* pData1, const uint16_t* pData2, uint8_t r, uint8_t g, uint8_t b) { - std::lock_guard lock(m_mutex); DMDUpdate* const pUpdate = new DMDUpdate(); memset(pUpdate, 0, sizeof(DMDUpdate)); pUpdate->mode = DmdMode::AlphaNumeric; @@ -163,8 +161,10 @@ void DMD::UpdateAlphaNumericData(AlphaNumericLayout layout, const uint16_t* pDat pUpdate->g = g; pUpdate->b = b; - m_updates.push(pUpdate); - m_condVar.notify_one(); + { + std::lock_guard lock(m_mutex); + m_updates.push(pUpdate); + } } void DMD::FindDevices() @@ -223,7 +223,6 @@ void DMD::FindDevices() void DMD::Run() { - std::lock_guard lock(m_mutex); if (m_running) return; @@ -235,13 +234,17 @@ void DMD::Run() DmdMode mode = DmdMode::Unknown; while (m_running) { - std::unique_lock lock(m_mutex); - m_condVar.wait(lock, [this]{ return !m_updates.empty() || !m_running; }); - - while (!m_updates.empty()) { - DMDUpdate* const pUpdate = m_updates.front(); - m_updates.pop(); + DMDUpdate* pUpdate = nullptr; + + { + std::lock_guard lock(m_mutex); + if (!m_updates.empty()) { + pUpdate = m_updates.front(); + m_updates.pop(); + } + } + if (pUpdate) { const bool update = (mode != pUpdate->mode); mode = pUpdate->mode; @@ -256,19 +259,14 @@ void DMD::Run() free(pUpdate->pData2); delete pUpdate; } + else + std::this_thread::sleep_for(std::chrono::milliseconds(1)); } Log("DMD run thread finished"); }); } -void DMD::Stop() -{ - std::lock_guard lock(m_mutex); - m_running = false; - m_condVar.notify_all(); -} - bool DMD::UpdatePalette(const DMDUpdate* pUpdate) { if (pUpdate->depth != 2 && pUpdate->depth != 4) diff --git a/src/Pixelcade.cpp b/src/Pixelcade.cpp index 18e5b4c..25767b7 100644 --- a/src/Pixelcade.cpp +++ b/src/Pixelcade.cpp @@ -20,8 +20,6 @@ Pixelcade::Pixelcade(struct sp_port* pSerialPort, int width, int height) m_width = width; m_height = height; m_length = width * height; - for (int i = 0; i < PIXELCADE_MAX_QUEUE_FRAMES; ++i) - m_framePool.push((uint16_t*)malloc(m_length * sizeof(uint16_t))); m_pThread = nullptr; m_running = false; @@ -31,31 +29,17 @@ Pixelcade::Pixelcade(struct sp_port* pSerialPort, int width, int height) Pixelcade::~Pixelcade() { if (m_pThread) { - Stop(); + m_running = false; m_pThread->join(); delete m_pThread; m_pThread = nullptr; } - { - std::lock_guard lock(m_mutex); - while (!m_frames.empty()) { - uint16_t* pFrame = m_frames.front(); - m_frames.pop(); - free(pFrame); - } - - while (!m_framePool.empty()) { - uint16_t* pFrame = m_framePool.front(); - m_framePool.pop(); - free(pFrame); - } + while (!m_frames.empty()) { + free(m_frames.front()); + m_frames.pop(); } - - sp_set_dtr(m_pSerialPort, SP_DTR_OFF); - sp_close(m_pSerialPort); - sp_free_port(m_pSerialPort); } Pixelcade* Pixelcade::Connect(const char* pDevice, int width, int height) @@ -104,6 +88,12 @@ Pixelcade* Pixelcade::Open(const char* pDevice, int width, int height) return nullptr; } + sp_set_baudrate(pSerialPort, 115200); + sp_set_bits(pSerialPort, 8); + sp_set_parity(pSerialPort, SP_PARITY_NONE); + sp_set_stopbits(pSerialPort, 1); + sp_set_xon_xoff(pSerialPort, SP_XONXOFF_DISABLED); + sp_set_dtr(pSerialPort, SP_DTR_OFF); sp_set_rts(pSerialPort, SP_RTS_ON); @@ -146,20 +136,13 @@ Pixelcade* Pixelcade::Open(const char* pDevice, int width, int height) void Pixelcade::Update(uint16_t* pData) { - std::lock_guard lock(m_mutex); - uint16_t* pFrame; - - if (!m_framePool.empty()) { - pFrame = m_framePool.front(); - m_framePool.pop(); - } - else - pFrame = (uint16_t*)malloc(m_length * sizeof(uint16_t)); - + uint16_t* pFrame = (uint16_t*)malloc(m_length * sizeof(uint16_t)); memcpy(pFrame, pData, m_length * sizeof(uint16_t)); - m_frames.push(pFrame); - m_condVar.notify_one(); + { + std::lock_guard lock(m_mutex); + m_frames.push(pFrame); + } } void Pixelcade::EnableRgbLedMatrix(int shifterLen32, int rows) @@ -170,7 +153,6 @@ void Pixelcade::EnableRgbLedMatrix(int shifterLen32, int rows) void Pixelcade::Run() { - std::lock_guard lock(m_mutex); if (m_running) return; @@ -180,57 +162,78 @@ void Pixelcade::Run() Log("Pixelcade run thread starting"); EnableRgbLedMatrix(4, 16); + int errors = 0; + while (m_running) { - std::unique_lock lock(m_mutex); - m_condVar.wait(lock, [this]{ return !m_frames.empty() || !m_running; }); + uint16_t* pFrame = nullptr; - if (m_frames.size() > PIXELCADE_MAX_QUEUE_FRAMES) { - while (!m_frames.empty()) { - uint16_t* pFrame = m_frames.front(); + { + std::lock_guard lock(m_mutex); + if (!m_frames.empty()) { + pFrame = m_frames.front(); m_frames.pop(); - m_framePool.push(pFrame); } - } - else { - while (!m_frames.empty()) { - uint16_t* pFrame = m_frames.front(); - m_frames.pop(); - static uint8_t command = PIXELCADE_COMMAND_RGB_LED_MATRIX_FRAME; - sp_blocking_write(m_pSerialPort, &command, 1, PIXELCADE_COMMAND_WRITE_TIMEOUT); + while (m_frames.size() > PIXELCADE_MAX_QUEUE_FRAMES) { + free(m_frames.front()); + m_frames.pop(); + } + } - uint8_t planes[128 * 32 * 3 / 2]; - if (m_width == 128 && m_height == 32) - FrameUtil::SplitIntoRgbPlanes(pFrame, 128 * 32, 128, 16, (uint8_t*)planes); - else { - uint16_t scaledFrame[128 * 32]; - FrameUtil::ResizeRgb565Bilinear(pFrame, m_width, m_height, scaledFrame, 128, 32); - FrameUtil::SplitIntoRgbPlanes(scaledFrame, 128 * 32, 128, 16, (uint8_t*)planes); - } + if (pFrame) { + uint8_t planes[128 * 32 * 3 / 2]; + if (m_width == 128 && m_height == 32) + FrameUtil::SplitIntoRgbPlanes(pFrame, 128 * 32, 128, 16, (uint8_t*)planes); + else { + uint16_t scaledFrame[128 * 32]; + FrameUtil::ResizeRgb565Bilinear(pFrame, m_width, m_height, scaledFrame, 128, 32); + FrameUtil::SplitIntoRgbPlanes(scaledFrame, 128 * 32, 128, 16, (uint8_t*)planes); + } - enum sp_return response = sp_blocking_write(m_pSerialPort, planes, 128 * 32 * 3 / 2, PIXELCADE_COMMAND_WRITE_TIMEOUT); + static uint8_t command = PIXELCADE_COMMAND_RGB_LED_MATRIX_FRAME; + sp_blocking_write(m_pSerialPort, &command, 1, PIXELCADE_COMMAND_WRITE_TIMEOUT); - m_framePool.push(pFrame); + enum sp_return response = sp_blocking_write(m_pSerialPort, planes, 128 * 32 * 3 / 2, PIXELCADE_COMMAND_WRITE_TIMEOUT); - if (response == SP_ERR_FAIL) { - char* pMessage = sp_last_error_message(); - Log("Error while transmitting to Pixelcade: %s", pMessage); - sp_free_error_message(pMessage); + if (response > 0) { + if (errors > 0) { + Log("Communication to Pixelcade restored after %d frames", errors); + errors = 0; + } + } + else if (response == 0) { + if (errors++ > PIXELCADE_MAX_NO_RESPONSE) { + Log("Error while transmitting to Pixelcade: no response for the past %d frames", PIXELCADE_MAX_NO_RESPONSE); m_running = false; } } + else if (response == SP_ERR_FAIL) { + char* pMessage = sp_last_error_message(); + Log("Error while transmitting to Pixelcade: %s", pMessage); + sp_free_error_message(pMessage); + m_running = false; + } } + else + std::this_thread::sleep_for(std::chrono::milliseconds(1)); } + sp_flush(m_pSerialPort, SP_BUF_BOTH); + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + sp_set_dtr(m_pSerialPort, SP_DTR_OFF); + sp_set_rts(m_pSerialPort, SP_RTS_OFF); + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + sp_close(m_pSerialPort); + sp_free_port(m_pSerialPort); + + m_pSerialPort = nullptr; + Log("Pixelcade run thread finished"); }); } -void Pixelcade::Stop() -{ - std::lock_guard lock(m_mutex); - m_running = false; - m_condVar.notify_all(); -} - } \ No newline at end of file diff --git a/src/Pixelcade.h b/src/Pixelcade.h index 320f024..20df139 100644 --- a/src/Pixelcade.h +++ b/src/Pixelcade.h @@ -12,14 +12,14 @@ #include #include #include -#include #define PIXELCADE_RESPONSE_ESTABLE_CONNECTION 0x00 #define PIXELCADE_COMMAND_RGB_LED_MATRIX_FRAME 0x1F #define PIXELCADE_COMMAND_RGB_LED_MATRIX_ENABLE 0x1E #define PIXELCADE_COMMAND_READ_TIMEOUT 100 -#define PIXELCADE_COMMAND_WRITE_TIMEOUT 50 +#define PIXELCADE_COMMAND_WRITE_TIMEOUT 100 #define PIXELCADE_MAX_QUEUE_FRAMES 4 +#define PIXELCADE_MAX_NO_RESPONSE 20 namespace DMDUtil { @@ -35,7 +35,6 @@ class Pixelcade private: static Pixelcade* Open(const char* pDevice, int width, int height); void Run(); - void Stop(); void EnableRgbLedMatrix(int shifterLen32, int rows); struct sp_port* m_pSerialPort; @@ -45,9 +44,7 @@ class Pixelcade std::thread* m_pThread; std::queue m_frames; - std::queue m_framePool; std::mutex m_mutex; - std::condition_variable m_condVar; bool m_running; };