Skip to content

Commit dfd9da4

Browse files
committed
Added mutex in DecodeRXMessage
Fixed event system variables
1 parent 8f9af22 commit dfd9da4

File tree

5 files changed

+248
-5
lines changed

5 files changed

+248
-5
lines changed

main/EventSystem.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1789,7 +1789,11 @@ bool CEventSystem::parseBlocklyActions(const std::string &Actions, const std::st
17891789
}
17901790
size_t eQPos = csubstr.find_first_of("=") + 1;
17911791
std::string doWhat = csubstr.substr(eQPos);
1792-
doWhat = doWhat.substr(1, doWhat.size() - 2);
1792+
if (doWhat.find('"') == 0)
1793+
{
1794+
//Strip quotes
1795+
doWhat = doWhat.substr(1, doWhat.size() - 2);
1796+
}
17931797

17941798
size_t sPos = csubstr.find_first_of("[") + 1;
17951799
size_t ePos = csubstr.find_first_of("]");

main/mainworker.cpp

Lines changed: 220 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ m_LastSunriseSet("")
134134
{
135135
m_SecCountdown=-1;
136136
m_stoprequested=false;
137+
m_stopRxMessageThread = false;
137138
m_verboselevel=EVBL_None;
138139

139140
m_bStartHardware=false;
@@ -160,6 +161,8 @@ m_LastSunriseSet("")
160161
m_LastUpdateCheck = 0;
161162
m_bHaveUpdate = false;
162163
m_iRevision = 0;
164+
165+
m_rxMessageIdx = 1;
163166
}
164167

165168
MainWorker::~MainWorker()
@@ -884,6 +887,13 @@ bool MainWorker::Start()
884887

885888
bool MainWorker::Stop()
886889
{
890+
if (m_rxMessageThread) {
891+
// Stop RxMessage thread before hardware to avoid NULL pointer exception
892+
m_stopRxMessageThread = true;
893+
UnlockRxMessageQueue();
894+
m_rxMessageThread->join();
895+
m_rxMessageThread.reset();
896+
}
887897
if (m_thread)
888898
{
889899
m_webservers.StopServers();
@@ -945,7 +955,9 @@ bool MainWorker::StartThread()
945955
}
946956

947957
m_thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&MainWorker::Do_Work, this)));
948-
return (m_thread!=NULL);
958+
m_rxMessageThread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&MainWorker::Do_Work_On_Rx_Messages, this)));
959+
960+
return (m_thread!=NULL) && (m_rxMessageThread!=NULL);
949961
}
950962

951963
#define HEX( x ) \
@@ -1638,9 +1650,215 @@ unsigned long long MainWorker::PerformRealActionFromDomoticzClient(const unsigne
16381650
return -1;
16391651
}
16401652

