mirror of
https://github.com/anklimov/lighthub
synced 2025-12-06 03:39:49 +03:00
input fix for mixed configs & repeat flag, comments
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
-DMULTIVENT_DISABLE
|
||||
#-DWiz5100
|
||||
-DARDUINO_OTA_MDNS_DISABLE
|
||||
-DMDNS_ENABLE
|
||||
#-DMDNS_ENABLE
|
||||
|
||||
-DHSV_DISABLE
|
||||
-DPWM_DISABLE
|
||||
|
||||
@@ -27,6 +27,12 @@ extern volatile int8_t configLocked;
|
||||
extern bool configLoaded;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Prints the data contained in a CAN frame.
|
||||
*
|
||||
* @param frame Pointer to the datagram_t structure containing the CAN frame.
|
||||
* @param len Length of the data to print.
|
||||
*/
|
||||
void printFrame(datagram_t * frame, uint8_t len ) {
|
||||
|
||||
debugSerial.print(" Data:");
|
||||
@@ -38,6 +44,12 @@ void printFrame(datagram_t * frame, uint8_t len ) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sends the uptime metric to the CAN bus.
|
||||
*
|
||||
* @param ut Uptime value to send.
|
||||
* @return true if the message was sent successfully, false otherwise.
|
||||
*/
|
||||
bool canDriver::upTime(uint32_t ut)
|
||||
{
|
||||
if (!controllerId) return false;
|
||||
@@ -57,6 +69,12 @@ bool canDriver::upTime(uint32_t ut)
|
||||
return write (id.id, &packet, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends the salt metric to the CAN bus.
|
||||
*
|
||||
* @param salt Salt value to send.
|
||||
* @return true if the message was sent successfully, false otherwise.
|
||||
*/
|
||||
bool canDriver::salt(uint32_t salt)
|
||||
{
|
||||
if (!controllerId) return false;
|
||||
@@ -77,6 +95,11 @@ bool canDriver::salt(uint32_t salt)
|
||||
return write (id.id, &packet, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Looks up the MAC address and sends it over the CAN bus.
|
||||
*
|
||||
* @return true if the MAC address was sent successfully, false otherwise.
|
||||
*/
|
||||
bool canDriver::lookupMAC()
|
||||
{
|
||||
// return 0;
|
||||
@@ -102,6 +125,14 @@ bool canDriver::lookupMAC()
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Requests a frame from the specified device on the CAN bus.
|
||||
*
|
||||
* @param devId Device ID to request the frame from.
|
||||
* @param _payloadType Type of payload to request.
|
||||
* @param seqNo Sequence number for the request.
|
||||
* @return true if the request was successful, false otherwise.
|
||||
*/
|
||||
bool canDriver::requestFrame(uint8_t devId, payloadType _payloadType, uint16_t seqNo )
|
||||
{
|
||||
canid_t id;
|
||||
@@ -127,6 +158,12 @@ packet.metric1 =0;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends the remote ID of a device identified by its MAC address.
|
||||
*
|
||||
* @param mac MAC address of the device.
|
||||
* @return true if the remote ID was sent successfully, false otherwise.
|
||||
*/
|
||||
bool canDriver::sendRemoteID(macAddress mac)
|
||||
{
|
||||
canid_t id;
|
||||
@@ -154,6 +191,11 @@ return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initializes the CAN driver and sets up the CAN bus.
|
||||
*
|
||||
* @return true if initialization was successful, false otherwise.
|
||||
*/
|
||||
bool canDriver::begin()
|
||||
{
|
||||
if (root)
|
||||
@@ -207,6 +249,11 @@ bool canDriver::begin()
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads a frame from the CAN bus.
|
||||
*
|
||||
* @return Length of the received frame, or -1 if no frame was received.
|
||||
*/
|
||||
int canDriver::readFrame()
|
||||
{
|
||||
if (!ready) return -1;
|
||||
@@ -284,6 +331,9 @@ int canDriver::readFrame()
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Polls the CAN bus for incoming frames and processes them.
|
||||
*/
|
||||
void canDriver::Poll()
|
||||
{
|
||||
|
||||
@@ -355,6 +405,15 @@ switch (state)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processes a received CAN packet.
|
||||
*
|
||||
* @param id Identifier of the CAN packet.
|
||||
* @param packet Pointer to the received datagram_t structure.
|
||||
* @param len Length of the received packet.
|
||||
* @param rtr Indicates if the packet is a remote transmission request.
|
||||
* @return true if the packet was processed successfully, false otherwise.
|
||||
*/
|
||||
bool canDriver::processPacket(canid_t id, datagram_t *packet, uint8_t len, bool rtr)
|
||||
{
|
||||
|
||||
@@ -557,6 +616,11 @@ else //Requests
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves the device ID of this CAN driver.
|
||||
*
|
||||
* @return The device ID, or 0 if not set.
|
||||
*/
|
||||
uint8_t canDriver::getMyId()
|
||||
{
|
||||
if (!canConfigObj) return 0;
|
||||
@@ -565,6 +629,12 @@ if (addrObj && (addrObj->type == aJson_Int)) return addrObj->valueint;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves the configuration object for a device by its ID.
|
||||
*
|
||||
* @param devId Device ID to look up.
|
||||
* @return Pointer to the configuration object, or NULL if not found.
|
||||
*/
|
||||
aJsonObject * canDriver::getConfbyID(uint8_t devId)
|
||||
{
|
||||
if (!canConfigObj) return NULL;
|
||||
@@ -583,6 +653,13 @@ while (remoteConfObj)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds a configuration object by device name.
|
||||
*
|
||||
* @param devName Name of the device to look for.
|
||||
* @param devAddr Pointer to store the device address if found.
|
||||
* @return Pointer to the configuration object, or NULL if not found.
|
||||
*/
|
||||
aJsonObject * canDriver::findConfbyName(char* devName, int * devAddr)
|
||||
{
|
||||
if (!canRemoteConfigObj || canRemoteConfigObj->type != aJson_Object || !devName ) return NULL;
|
||||
@@ -611,6 +688,13 @@ return NULL;
|
||||
#if not defined (NOIP)
|
||||
extern PubSubClient mqttClient;
|
||||
|
||||
/**
|
||||
* @brief Subscribes to MQTT topics based on the CAN configuration.
|
||||
*
|
||||
* @param root Pointer to the root topic string.
|
||||
* @param buflen Length of the buffer for the topic string.
|
||||
* @return true if subscription was successful, false otherwise.
|
||||
*/
|
||||
bool canDriver::subscribeTopics(char * root, size_t buflen)
|
||||
{
|
||||
if (!root) return false;
|
||||
@@ -643,6 +727,12 @@ while (remoteConfObj)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Retrieves the device ID associated with a given MAC address.
|
||||
*
|
||||
* @param mac MAC address to look up.
|
||||
* @return The device ID, or 0 if not found.
|
||||
*/
|
||||
uint8_t canDriver::getIdByMac(macAddress mac)
|
||||
{
|
||||
char macStr[19];
|
||||
@@ -675,6 +765,14 @@ if (addrObj && (addrObj->type == aJson_Int))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends a message over the CAN bus.
|
||||
*
|
||||
* @param msg_id Identifier for the message.
|
||||
* @param buf Pointer to the datagram_t structure containing the message data.
|
||||
* @param size Size of the message data.
|
||||
* @return true if the message was sent successfully, false otherwise.
|
||||
*/
|
||||
bool canDriver::write(uint32_t msg_id, datagram_t * buf, uint8_t size)
|
||||
{ //
|
||||
if (!ready) {
|
||||
@@ -724,12 +822,28 @@ bool canDriver::write(uint32_t msg_id, datagram_t * buf, uint8_t size)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sends the status of a specified item.
|
||||
*
|
||||
* @param itemNum Item number to send the status for.
|
||||
* @param cmd Command structure containing the status information.
|
||||
* @param subItem Sub-item identifier.
|
||||
* @return true if the status was sent successfully, false otherwise.
|
||||
*/
|
||||
bool canDriver::sendStatus(uint16_t itemNum, itemCmd cmd, int subItem)
|
||||
{
|
||||
if (!itemNum || !controllerId) return false;
|
||||
return sendCommand(controllerId, itemNum, cmd, true, subItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends a command to a specified CAN device.
|
||||
*
|
||||
* @param can Pointer to the configuration object for the device.
|
||||
* @param cmd Command structure containing the command information.
|
||||
* @param status Indicates if the command is a status update.
|
||||
* @return true if the command was sent successfully, false otherwise.
|
||||
*/
|
||||
bool canDriver::sendCommand(aJsonObject * can, itemCmd cmd, bool status)
|
||||
{
|
||||
if (can && (can->type == aJson_Array))
|
||||
@@ -766,6 +880,16 @@ bool canDriver::sendCommand(aJsonObject * can, itemCmd cmd, bool status)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends a command to a specified device by ID.
|
||||
*
|
||||
* @param devID Device ID to send the command to.
|
||||
* @param itemID Item ID to send the command for.
|
||||
* @param cmd Command structure containing the command information.
|
||||
* @param status Indicates if the command is a status update.
|
||||
* @param subItemID Sub-item identifier.
|
||||
* @return true if the command was sent successfully, false otherwise.
|
||||
*/
|
||||
bool canDriver::sendCommand(uint8_t devID, uint16_t itemID,itemCmd cmd, bool status,int subItemID )
|
||||
{
|
||||
canid_t id;
|
||||
@@ -801,6 +925,13 @@ bool canDriver::sendCommand(uint8_t devID, uint16_t itemID,itemCmd cmd, bool sta
|
||||
////////////////////////////// Steream //////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sends data over the CAN stream.
|
||||
*
|
||||
* @param len Length of the data to send.
|
||||
* @param _seqNo Sequence number for the data.
|
||||
* @return 1 if the data was sent successfully, 0 otherwise.
|
||||
*/
|
||||
int canStream::send(uint8_t len, uint16_t _seqNo)
|
||||
{
|
||||
canid_t id;
|
||||
@@ -823,6 +954,11 @@ bool canDriver::sendCommand(uint8_t devID, uint16_t itemID,itemCmd cmd, bool sta
|
||||
else return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks the state of the CAN stream and processes any incoming data.
|
||||
*
|
||||
* @return -1 on error, or the number of bytes available for reading.
|
||||
*/
|
||||
int canStream::checkState()
|
||||
{
|
||||
bool res = false;
|
||||
@@ -918,6 +1054,11 @@ bool canDriver::sendCommand(uint8_t devID, uint16_t itemID,itemCmd cmd, bool sta
|
||||
|
||||
|
||||
// Stream methods
|
||||
/**
|
||||
* @brief Checks how many bytes are available for reading from the CAN stream.
|
||||
*
|
||||
* @return Number of bytes available, or -1 on error.
|
||||
*/
|
||||
int canStream::available()
|
||||
{
|
||||
if (!driver) return -1;
|
||||
@@ -925,6 +1066,11 @@ bool canDriver::sendCommand(uint8_t devID, uint16_t itemID,itemCmd cmd, bool sta
|
||||
return avail;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Reads a byte from the CAN stream.
|
||||
*
|
||||
* @return The byte read, or -1 on error.
|
||||
*/
|
||||
int canStream::read()
|
||||
{
|
||||
if (!driver) return -1;
|
||||
@@ -939,6 +1085,11 @@ bool canDriver::sendCommand(uint8_t devID, uint16_t itemID,itemCmd cmd, bool sta
|
||||
else return -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Peeks at the next byte in the CAN stream without removing it.
|
||||
*
|
||||
* @return The next byte, or -1 on error.
|
||||
*/
|
||||
int canStream::peek()
|
||||
{
|
||||
if (!driver) return -1;
|
||||
@@ -954,6 +1105,12 @@ bool canDriver::sendCommand(uint8_t devID, uint16_t itemID,itemCmd cmd, bool sta
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Writes a byte to the CAN stream.
|
||||
*
|
||||
* @param c The byte to write.
|
||||
* @return The number of bytes written, or -1 on error.
|
||||
*/
|
||||
size_t canStream::write(uint8_t c)
|
||||
{
|
||||
//if ((state != canState::StreamOpenedWrite) || (state != canState::waitingConfirm)) return -1;
|
||||
@@ -984,12 +1141,20 @@ bool canDriver::sendCommand(uint8_t devID, uint16_t itemID,itemCmd cmd, bool sta
|
||||
}
|
||||
return 1; };
|
||||
|
||||
/**
|
||||
* @brief Flushes the CAN stream, sending any buffered data.
|
||||
*/
|
||||
void canStream::flush()
|
||||
{
|
||||
send(writePos,seqNo);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks if the CAN stream is available for writing.
|
||||
*
|
||||
* @return 1 if available, 0 if waiting for confirmation.
|
||||
*/
|
||||
int canStream::availableForWrite()
|
||||
{
|
||||
switch (state)
|
||||
|
||||
@@ -681,9 +681,9 @@ debugSerial << F("IN:") << pin << F(" DHT22 type. T=") << temp << F("°C H=") <<
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO Polling via timed interrupt with CHECK_INTERRUPT cause
|
||||
|
||||
bool Input::
|
||||
changeState(uint8_t newState, short cause, aJsonObject * currentInputObject, bool contactState)
|
||||
changeState(uint8_t newState, short cause, aJsonObject * currentInputObject, bool contactState, bool calledOnTimer)
|
||||
{
|
||||
if (!inputObj || !store) return false;
|
||||
|
||||
@@ -782,22 +782,30 @@ if (newState!=store->state && cause!=CHECK_INTERRUPT) debugSerial<<F("#")<<pin<<
|
||||
cmd = aJson.getObjectItem(currentInputObject, "rpcmd3");
|
||||
toggle=store->toggle3;
|
||||
break;
|
||||
|
||||
case IS_NOP:
|
||||
if (!calledOnTimer) break;
|
||||
if (contactState)
|
||||
cmd = aJson.getObjectItem(currentInputObject, "scmd");
|
||||
else cmd = aJson.getObjectItem(currentInputObject, "rcmd");
|
||||
break;
|
||||
}
|
||||
|
||||
if (cause != CHECK_INTERRUPT)
|
||||
if (!calledOnTimer || newState == IS_NOP)
|
||||
{
|
||||
onContactChanged(contactState);
|
||||
store->delayedState=false;
|
||||
}
|
||||
else
|
||||
{
|
||||
store->delayedState=true;
|
||||
store->lastValue = contactState;
|
||||
store->reqState=newState;
|
||||
if (cause != CHECK_INTERRUPT)
|
||||
{
|
||||
onContactChanged(contactState);
|
||||
store->delayedState=false;
|
||||
}
|
||||
else
|
||||
{
|
||||
store->delayedState=true;
|
||||
store->lastValue = contactState;
|
||||
store->reqState=newState;
|
||||
}
|
||||
}
|
||||
|
||||
if (newState == IS_NOP) return true;
|
||||
if ((newState == IS_NOP) && !calledOnTimer) return true;
|
||||
|
||||
aJsonObject *defaultItem = aJson.getObjectItem(currentInputObject, "item");
|
||||
aJsonObject *defaultEmit = aJson.getObjectItem(currentInputObject, "emit");
|
||||
@@ -807,7 +815,7 @@ if (newState!=store->state && cause!=CHECK_INTERRUPT) debugSerial<<F("#")<<pin<<
|
||||
|
||||
if (!cmd && !defCmd.isCommand())
|
||||
{
|
||||
store->state=newState;
|
||||
if (newState !=IS_NOP) store->state=newState;
|
||||
store->delayedState=false;
|
||||
return true; //nothing to do
|
||||
}
|
||||
@@ -815,7 +823,7 @@ if (newState!=store->state && cause!=CHECK_INTERRUPT) debugSerial<<F("#")<<pin<<
|
||||
|
||||
if (cause != CHECK_INTERRUPT)
|
||||
{
|
||||
store->state=newState;
|
||||
if (newState !=IS_NOP) store->state=newState;
|
||||
store->delayedState=false;
|
||||
checkInstructions(cmd);
|
||||
executeCommand(cmd,toggle,defCmd,defaultItem,defaultEmit,defaultCan);
|
||||
@@ -824,7 +832,7 @@ if (newState!=store->state && cause!=CHECK_INTERRUPT) debugSerial<<F("#")<<pin<<
|
||||
else
|
||||
{
|
||||
//Postpone actual execution
|
||||
if (newState != store->state)
|
||||
if ((newState != store->state) && (newState !=IS_NOP))
|
||||
{
|
||||
store->reqState=newState;
|
||||
store->delayedState=true;
|
||||
@@ -880,15 +888,15 @@ switch (store->state) //Timer based transitions
|
||||
case IS_PRESSED:
|
||||
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_LONG,0xFFFF))
|
||||
{
|
||||
if (!aJson.getObjectItem(inputObj, "lcmd") && !aJson.getObjectItem(currentInputObject, "rpcmd")) changeState(IS_WAITRELEASE, cause,currentInputObject,currentInputState);
|
||||
else changeState(IS_LONG, cause,currentInputObject,currentInputState);
|
||||
if (!aJson.getObjectItem(inputObj, "lcmd") && !aJson.getObjectItem(currentInputObject, "rpcmd")) changeState(IS_WAITRELEASE, cause,currentInputObject,currentInputState,true);
|
||||
else changeState(IS_LONG, cause,currentInputObject,currentInputState,true);
|
||||
}
|
||||
break;
|
||||
|
||||
case IS_LONG:
|
||||
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT,0xFFFF))
|
||||
{
|
||||
changeState(IS_REPEAT, cause,currentInputObject,currentInputState);
|
||||
changeState(IS_REPEAT, cause,currentInputObject,currentInputState,true);
|
||||
store->timestamp16 = millis() & 0xFFFF;
|
||||
}
|
||||
break;
|
||||
@@ -896,7 +904,7 @@ switch (store->state) //Timer based transitions
|
||||
case IS_REPEAT:
|
||||
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT_PULSE,0xFFFF))
|
||||
{
|
||||
changeState(IS_REPEAT, cause,currentInputObject,currentInputState);
|
||||
changeState(IS_REPEAT, cause,currentInputObject,currentInputState,true);
|
||||
store->timestamp16 = millis() & 0xFFFF;
|
||||
}
|
||||
break;
|
||||
@@ -904,15 +912,15 @@ switch (store->state) //Timer based transitions
|
||||
case IS_PRESSED2:
|
||||
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_LONG,0xFFFF))
|
||||
{
|
||||
if (!aJson.getObjectItem(currentInputObject, "lcmd2") && !aJson.getObjectItem(currentInputObject, "rpcmd2")) changeState(IS_WAITRELEASE, cause,currentInputObject,currentInputState);
|
||||
else changeState(IS_LONG2, cause,currentInputObject,currentInputState);
|
||||
if (!aJson.getObjectItem(currentInputObject, "lcmd2") && !aJson.getObjectItem(currentInputObject, "rpcmd2")) changeState(IS_WAITRELEASE, cause,currentInputObject,currentInputState,true);
|
||||
else changeState(IS_LONG2, cause,currentInputObject,currentInputState,true);
|
||||
}
|
||||
break;
|
||||
|
||||
case IS_LONG2:
|
||||
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT,0xFFFF))
|
||||
{
|
||||
changeState(IS_REPEAT2, cause,currentInputObject,currentInputState);
|
||||
changeState(IS_REPEAT2, cause,currentInputObject,currentInputState,true);
|
||||
store->timestamp16 = millis() & 0xFFFF;
|
||||
}
|
||||
break;
|
||||
@@ -920,7 +928,7 @@ switch (store->state) //Timer based transitions
|
||||
case IS_REPEAT2:
|
||||
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT_PULSE,0xFFFF))
|
||||
{
|
||||
changeState(IS_REPEAT2, cause,currentInputObject,currentInputState);
|
||||
changeState(IS_REPEAT2, cause,currentInputObject,currentInputState,true);
|
||||
store->timestamp16 = millis() & 0xFFFF;
|
||||
}
|
||||
break;
|
||||
@@ -930,17 +938,17 @@ switch (store->state) //Timer based transitions
|
||||
{
|
||||
if (!aJson.getObjectItem(currentInputObject, "lcmd3") && !aJson.getObjectItem(currentInputObject, "rpcmd3")) //No longpress handlers
|
||||
{
|
||||
if (aJson.getObjectItem(currentInputObject, "scmd3")) changeState(IS_WAITRELEASE, cause,currentInputObject,currentInputState); //was used
|
||||
else changeState(IS_PRESSED2, cause,currentInputObject,currentInputState); // completely empty trippleClick section - fallback to first click handler
|
||||
if (aJson.getObjectItem(currentInputObject, "scmd3")) changeState(IS_WAITRELEASE, cause,currentInputObject,currentInputState,true); //was used
|
||||
else changeState(IS_PRESSED2, cause,currentInputObject,currentInputState,true); // completely empty trippleClick section - fallback to first click handler
|
||||
}
|
||||
else changeState(IS_LONG3, cause,currentInputObject,currentInputState);
|
||||
else changeState(IS_LONG3, cause,currentInputObject,currentInputState,true);
|
||||
}
|
||||
break;
|
||||
|
||||
case IS_LONG3:
|
||||
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT,0xFFFF))
|
||||
{
|
||||
changeState(IS_REPEAT3, cause,currentInputObject,currentInputState);
|
||||
changeState(IS_REPEAT3, cause,currentInputObject,currentInputState,true);
|
||||
store->timestamp16 = millis() & 0xFFFF;
|
||||
}
|
||||
break;
|
||||
@@ -948,7 +956,7 @@ switch (store->state) //Timer based transitions
|
||||
case IS_REPEAT3:
|
||||
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT_PULSE,0xFFFF))
|
||||
{
|
||||
changeState(IS_REPEAT3, cause,currentInputObject,currentInputState);
|
||||
changeState(IS_REPEAT3, cause,currentInputObject,currentInputState,true);
|
||||
store->timestamp16 = millis() & 0xFFFF;
|
||||
}
|
||||
break;
|
||||
@@ -958,7 +966,7 @@ switch (store->state) //Timer based transitions
|
||||
case IS_WAITPRESS:
|
||||
|
||||
|
||||
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_IDLE,0xFFFF)) changeState(IS_IDLE, cause,currentInputObject,currentInputState);
|
||||
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_IDLE,0xFFFF)) changeState(IS_IDLE, cause,currentInputObject,currentInputState,true);
|
||||
break;
|
||||
} //switch
|
||||
#ifdef ROTARYENCODER
|
||||
@@ -1028,7 +1036,7 @@ if (re)
|
||||
res = changeState(IS_PRESSED3, cause,currentInputObject,currentInputState);
|
||||
break;
|
||||
default:
|
||||
res = changeState(IS_NOP, cause,currentInputObject,currentInputState);
|
||||
res = changeState(IS_NOP, cause,currentInputObject,currentInputState,(currentInputState == store->lastValue));
|
||||
|
||||
}
|
||||
else
|
||||
@@ -1064,7 +1072,7 @@ if (re)
|
||||
res = changeState(IS_IDLE, cause,currentInputObject,currentInputState);
|
||||
break;
|
||||
default:
|
||||
res = changeState(IS_NOP, cause,currentInputObject,currentInputState);
|
||||
res = changeState(IS_NOP, cause,currentInputObject,currentInputState, (currentInputState == store->lastValue));
|
||||
}
|
||||
if (res) { //State changed or postponed
|
||||
// store->logicState = currentInputState;
|
||||
@@ -1186,13 +1194,14 @@ strncpy(addrstr,emit->valuestring,sizeof(addrstr));
|
||||
if (mqttClient.connected() && !ethernetIdleCount)
|
||||
{
|
||||
if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,emit->valuestring);
|
||||
|
||||
if (newValue) { //send set command
|
||||
if (!scmd || scmd->type != aJson_String) mqttClient.publish(addrstr, "ON", true);
|
||||
else if (strlen(scmd->valuestring))
|
||||
mqttClient.publish(addrstr, scmd->valuestring, true);
|
||||
if (!scmd) {mqttClient.publish(addrstr, "ON", true); debugSerial<<F("Emit:")<<addrstr<< F("->") << "ON"<<endl;}
|
||||
else if ((scmd->type == aJson_String) && strlen(scmd->valuestring))
|
||||
{mqttClient.publish(addrstr, scmd->valuestring, true);debugSerial<<F("Emit:")<<addrstr<< F("->") << scmd->valuestring<<endl;}
|
||||
} else { //send reset command
|
||||
if (!rcmd || rcmd->type != aJson_String) mqttClient.publish(addrstr, "OFF", true);
|
||||
else if (strlen(rcmd->valuestring))mqttClient.publish(addrstr, rcmd->valuestring, true);
|
||||
if (!rcmd) {mqttClient.publish(addrstr, "OFF", true);debugSerial<<F("Emit:")<<addrstr<< F("->") << "OFF"<<endl;}
|
||||
else if ((rcmd->type == aJson_String) && strlen(rcmd->valuestring)) {mqttClient.publish(addrstr, rcmd->valuestring, true);debugSerial<<F("Emit:")<<addrstr<< F("->") << rcmd->valuestring<<endl;}
|
||||
}
|
||||
}
|
||||
#endif //NOIP
|
||||
@@ -1203,12 +1212,12 @@ if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,emit->valuestri
|
||||
Item it(item->valuestring);
|
||||
if (it.isValid()) {
|
||||
if (newValue) { //send set command
|
||||
if (!scmd || scmd->type != aJson_String) it.Ctrl(itemCmd(ST_VOID,CMD_ON));
|
||||
else if (strlen(scmd->valuestring))
|
||||
if (!scmd ) it.Ctrl(itemCmd(ST_VOID,CMD_ON));
|
||||
else if ((scmd->type == aJson_String) && strlen(scmd->valuestring))
|
||||
it.Ctrl(scmd->valuestring);
|
||||
} else { //send reset command
|
||||
if (!rcmd || rcmd->type != aJson_String) it.Ctrl(itemCmd(ST_VOID,CMD_OFF));
|
||||
else if (strlen(rcmd->valuestring))
|
||||
if (!rcmd ) it.Ctrl(itemCmd(ST_VOID,CMD_OFF));
|
||||
else if ((rcmd->type == aJson_String) && strlen(rcmd->valuestring))
|
||||
it.Ctrl(rcmd->valuestring);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ protected:
|
||||
bool publishDataToDomoticz(int , aJsonObject *, const char *format, ...);
|
||||
|
||||
char* getIdxField();
|
||||
bool changeState(uint8_t newState, short cause, aJsonObject * currentInputObject, bool contactState);
|
||||
bool changeState(uint8_t newState, short cause, aJsonObject * currentInputObject, bool contactState, bool calledOnTimer = false);
|
||||
void setupRotaryEncoder();
|
||||
|
||||
aJsonObject * getCurrentInput();
|
||||
|
||||
@@ -60,8 +60,18 @@ const reg_t regSize_P[] PROGMEM =
|
||||
} ;
|
||||
#define regSizeNum sizeof(regSize_P)/sizeof(reg_t)
|
||||
|
||||
/**
|
||||
* @brief Меняет порядок байтов в 16-битном числе.
|
||||
* @param x Входное число.
|
||||
* @return Число с изменённым порядком байтов.
|
||||
*/
|
||||
uint16_t swap (uint16_t x) {return ((x & 0xff) << 8) | ((x & 0xff00) >> 8);}
|
||||
|
||||
/**
|
||||
* @brief Преобразует строку в тип регистра.
|
||||
* @param str Строка с типом регистра.
|
||||
* @return Код типа регистра.
|
||||
*/
|
||||
int str2regSize(char * str)
|
||||
{
|
||||
for(uint8_t i=0; i<regSizeNum && str;i++)
|
||||
@@ -71,6 +81,12 @@ int str2regSize(char * str)
|
||||
}
|
||||
|
||||
//TODO irs etc
|
||||
/**
|
||||
* @brief Получает имя параметра по номеру регистра.
|
||||
* @param parameters JSON-объект с параметрами.
|
||||
* @param regnum Номер регистра.
|
||||
* @return Имя параметра или NULL.
|
||||
*/
|
||||
char * getParamNameByReg(aJsonObject * parameters, int regnum)
|
||||
{
|
||||
if (!parameters) return NULL;
|
||||
@@ -89,6 +105,11 @@ char * getParamNameByReg(aJsonObject * parameters, int regnum)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверяет наличие действия в JSON-объекте.
|
||||
* @param execObj JSON-объект.
|
||||
* @return true, если действие найдено, иначе false.
|
||||
*/
|
||||
bool haveAction(aJsonObject * execObj)
|
||||
{
|
||||
aJsonObject * j = execObj->child;
|
||||
@@ -111,6 +132,10 @@ case aJson_Array:
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Загружает и применяет конфигурацию Modbus.
|
||||
* @return true, если конфигурация успешно загружена, иначе false.
|
||||
*/
|
||||
bool out_Modbus::getConfig()
|
||||
{
|
||||
// Retrieve and store template values from global modbus settings
|
||||
@@ -224,6 +249,11 @@ bool out_Modbus::getConfig()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Создаёт поле для хранения последнего измеренного значения по имени параметра.
|
||||
* @param name Имя параметра.
|
||||
* @return true, если успешно, иначе false.
|
||||
*/
|
||||
int out_Modbus::createLastMeasured(char * name)
|
||||
{
|
||||
if (!name) return false;
|
||||
@@ -231,6 +261,11 @@ aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2);
|
||||
return createLastMeasured(aJson.getObjectItem(itemParametersObj,name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Создаёт поле для хранения последнего измеренного значения по JSON-объекту.
|
||||
* @param execObj JSON-объект параметра.
|
||||
* @return true, если успешно, иначе false.
|
||||
*/
|
||||
int out_Modbus::createLastMeasured(aJsonObject * execObj)
|
||||
{
|
||||
if (!execObj) return false;
|
||||
@@ -255,6 +290,11 @@ int out_Modbus::createLastMeasured(aJsonObject * execObj)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получает объект последнего измеренного значения по имени параметра.
|
||||
* @param name Имя параметра.
|
||||
* @return JSON-объект или NULL.
|
||||
*/
|
||||
aJsonObject * out_Modbus::getLastMeasured(char * name)
|
||||
{
|
||||
if (!name) return NULL;
|
||||
@@ -262,6 +302,11 @@ aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2);
|
||||
return getLastMeasured (aJson.getObjectItem(itemParametersObj,name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получает объект последнего измеренного значения по JSON-объекту.
|
||||
* @param execObj JSON-объект параметра.
|
||||
* @return JSON-объект или NULL.
|
||||
*/
|
||||
aJsonObject * out_Modbus::getLastMeasured(aJsonObject * execObj)
|
||||
{
|
||||
if (!execObj) return NULL;
|
||||
@@ -271,6 +316,10 @@ if (lastMeasured && lastMeasured->type == aJson_Int) return lastMeasured;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализирует канал Modbus и загружает конфигурацию.
|
||||
* @return 1 при успехе, 0 при ошибке.
|
||||
*/
|
||||
int out_Modbus::Setup()
|
||||
{
|
||||
abstractOut::Setup();
|
||||
@@ -295,6 +344,10 @@ else
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Останавливает работу канала Modbus и освобождает ресурсы.
|
||||
* @return 1 при успехе.
|
||||
*/
|
||||
int out_Modbus::Stop()
|
||||
{
|
||||
debugSerial.print("MBUS: De-Init ");
|
||||
@@ -309,6 +362,13 @@ return 1;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Читает данные из Modbus-устройства.
|
||||
* @param reg Номер регистра.
|
||||
* @param regType Тип регистра.
|
||||
* @param count Количество регистров.
|
||||
* @return true, если чтение успешно, иначе false.
|
||||
*/
|
||||
bool readModbus(uint16_t reg, int regType, int count)
|
||||
{
|
||||
uint8_t result;
|
||||
@@ -336,6 +396,17 @@ return (result == node.ku8MBSuccess);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Находит и обрабатывает регистр Modbus, выполняет сопоставление и действия.
|
||||
* @param registerNum Номер регистра.
|
||||
* @param posInBuffer Позиция в буфере ответа.
|
||||
* @param regType Тип регистра.
|
||||
* @param registerFrom Начальный регистр диапазона.
|
||||
* @param registerTo Конечный регистр диапазона.
|
||||
* @param doExecution Выполнять ли действие.
|
||||
* @param submitParam Флаг для подавления повторных действий.
|
||||
* @return Команда itemCmd с результатом.
|
||||
*/
|
||||
itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uint8_t regType, uint16_t registerFrom, uint16_t registerTo, bool doExecution, bool * submitParam)
|
||||
{
|
||||
aJsonObject * paramObj = store->parameters->child;
|
||||
@@ -627,7 +698,12 @@ return itemCmd();
|
||||
}
|
||||
|
||||
|
||||
void out_Modbus::pollModbus(aJsonObject * reg, int regType)
|
||||
/**
|
||||
* @brief Опрос Modbus-устройства по списку регистров.
|
||||
* @param reg JSON-объект с регистрами.
|
||||
* @param regType Тип регистра.
|
||||
*/
|
||||
void out_Modbus::pollModbus(aJsonObject * reg, int regType)
|
||||
{
|
||||
if (!reg) return;
|
||||
reg=reg->child;
|
||||
@@ -665,6 +741,9 @@ return itemCmd();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализирует линию связи Modbus.
|
||||
*/
|
||||
void out_Modbus::initLine()
|
||||
{
|
||||
//store->serialParam=(USARTClass::USARTModes) SERIAL_8N1;
|
||||
@@ -683,6 +762,12 @@ void out_Modbus::initLine()
|
||||
node.begin(item->getArg(0), modbusSerial);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Отправляет значение в Modbus-устройство.
|
||||
* @param paramName Имя параметра.
|
||||
* @param outValue JSON-объект с отправляемым значением.
|
||||
* @return 0 при успехе, отрицательное значение при ошибке.
|
||||
*/
|
||||
int out_Modbus::sendModbus(char * paramName, aJsonObject * outValue)
|
||||
{
|
||||
if (!store) {errorSerial<<F(" internal send error - no store")<<endl; return -1;}
|
||||
@@ -819,6 +904,11 @@ if ((res ==0) && (outValue->type == aJson_Int) && lastMeasured && (lastMeasured-
|
||||
return ( res == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Осуществляет опрос и отправку команд Modbus.
|
||||
* @param cause Причина вызова (например, медленный опрос).
|
||||
* @return Интервал следующего опроса.
|
||||
*/
|
||||
int out_Modbus::Poll(short cause)
|
||||
{
|
||||
if (cause==POLLING_SLOW) return 0;
|
||||
@@ -949,11 +1039,21 @@ if (store->pollingRegisters || store->pollingIrs || store->pollingCoils || store
|
||||
return store->pollingInterval;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Возвращает тип канала.
|
||||
* @return CH_MBUS.
|
||||
*/
|
||||
int out_Modbus::getChanType()
|
||||
{
|
||||
return CH_MBUS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Отправляет команду itemCmd в Modbus по шаблону параметра.
|
||||
* @param templateParamObj JSON-объект шаблона параметра.
|
||||
* @param cmd Команда itemCmd.
|
||||
* @return 1 при успехе, 0 при ошибке.
|
||||
*/
|
||||
int out_Modbus::sendItemCmd(aJsonObject *templateParamObj, itemCmd cmd)
|
||||
{
|
||||
if (templateParamObj)
|
||||
@@ -1050,6 +1150,14 @@ else return 0;
|
||||
// 2. custom textual subItem
|
||||
// 3. non-standard numeric suffix Code equal param id
|
||||
|
||||
/**
|
||||
* @brief Унифицированное управление Modbus-каналом.
|
||||
* @param cmd Команда itemCmd.
|
||||
* @param subItem Имя подэлемента.
|
||||
* @param toExecute Выполнять ли команду.
|
||||
* @param authorized Авторизовано ли выполнение.
|
||||
* @return Результат выполнения.
|
||||
*/
|
||||
int out_Modbus::Ctrl(itemCmd cmd, char* subItem, bool toExecute,bool authorized)
|
||||
{
|
||||
if (!store) return -1;
|
||||
|
||||
Reference in New Issue
Block a user