1641-
void MainWorker::DecodeRXMessage(const CDomoticzHardwareBase *pHardware, const unsigned char *pRXCommand) {
1653+
void MainWorker::DecodeRXMessage(const CDomoticzHardwareBase *pHardware, const unsigned char *pRXCommand)
1654+
{
1655+
boost::lock_guard<boost::mutex> l(m_decodeRXMessageMutex);
16421656
if ((pHardware == NULL) || (pRXCommand == NULL))
16431657
return;
1658+
if ((pHardware->HwdType == HTYPE_Domoticz) && (pHardware->m_HwdID == 8765))
1659+
{
1660+
//Directly process the command
1661+
ProcessRXMessage(pHardware, pRXCommand);
1662+
}
1663+
else
1664+
{
1665+
ProcessRXMessage(pHardware, pRXCommand);
1666+
// Submit command without waiting for the command to be processed
1667+
//PushRxMessage(pHardware, pRXCommand);
1668+
}
1669+
}
1670+
1671+
void MainWorker::PushRxMessage(const CDomoticzHardwareBase *pHardware, const unsigned char *pRXCommand)
1672+
{
1673+
// Check command, submit it without waiting for it to be processed
1674+
CheckAndPushRxMessage(pHardware, pRXCommand, false);
1675+
}
1676+
1677+
void MainWorker::PushAndWaitRxMessage(const CDomoticzHardwareBase *pHardware, const unsigned char *pRXCommand)
1678+
{
1679+
// Check command, submit it and wait for it to be processed
1680+
CheckAndPushRxMessage(pHardware, pRXCommand, true);
1681+
}
1682+
1683+
void MainWorker::CheckAndPushRxMessage(const CDomoticzHardwareBase *pHardware, const unsigned char *pRXCommand, const bool wait)
1684+
{
1685+
if ((pHardware == NULL) || (pRXCommand == NULL)) {
1686+
_log.Log(LOG_ERROR, "RxQueue: cannot push message with undefined hardware (%s) or command (%s)",
1687+
(pHardware == NULL) ? "null" : "not null",
1688+
(pRXCommand == NULL) ? "null" : "not null");
1689+
return;
1690+
}
1691+
if (pHardware->m_HwdID < 1) {
1692+
_log.Log(LOG_ERROR, "RxQueue: cannot push message with invalid hardware id (id=%d, type=%d, name=%s)",
1693+
pHardware->m_HwdID,
1694+
pHardware->HwdType,
1695+
pHardware->Name.c_str());
1696+
return;
1697+
}
1698+
1699+
// Build queue item
1700+
_tRxQueueItem rxMessage;
1701+
rxMessage.rxMessageIdx = m_rxMessageIdx++;
1702+
rxMessage.hardwareId = pHardware->m_HwdID;
1703+
// defensive copy of the command
1704+
rxMessage.vrxCommand.insert(rxMessage.vrxCommand.begin(), pRXCommand, pRXCommand + pRXCommand[0] + 1);
1705+
rxMessage.crc = 0x0;
1706+
#ifdef DEBUG_RXQUEUE
1707+
// CRC
1708+
boost::crc_optimal<16, 0x1021, 0xFFFF, 0, false, false> crc_ccitt2;
1709+
crc_ccitt2 = std::for_each(pRXCommand, pRXCommand + pRXCommand[0] + 1, crc_ccitt2);
1710+
rxMessage.crc = crc_ccitt2();
1711+
#endif
1712+
1713+
if (m_stopRxMessageThread) {
1714+
// Server is stopping
1715+
return;
1716+
}
1717+
1718+
// Trigger
1719+
rxMessage.trigger = NULL; // Should be initialized to NULL if trigger is no used
1720+
if (wait) { // add trigger to wait for the message to be processed
1721+
rxMessage.trigger = new queue_element_trigger();
1722+
}
1723+
1724+
#ifdef DEBUG_RXQUEUE
1725+
_log.Log(LOG_STATUS, "RxQueue: push a rxMessage(%lu) (hrdwId=%d, hrdwType=%d, hrdwName=%s, type=%02X, subtype=%02X)",
1726+
rxMessage.rxMessageIdx,
1727+
pHardware->m_HwdID,
1728+
pHardware->HwdType,
1729+
pHardware->Name.c_str(),
1730+
pRXCommand[1],
1731+
pRXCommand[2]);
1732+
#endif
1733+
1734+
// Push item to queue
1735+
m_rxMessageQueue.push(rxMessage);
1736+
1737+
if (rxMessage.trigger != NULL) {
1738+
#ifdef DEBUG_RXQUEUE
1739+
_log.Log(LOG_STATUS, "RxQueue: wait for rxMessage(%lu) to be processed...", rxMessage.rxMessageIdx);
1740+
#endif
1741+
bool moreThanTimeout = true;
1742+
while(!rxMessage.trigger->timed_wait(boost::posix_time::milliseconds(1000))) {
1743+
#ifdef DEBUG_RXQUEUE
1744+
_log.Log(LOG_STATUS, "RxQueue: wait 1s for rxMessage(%lu) to be processed...", rxMessage.rxMessageIdx);
1745+
#endif
1746+
moreThanTimeout = true;
1747+
if (m_stopRxMessageThread) {
1748+
// Server is stopping
1749+
break;
1750+
}
1751+
}
1752+
#ifdef DEBUG_RXQUEUE
1753+
if (moreThanTimeout) {
1754+
_log.Log(LOG_STATUS, "RxQueue: rxMessage(%lu) processed", rxMessage.rxMessageIdx);
1755+
}
1756+
#endif
1757+
delete rxMessage.trigger;
1758+
}
1759+
}
1760+
1761+
void MainWorker::UnlockRxMessageQueue()
1762+
{
1763+
#ifdef DEBUG_RXQUEUE
1764+
_log.Log(LOG_STATUS, "RxQueue: unlock queue using dummy message");
1765+
#endif
1766+
// Push dummy message to unlock queue
1767+
_tRxQueueItem rxMessage;
1768+
rxMessage.rxMessageIdx = m_rxMessageIdx++;
1769+
rxMessage.hardwareId = -1;
1770+
rxMessage.trigger = NULL;
1771+
m_rxMessageQueue.push(rxMessage);
1772+
}
1773+
1774+
void MainWorker::Do_Work_On_Rx_Messages()
1775+
{
1776+
_log.Log(LOG_STATUS, "RxQueue: queue worker started...");
1777+
1778+
m_stopRxMessageThread = false;
1779+
while (true) {
1780+
if (m_stopRxMessageThread) {
1781+
// Server is stopping
1782+
break;
1783+
}
1784+
1785+
// Wait and pop next message or timeout
1786+
_tRxQueueItem rxQItem;
1787+
bool hasPopped = m_rxMessageQueue.timed_wait_and_pop<boost::posix_time::milliseconds>(rxQItem,
1788+
boost::posix_time::milliseconds(5000));// (if no message for 2 seconds, returns anyway to check m_stopRxMessageThread)
1789+
1790+
if (!hasPopped) {
1791+
// Timeout occurred : queue is empty
1792+
#ifdef DEBUG_RXQUEUE
1793+
//_log.Log(LOG_STATUS, "RxQueue: the queue has been empty for five seconds");
1794+
#endif
1795+
continue;
1796+
}
1797+
if (rxQItem.hardwareId == -1) {
1798+
// dummy message
1799+
#ifdef DEBUG_RXQUEUE
1800+
_log.Log(LOG_STATUS, "RxQueue: dummy message popped");
1801+
#endif
1802+
continue;
1803+
}
1804+
if (rxQItem.hardwareId < 1) {
1805+
_log.Log(LOG_ERROR, "RxQueue: cannot process invalid hardware id: (%d)", rxQItem.hardwareId);
1806+
// cannot process message with invalid id or null message
1807+
if (rxQItem.trigger != NULL) rxQItem.trigger->popped();
1808+
continue;
1809+
}
1810+
1811+
const CDomoticzHardwareBase *pHardware = GetHardware(rxQItem.hardwareId);
1812+
1813+
// Check pointers
1814+
if (pHardware == NULL) {
1815+
_log.Log(LOG_ERROR, "RxQueue: cannot retrieve hardware with id: %d", rxQItem.hardwareId);
1816+
if (rxQItem.trigger != NULL) rxQItem.trigger->popped();
1817+
continue;
1818+
}
1819+
if (rxQItem.vrxCommand.empty()) {
1820+
_log.Log(LOG_ERROR, "RxQueue: cannot retrieve command with id: %d", rxQItem.hardwareId);
1821+
if (rxQItem.trigger != NULL) rxQItem.trigger->popped();
1822+
continue;
1823+
}
1824+
1825+
const unsigned char *pRXCommand = &rxQItem.vrxCommand[0];
1826+
1827+
#ifdef DEBUG_RXQUEUE
1828+
// CRC
1829+
boost::uint16_t crc = rxQItem.crc;
1830+
boost::crc_optimal<16, 0x1021, 0xFFFF, 0, false, false> crc_ccitt2;
1831+
crc_ccitt2 = std::for_each(pRXCommand, pRXCommand+rxQItem.vrxCommand.size(), crc_ccitt2);
1832+
if (crc != crc_ccitt2()) {
1833+
_log.Log(LOG_ERROR, "RxQueue: cannot process invalid rxMessage(%lu) from hardware with id=%d (type %d)",
1834+
rxQItem.rxMessageIdx,
1835+
rxQItem.hardwareId,
1836+
pHardware->HwdType);
1837+
if (rxQItem.trigger != NULL) rxQItem.trigger->popped();
1838+
continue;
1839+
}
1840+
1841+
_log.Log(LOG_STATUS, "RxQueue: process a rxMessage(%lu) (hrdwId=%d, hrdwType=%d, hrdwName=%s, type=%02X, subtype=%02X)",
1842+
rxQItem.rxMessageIdx,
1843+
pHardware->m_HwdID,
1844+
pHardware->HwdType,
1845+
pHardware->Name.c_str(),
1846+
pRXCommand[1],
1847+
pRXCommand[2]);
1848+
#endif
1849+
1850+
ProcessRXMessage(pHardware, pRXCommand);
1851+
if (rxQItem.trigger != NULL)
1852+
{
1853+
rxQItem.trigger->popped();
1854+
}
1855+
}
1856+
1857+
_log.Log(LOG_STATUS, "RxQueue: queue worker stopped...");
1858+
}
1859+
1860+
void MainWorker::ProcessRXMessage(const CDomoticzHardwareBase *pHardware, const unsigned char *pRXCommand)
1861+
{
16441862
// current date/time based on current system
16451863
size_t Len = pRXCommand[0] + 1;
16461864

main/mainworker.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ class MainWorker
141141
std::map<std::string, time_t > m_componentheartbeats;
142142
boost::mutex m_heartbeatmutex;
143143

144+
boost::mutex m_decodeRXMessageMutex;
145+
144146
std::vector<int> m_devicestorestart;
145147

146148
int m_SecCountdown;
@@ -195,6 +197,25 @@ class MainWorker
195197
void decode_BateryLevel(bool bIsInPercentage, unsigned char level);
196198
unsigned char get_BateryLevel(const CDomoticzHardwareBase *pHardware, bool bIsInPercentage, unsigned char level);
197199

200+
// RxMessage queue resources
201+
volatile bool m_stopRxMessageThread;
202+
volatile unsigned long m_rxMessageIdx;
203+
boost::shared_ptr<boost::thread> m_rxMessageThread;
204+
void Do_Work_On_Rx_Messages();
205+
struct _tRxQueueItem {
206+
unsigned long rxMessageIdx;
207+
int hardwareId;
208+
std::vector<unsigned char> vrxCommand;
209+
boost::uint16_t crc;
210+
queue_element_trigger* trigger;
211+
};
212+
concurrent_queue<_tRxQueueItem> m_rxMessageQueue;
213+
void UnlockRxMessageQueue();
214+
void PushRxMessage(const CDomoticzHardwareBase *pHardware, const unsigned char *pRXCommand);
215+
void PushAndWaitRxMessage(const CDomoticzHardwareBase *pHardware, const unsigned char *pRXCommand);
216+
void CheckAndPushRxMessage(const CDomoticzHardwareBase *pHardware, const unsigned char *pRXCommand, const bool wait);
217+
void ProcessRXMessage(const CDomoticzHardwareBase *pHardware, const unsigned char *pRXCommand);
218+
198219
//(RFX) Message decoders
199220
unsigned long long decode_InterfaceMessage(const CDomoticzHardwareBase *pHardware, const int HwdID, const tRBUF *pResponse);
200221
unsigned long long decode_InterfaceControl(const CDomoticzHardwareBase *pHardware, const int HwdID, const tRBUF *pResponse);

www/eventsframe.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@
157157
return '"'+encodeURIComponent($(titleB).text())+'"';
158158
}
159159
else if ($(titleB).attr("name") == "NUM") {
160-
return '"'+$(titleB).text()+'"';
160+
return $(titleB).text();
161161
}
162162
return "unknown comparevariable "+variableType;
163163
}

www/html5.appcache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
CACHE MANIFEST
2-
# ref 1125
2+
# ref 1126
33

44
CACHE:
55
# CSS

0 commit comments

Comments
 (0)