diff --git a/README.md b/README.md index 85d3174..d990bb0 100644 --- a/README.md +++ b/README.md @@ -78,15 +78,16 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to * Allow selecting of pre-defined VSP programs (Aqualink Touch & OneTouch protocols.) * Add set time to OneTouch protocol. -# Update in Release 2.3.0d (pre release) +# Update in Release 2.3.0e (pre release) * This is pre-release, please treat it as such. * Proceed with caution on PDA panels I have not been able to test it fully on all variants and you may need to go back to your current (or previous) version of AqualinkD * Changed a lot of logic around different protocols. -* Add support for dimmers. * AqualinkD will find out the fastest way to change something depending on the protocols available. * Added scheduler (click time in web ui). supports full calendar year (ie seasons), See wiki for details. * Added timers for devices (ie can turn on Pump for x minutes), Long press on device in WebUI. * Timers supported in MQTT/API. +* Add support for dimmers. +* Extended SWG status now in web UI. * Serial logging / error checking enhancements. * Added simulator back. (+ Improved UI). * Fix issue with incorrect device state after duplicate MQTT messages being sent in rapid succession ( < 0.5 second). diff --git a/aq_panel.c b/aq_panel.c index be49bba..b31b85d 100644 --- a/aq_panel.c +++ b/aq_panel.c @@ -109,7 +109,7 @@ setPanel("RS-8 Combo"); */ -char _panelString[36]; +char _panelString[60]; void setPanelString() { sprintf(_panelString, "%s%s-%d %s%s%s", diff --git a/aq_programmer.c b/aq_programmer.c index 789c5a4..194883c 100644 --- a/aq_programmer.c +++ b/aq_programmer.c @@ -81,8 +81,8 @@ bool waitForButtonState(struct aqualinkdata *aq_data, aqkey* button, aqledstate bool waitForEitherMessage(struct aqualinkdata *aq_data, char* message1, char* message2, int numMessageReceived); bool push_aq_cmd(unsigned char cmd); -void waitfor_queue2empty(); -void longwaitfor_queue2empty(); +//void waitfor_queue2empty(); +//void longwaitfor_queue2empty(); void _aq_programmer(program_type r_type, char *args, struct aqualinkdata *aq_data, bool allowOveride); diff --git a/aq_programmer.h b/aq_programmer.h index 364d257..3bdd160 100644 --- a/aq_programmer.h +++ b/aq_programmer.h @@ -119,6 +119,9 @@ void queueGetProgramData(emulation_type source_type, struct aqualinkdata *aq_dat //void queueGetExtendedProgramData(emulation_type source_type, struct aqualinkdata *aq_data, bool labels); unsigned char pop_aq_cmd(struct aqualinkdata *aq_data); +void waitForSingleThreadOrTerminate(struct programmingThreadCtrl *threadCtrl, program_type type); +void cleanAndTerminateThread(struct programmingThreadCtrl *threadCtrl); + //void force_queue_delete() // Yes I want compiler warning if this is used. @@ -137,11 +140,6 @@ int RPM_check(pump_type type, int value, struct aqualinkdata *aqdata); const char *ptypeName(program_type type); const char *programtypeDisplayName(program_type type); -// These shouldn't be here, but just for the PDA AQ PROGRAMMER -void send_cmd(unsigned char cmd); -bool push_aq_cmd(unsigned char cmd); -void waitForSingleThreadOrTerminate(struct programmingThreadCtrl *threadCtrl, program_type type); -void cleanAndTerminateThread(struct programmingThreadCtrl *threadCtrl); -bool waitForMessage(struct aqualinkdata *aq_data, char* message, int numMessageReceived); + #endif diff --git a/aq_serial.c b/aq_serial.c index 5e29b92..068ac84 100644 --- a/aq_serial.c +++ b/aq_serial.c @@ -51,7 +51,10 @@ const char* get_packet_type(unsigned char* packet , int length) switch (packet[PKT_CMD]) { case CMD_ACK: - return "Ack"; + if (packet[5] == NUL) + return "Ack"; + else + return "Ack w/ Command"; break; case CMD_STATUS: return "Status"; @@ -919,7 +922,7 @@ int get_packet(int fd, unsigned char* packet) } LOG(RSSD_LOG,LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index); - if (_aqconfig_.log_protocol_packets) + if (_aqconfig_.log_protocol_packets || getLogLevel(RSSD_LOG) >= LOG_DEBUG_SERIAL) logPacketRead(packet, index); // Return the packet length. return index; diff --git a/aqualinkd.c b/aqualinkd.c index 67b4e4e..cb57918 100644 --- a/aqualinkd.c +++ b/aqualinkd.c @@ -1235,6 +1235,14 @@ int main(int argc, char *argv[]) LOG(AQUA_LOG,LOG_NOTICE, "Config light_pgm_mode = %.2f\n", _aqconfig_.light_programming_mode); LOG(AQUA_LOG,LOG_NOTICE, "Debug RS485 protocol = %s\n", bool2text(_aqconfig_.log_protocol_packets)); LOG(AQUA_LOG,LOG_NOTICE, "Debug RS485 protocol raw = %s\n", bool2text(_aqconfig_.log_raw_bytes)); + if ( _aqconfig_.RSSD_LOG_filter != NUL) + LOG(AQUA_LOG,LOG_NOTICE, "Log RS485 packets from = 0x%02hhx\n", _aqconfig_.RSSD_LOG_filter + + + + + + ); //LOG(AQUA_LOG,LOG_NOTICE, "Use PDA 4 auxiliary info = %s\n", bool2text(_aqconfig_.use_PDA_auxiliary)); //LOG(AQUA_LOG,LOG_NOTICE, "Read Pentair Packets = %s\n", bool2text(_aqconfig_.read_pentair_packets)); // logMessage (LOG_NOTICE, "Config serial_port = %s\n", config_parameters->serial_port); @@ -1861,52 +1869,6 @@ void main_loop() if (getProtocolType(packet_buffer) == JANDY) { _aqualink_data.updated = processJandyPacket(packet_buffer, packet_length, &_aqualink_data); - /* - // We received the ack from a Jandy device we are interested in - if (packet_buffer[PKT_DEST] == DEV_MASTER && interestedInNextAck != DRS_NONE) - { - if (interestedInNextAck == DRS_SWG) - { - _aqualink_data.updated = processPacketFromSWG(packet_buffer, packet_length, &_aqualink_data); - } - else if (interestedInNextAck == DRS_EPUMP) - { - _aqualink_data.updated = processPacketFromJandyPump(packet_buffer, packet_length, &_aqualink_data); - } - interestedInNextAck = DRS_NONE; - previous_packet_to = NUL; - } - // We were expecting an ack from Jandy device but didn't receive it. - else if (packet_buffer[PKT_DEST] != DEV_MASTER && interestedInNextAck != DRS_NONE ) - { - if (interestedInNextAck == DRS_SWG && _aqualink_data.ar_swg_device_status != SWG_STATUS_OFF) - { // SWG Offline - processMissingAckPacketFromSWG(previous_packet_to, &_aqualink_data); - } - else if (interestedInNextAck == DRS_EPUMP) - { // ePump offline - processMissingAckPacketFromJandyPump(previous_packet_to, &_aqualink_data); - } - interestedInNextAck = DRS_NONE; - previous_packet_to = NUL; - } - else if (READ_RSDEV_SWG && packet_buffer[PKT_DEST] == SWG_DEV_ID) - { - interestedInNextAck = DRS_SWG; - _aqualink_data.updated = processPacketToSWG(packet_buffer, packet_length, &_aqualink_data, _aqconfig_.swg_zero_ignore); - previous_packet_to = packet_buffer[PKT_DEST]; - } - else if (READ_RSDEV_ePUMP && packet_buffer[PKT_DEST] >= JANDY_DEC_PUMP_MIN && packet_buffer[PKT_DEST] <= JANDY_DEC_PUMP_MAX) - { - interestedInNextAck = DRS_EPUMP; - _aqualink_data.updated = processPacketToJandyPump(packet_buffer, packet_length, &_aqualink_data); - previous_packet_to = packet_buffer[PKT_DEST]; - } - else - { - interestedInNextAck = DRS_NONE; - previous_packet_to = NUL; - }*/ } // Process Pentair Device Packed (pentair have to & from in message, so no need to) else if (getProtocolType(packet_buffer) == PENTAIR && READ_RSDEV_vsfPUMP) { diff --git a/config.c b/config.c index 6b8ba40..83d9394 100644 --- a/config.c +++ b/config.c @@ -79,6 +79,7 @@ void init_parameters (struct aqconfig * parms) //parms->device_id = strtoul(DEFAULT_DEVICE_ID, &p, 16); parms->device_id = strtoul(DEFAULT_DEVICE_ID, NULL, 16); parms->rssa_device_id = NUL; + parms->RSSD_LOG_filter = NUL; parms->paneltype_mask = 0; #if defined AQ_ONETOUCH || defined AQ_IAQTOUCH parms->extended_device_id = NUL; @@ -381,6 +382,9 @@ bool setConfigValue(struct aqualinkdata *aqdata, char *param, char *value) { } else if (strncasecmp(param, "rssa_device_id", 14) == 0) { _aqconfig_.rssa_device_id = strtoul(cleanalloc(value), NULL, 16); rtn=true; + } else if (strncasecmp(param, "RSSD_LOG_filter", 15) == 0) { + _aqconfig_.RSSD_LOG_filter = strtoul(cleanalloc(value), NULL, 16); + rtn=true; #if defined AQ_ONETOUCH || defined AQ_IAQTOUCH } else if (strncasecmp (param, "extended_device_id_programming", 30) == 0) { // Has to be before the below. diff --git a/config.h b/config.h index e4cff04..a4b4eb1 100644 --- a/config.h +++ b/config.h @@ -77,6 +77,7 @@ struct aqconfig bool display_warnings_web; bool log_protocol_packets; // Read & Write as packets bool log_raw_bytes; // Read as bytes + unsigned char RSSD_LOG_filter; //bool log_raw_RS_bytes; bool readahead_b4_write; bool mqtt_timed_update; diff --git a/json_messages.c b/json_messages.c index df533bd..ea8865d 100644 --- a/json_messages.c +++ b/json_messages.c @@ -501,6 +501,9 @@ int build_aqualink_status_JSON(struct aqualinkdata *aqdata, char* buffer, int si if ( aqdata->orp != TEMP_UNKNOWN ) length += sprintf(buffer+length, ",\"chem_orp\":\"%d\"",aqdata->orp ); + if ( READ_RSDEV_SWG ) + length += sprintf(buffer+length, ",\"swg_fullstatus\": \"%d\"", aqdata->ar_swg_device_status); + length += sprintf(buffer+length, ",\"leds\":{" ); for (i=0; i < aqdata->total_buttons; i++) { diff --git a/packetLogger.c b/packetLogger.c index 631f688..13a736c 100644 --- a/packetLogger.c +++ b/packetLogger.c @@ -13,6 +13,7 @@ static FILE *_byteLogFile = NULL; static bool _logfile_raw = false; static bool _logfile_packets = false; //static bool _includePentair = false; +static unsigned char _lastReadFrom = NUL; void _logPacket(int16_t from, unsigned char *packet_buffer, int packet_length, bool error, bool force, bool is_read); int _beautifyPacket(char *buff, unsigned char *packet_buffer, int packet_length, bool error, bool is_read); @@ -95,9 +96,29 @@ void debuglogPacket(int16_t from, unsigned char *packet_buffer, int packet_lengt void _logPacket(int16_t from, unsigned char *packet_buffer, int packet_length, bool error, bool force, bool is_read) { // No point in continuing if loglevel is < debug_serial and not writing to file - if ( force == false && error == false && getLogLevel(from) < LOG_DEBUG_SERIAL /*&& _logfile_raw == false*/ && _logfile_packets == false) { + if ( force == false && + error == false && + getLogLevel(from) < LOG_DEBUG_SERIAL && + /*_logfile_raw == false &&*/ + _logfile_packets == false ) { return; } + + if ( _aqconfig_.RSSD_LOG_filter != NUL ) { + if (is_read) { + _lastReadFrom = packet_buffer[PKT_DEST]; + if ( is_read && _aqconfig_.RSSD_LOG_filter != packet_buffer[PKT_DEST]) { + return; + } + } else if (!is_read && _lastReadFrom != _aqconfig_.RSSD_LOG_filter) // Must be write + return; +/* + if ( is_read && _aqconfig_.RSSD_LOG_filter != packet_buffer[PKT_DEST]) { + return; + } +*/ + } + char buff[1000]; _beautifyPacket(buff, packet_buffer, packet_length, error, is_read); @@ -110,6 +131,8 @@ void _logPacket(int16_t from, unsigned char *packet_buffer, int packet_length, b else { if (force) LOG(from,LOG_DEBUG, "%s", buff); + //else if (is_read && _aqconfig_.serial_debug_filter != NUL && _aqconfig_.serial_debug_filter == packet_buffer[PKT_DEST]) + // LOG(from,LOG_NOTICE, "%s", buff); else LOG(from,LOG_DEBUG_SERIAL, "%s", buff); } diff --git a/pda.c b/pda.c index d66c7a0..c14e84e 100644 --- a/pda.c +++ b/pda.c @@ -32,10 +32,6 @@ #include "devices_jandy.h" #include "rs_msg_utils.h" -// This needs to be tested on a real panel. -//#define NEW_UPDATE_METHOD - - // static struct aqualinkdata _aqualink_data; static struct aqualinkdata *_aqualink_data; static unsigned char _last_packet_type; @@ -137,31 +133,30 @@ void set_pda_led(struct aqualinkled *led, char state) } } -#ifdef NEW_UPDATE_METHOD void equiptment_update_cycle(int eqID) { // If you have a -1, it's a reset to clear / update information. int i; static uint32_t update_equiptment_bitmask = 0; if (eqID == -1) { - LOG(PDA_LOG,LOG_DEBUG, "(not implimented) Start new equiptment cycle\n"); + LOG(PDA_LOG,LOG_DEBUG, "Start new equiptment cycle\n"); - for (i=0; i < _aqualink_data->total_buttons; i++) { + for (i=0; i < _aqualink_data->total_buttons - 2 ; i++) { // total_buttons - 2 because we don't get heaters in this cycle if ((update_equiptment_bitmask & (1 << (i+1))) != (1 << (i+1))) { if (_aqualink_data->aqbuttons[i].led->state != OFF) { _aqualink_data->aqbuttons[i].led->state = OFF; _aqualink_data->updated = true; - LOG(PDA_LOG,LOG_DEBUG, "(not implimented) Turn off equiptment id %d %s not seen in last cycle\n", i, _aqualink_data->aqbuttons[i].name); + LOG(PDA_LOG,LOG_DEBUG, "Turn off equiptment id %d %s not seen in last cycle\n", i, _aqualink_data->aqbuttons[i].name); } } } update_equiptment_bitmask = 0; } else { update_equiptment_bitmask |= (1 << (eqID+1)); - LOG(PDA_LOG,LOG_DEBUG, "(not implimented) Added equiptment id %d %s to updated cycle\n", eqID, _aqualink_data->aqbuttons[eqID].name); + LOG(PDA_LOG,LOG_DEBUG, "Added equiptment id %d %s to updated cycle\n", eqID, _aqualink_data->aqbuttons[eqID].name); } } -#endif + void pass_pda_equiptment_status_item_OLD(char *msg) { @@ -250,10 +245,8 @@ void pass_pda_equiptment_status_item_OLD(char *msg) { if (strcasecmp(msg, _aqualink_data->aqbuttons[i].label) == 0) { -#ifdef NEW_UPDATE_METHOD equiptment_update_cycle(i); -#endif - LOG(PDA_LOG,LOG_DEBUG, "*** Found Status for %s = '%.*s'\n", _aqualink_data->aqbuttons[i].label, AQ_MSGLEN, msg); + LOG(PDA_LOG,LOG_DEBUG, "Status for %s = '%.*s'\n", _aqualink_data->aqbuttons[i].label, AQ_MSGLEN, msg); // It's on (or delayed) if it's listed here. if (_aqualink_data->aqbuttons[i].led->state != FLASH) { @@ -414,17 +407,21 @@ void setSingleDeviceMode() void process_pda_packet_msg_long_set_time(const char *msg) { - /* +/* // NOT Working at moment, also wrong format LOG(PDA_LOG,LOG_DEBUG, "process_pda_packet_msg_long_set_temp\n"); if (msg[4] == '/' && msg[7] == '/'){ //DATE - rsm_strncpycut(_aqualink_data->date, msg, AQ_MSGLEN-1, AQ_MSGLEN-1); + //rsm_strncpycut(_aqualink_data->date, msg, AQ_MSGLEN-1, AQ_MSGLEN-1); + strncpy(_aqualink_data->date, msg + 11, 3); } else if (msg[6] == ':' && msg[11] == 'M') { // TIME - rsm_strncpycut(_aqualink_data->time, msg, AQ_MSGLEN-1, AQ_MSGLEN-1); + //rsm_strncpycut(_aqualink_data->time, msg, AQ_MSGLEN-1, AQ_MSGLEN-1); + if (msg[4] == ' ') + strncpy(_aqualink_data->time, msg + 5, 6); + else } - */ + */ } void process_pda_packet_msg_long_set_temp(const char *msg) @@ -538,6 +535,25 @@ void process_pda_packet_msg_long_unknown(const char *msg) } } +void pda_pump_update(struct aqualinkdata *aq_data, int updated) { + const int bitmask[MAX_PUMPS] = {1,2,4,8}; + static unsigned char updates = '\0'; + int i; + + if (updated == -1) { + for(i=0; i < MAX_PUMPS; i++) { + if ((updates & bitmask[i]) != bitmask[i]) { + aq_data->pumps[i].rpm = PUMP_OFF_RPM; + aq_data->pumps[i].gpm = PUMP_OFF_GPM; + aq_data->pumps[i].watts = PUMP_OFF_WAT; + } + } + updates = '\0'; + } else if (updated >=0 && updated < MAX_PUMPS) { + updates |= bitmask[updated]; + } +} + void log_pump_information() { int i; //bool rtn = false; @@ -578,9 +594,10 @@ void log_pump_information() { for (i=0; i < _aqualink_data->num_pumps; i++) { if (_aqualink_data->pumps[i].pumpIndex == pump_index) { + LOG(PDA_LOG,LOG_INFO, "PDA Pump label: %s Index: %d, ID: %d, RPM: %d, Watts: %d, GPM: %d\n",_aqualink_data->pumps[i].button->name, i ,pump_index,pump_index,rpm,watts,gpm); //printf("**** FOUND PUMP %d at index %d *****\n",pump_index,i); //aq_data->pumps[i].updated = true; - //pump_update(_aqualink_data, i); + pda_pump_update(_aqualink_data, i); _aqualink_data->pumps[i].rpm = rpm; _aqualink_data->pumps[i].watts = watts; _aqualink_data->pumps[i].gpm = gpm; @@ -594,27 +611,19 @@ void log_pump_information() { _aqualink_data->pumps[i].pumpType = EPUMP; } //printf ("Set Pump Type to %d\n",aq_data->pumps[i].pumpType); + return; } } + LOG(PDA_LOG,LOG_ERR, "PDA Could not find config for Pump %s, Index %d, RPM %d, Watts %d, GPM %d\n",m3_line,pump_index,rpm,watts,gpm); } } void process_pda_packet_msg_long_equiptment_status(const char *msg_line, int lineindex, bool reset) { - //pass_pda_equiptment_status_item(msg); - -#ifdef NEW_UPDATE_METHOD - if (reset) { - equiptment_update_cycle(-1); - LOG(PDA_LOG,LOG_DEBUG, "*************** Equiptment reset\n"); - return; - } -#endif - - LOG(PDA_LOG,LOG_DEBUG, "*************** Pass Equiptment msg '%.16s'\n", msg_line); + LOG(PDA_LOG,LOG_DEBUG, "*** Pass Equiptment msg '%.16s'\n", msg_line); if (msg_line == NULL) { - LOG(PDA_LOG,LOG_DEBUG, "*************** Pass Equiptment msg is NULL do nothing\n"); + LOG(PDA_LOG,LOG_DEBUG, "*** Pass Equiptment msg is NULL do nothing\n"); return; } @@ -643,16 +652,8 @@ void process_pda_packet_msg_long_equiptment_status(const char *msg_line, int lin // FILTER PUMP // CLEANER // - // Equipment Status - // - // Intelliflo VS 1 - // RPM: 1700 - // Watts: 367 - // - // - // - // - // + + // VSP Pumps are not read here, since they are over multiple lines. // Check message for status of device // Loop through all buttons and match the PDA text. @@ -678,53 +679,29 @@ void process_pda_packet_msg_long_equiptment_status(const char *msg_line, int lin _aqualink_data->swg_ppm = atoi(index + strlen(MSG_SWG_PPM)); //if (_aqualink_data->ar_swg_status == SWG_STATUS_OFF) {_aqualink_data->ar_swg_status = SWG_STATUS_ON;} LOG(PDA_LOG,LOG_DEBUG, "SALT = %d\n", _aqualink_data->swg_ppm); - } - else if ((index = rsm_strnstr(msg, MSG_PMP_RPM, AQ_MSGLEN)) != NULL) - { // Default to pump 0, should check for correct pump - _aqualink_data->pumps[0].rpm = atoi(index + strlen(MSG_PMP_RPM)); - LOG(PDA_LOG,LOG_DEBUG, "RPM = %d\n", _aqualink_data->pumps[0].rpm); - log_pump_information(); - } - else if ((index = rsm_strnstr(msg, MSG_PMP_WAT, AQ_MSGLEN)) != NULL) - { // Default to pump 0, should check for correct pump - _aqualink_data->pumps[0].watts = atoi(index + strlen(MSG_PMP_WAT)); - LOG(PDA_LOG,LOG_DEBUG, "Watts = %d\n", _aqualink_data->pumps[0].watts); - log_pump_information(); - } - else if ((index = rsm_strnstr(msg, MSG_PMP_GPM, AQ_MSGLEN)) != NULL) - { // Default to pump 0, should check for correct pump - _aqualink_data->pumps[0].gpm = atoi(index + strlen(MSG_PMP_GPM)); - LOG(PDA_LOG,LOG_DEBUG, "GPM = %d\n", _aqualink_data->pumps[0].gpm); - log_pump_information(); - } - else if ((index = rsm_strnstr(msg, "(Offline)", AQ_MSGLEN)) != NULL) - { // Default to pump 0, should check for correct pump - //_aqualink_data->pumps[0].gpm = atoi(index + strlen(MSG_PMP_GPM)); - LOG(PDA_LOG,LOG_DEBUG, "Pump offline\n"); - log_pump_information(); - } + } else if (rsm_strncmp(msg_line, "POOL HEAT ENA",AQ_MSGLEN) == 0) { _aqualink_data->aqbuttons[_aqualink_data->pool_heater_index].led->state = ENABLE; LOG(PDA_LOG,LOG_DEBUG, "Pool Hearter is enabled\n"); + //equiptment_update_cycle(_aqualink_data->pool_heater_index); } else if (rsm_strncmp(msg_line, "SPA HEAT ENA",AQ_MSGLEN) == 0) { _aqualink_data->aqbuttons[_aqualink_data->spa_heater_index].led->state = ENABLE; - LOG(PDA_LOG,LOG_DEBUG, "Pool Hearter is enabled\n"); + LOG(PDA_LOG,LOG_DEBUG, "Spa Hearter is enabled\n"); + //equiptment_update_cycle(_aqualink_data->spa_heater_index); } else { for (i = 0; i < _aqualink_data->total_buttons; i++) { //LOG(PDA_LOG,LOG_DEBUG, "*** check msg '%s' against '%s'\n",labelBuff,_aqualink_data->aqbuttons[i].label); - LOG(PDA_LOG,LOG_DEBUG, "*** check msg '%.*s' against '%s'\n",AQ_MSGLEN,msg_line,_aqualink_data->aqbuttons[i].label); + //LOG(PDA_LOG,LOG_DEBUG, "*** check msg '%.*s' against '%s'\n",AQ_MSGLEN,msg_line,_aqualink_data->aqbuttons[i].label); if (rsm_strncmp(msg_line, _aqualink_data->aqbuttons[i].label, AQ_MSGLEN-1) == 0) //if (rsm_strcmp(_aqualink_data->aqbuttons[i].label, labelBuff) == 0) { -#ifdef NEW_UPDATE_METHOD equiptment_update_cycle(i); -#endif LOG(PDA_LOG,LOG_DEBUG, "Found Status for %s = '%.*s'\n", _aqualink_data->aqbuttons[i].label, AQ_MSGLEN, msg_line); // It's on (or delayed) if it's listed here. if (_aqualink_data->aqbuttons[i].led->state != FLASH) @@ -808,211 +785,138 @@ bool process_pda_packet(unsigned char *packet, int length) //int i; char *msg; int index = -1; - static bool equiptment_updated = false; - //static bool init = false; - - if (getLogLevel(PDA_LOG) == LOG_DEBUG) { - char buff[1024]; - beautifyPacket(buff, packet, length, true); - LOG(PDA_LOG,LOG_DEBUG, "%s", buff); - } + static bool equiptment_update_loop = false; + static bool read_equiptment_menu = false; -/* - // Some panels don't give the startup messages we used to key the init sequence, so check here - // need to put this in a better spot some time in the future - if (_initWithRS == false && pda_m_type() == PM_FW_VERSION && packet[PKT_CMD] == CMD_PDA_CLEAR ) { - _initWithRS == true; - queueGetProgramData(AQUAPDA, _aqualink_data); - } -*/ - process_pda_menu_packet(packet, length); + process_pda_menu_packet(packet, length, in_programming_mode(_aqualink_data)); - // NSF. - - //_aqualink_data->last_msg_was_status = false; - - // debugPacketPrint(0x00, packet, length); switch (packet[PKT_CMD]) { - - case CMD_ACK: - LOG(PDA_LOG,LOG_DEBUG, "RS Received ACK length %d.\n", length); - //if (init == false) - /* - if (_initWithRS == false) - { - LOG(PDA_LOG,LOG_DEBUG, "Running PDA_INIT\n"); - aq_programmer(AQ_PDA_INIT, NULL, _aqualink_data); - //init = true; - }*/ + case CMD_ACK: + LOG(PDA_LOG,LOG_DEBUG, "RS Received ACK length %d.\n", length); break; - case CMD_STATUS: - _aqualink_data->last_display_message[0] = '\0'; - if (equiptment_updated == true && pda_m_type() != PM_EQUIPTMENT_STATUS) - { - process_pda_packet_msg_long_equiptment_status(NULL, 0, true); - equiptment_updated = false; - } else if (_initWithRS == false && pda_m_type() == PM_FW_VERSION) { - _initWithRS = true; - LOG(PDA_LOG,LOG_DEBUG, "**** PDA INIT ****\n"); - //aq_programmer(AQ_PDA_INIT, NULL, _aqualink_data); - queueGetProgramData(AQUAPDA, _aqualink_data); - } -/* - // If we get a status packet, and we are on the status menu, this is a list of what's on - // or pending so unless flash turn everything off, and just turn on items that are listed. - // This is the only way to update a device that's been turned off by a real PDA / keypad. - // Note: if the last line of the status menu is present it may be cut off - if (pda_m_type() == PM_EQUIPTMENT_STATUS) - { + case CMD_PDA_CLEAR: + read_equiptment_menu = false; // Reset the have read menu flag, since this is new menu. + break; - if (_aqualink_data->frz_protect_state == ON) - _aqualink_data->frz_protect_state = ENABLE; - - //if (_aqualink_data->ar_swg_status == SWG_STATUS_ON) - // _aqualink_data->ar_swg_status = SWG_STATUS_OFF; - - if (_aqualink_data->swg_led_state == ON) - setSWGenabled(_aqualink_data); - - // Need to remove this when new way works. -#ifndef NEW_UPDATE_METHOD - if (pda_m_line(PDA_LINES - 1)[0] == '\0') + case CMD_STATUS: + _aqualink_data->last_display_message[0] = '\0'; + if (equiptment_update_loop == false && pda_m_type() == PM_EQUIPTMENT_STATUS) { - for (i = 0; i < _aqualink_data->total_buttons; i++) - { - if (_aqualink_data->aqbuttons[i].led->state != FLASH) - { - _aqualink_data->aqbuttons[i].led->state = OFF; - } - } + LOG(PDA_LOG,LOG_DEBUG, "**** PDA Start new Equiptment loop ****\n"); + equiptment_update_loop = true; + // Need to process the equiptment full MENU here } - else + else if (read_equiptment_menu == false && equiptment_update_loop == true && pda_m_type() == PM_EQUIPTMENT_STATUS) { - LOG(PDA_LOG,LOG_DEBUG, "PDA Equipment status may be truncated.\n"); + LOG(PDA_LOG,LOG_DEBUG, "**** PDA read Equiptment page ****\n"); + log_pump_information(); + read_equiptment_menu = true; } + else if (equiptment_update_loop == true && pda_m_type() != PM_EQUIPTMENT_STATUS) + { + LOG(PDA_LOG,LOG_DEBUG, "**** PDA End Equiptment loop ****\n"); + // Moved onto different MENU. Probably need to update any pump changes + equiptment_update_loop = false; - for (i = 1; i < PDA_LINES; i++) - pass_pda_equiptment_status_item(pda_m_line(i)); -#else - if (!equiptment_updated) { - equiptment_updated = true; - for (i = 1; i < PDA_LINES; i++) { - pass_pda_equiptment_status_item(pda_m_line(i)); + // End of equiptment status chain of menus, reset any pump or equiptment that wasn't listed in menus as long as we are not in programming mode + if (!in_programming_mode(_aqualink_data) ) { + pda_pump_update(_aqualink_data, -1); + equiptment_update_cycle(-1); } - } -#endif - } - if (pda_m_type() == PM_FREEZE_PROTECT_DEVICES) - { - process_pda_freeze_protect_devices(); - }*/ - break; - case CMD_MSG_LONG: - { - //printf ("*******************************************************************************************\n"); - //printf ("menu type %d\n",pda_m_type()); - - msg = (char *)packet + PKT_DATA + 1; - index = packet[PKT_DATA] & 0xF; - - //strcpy(_aqualink_data->last_message, msg); - - if (packet[PKT_DATA] == 0x82) - { // Air & Water temp is always this ID - process_pda_packet_msg_long_temp(msg); -#ifdef NEW_UPDATE_METHOD -// if (!equiptment_updated) { -// equiptment_update_cycle(-1); // Reset equiptment cycle -// equiptment_updated = false; -// } -#endif - } - else if (packet[PKT_DATA] == 0x40) - { // Time is always on this ID - process_pda_packet_msg_long_time(msg); - // If it wasn't a specific msg, (above) then run through and see what kind - // of message it is depending on the PDA menu. Note don't process EQUIPTMENT - // STATUS menu here, wait until a CMD_STATUS is received. - } - else { - switch (pda_m_type()) { - case PM_EQUIPTMENT_CONTROL: - process_pda_packet_msg_long_equipment_control(msg); - break; - case PM_HOME: - case PM_BUILDING_HOME: - process_pda_packet_msg_long_home(msg); - break; - case PM_EQUIPTMENT_STATUS: - process_pda_packet_msg_long_equiptment_status(msg, index, false); - equiptment_updated = true; - break; - case PM_SET_TEMP: - process_pda_packet_msg_long_set_temp(msg); - break; - case PM_SPA_HEAT: - process_pda_packet_msg_long_spa_heat(msg); - break; - case PM_POOL_HEAT: - process_pda_packet_msg_long_pool_heat(msg); - break; - case PM_FREEZE_PROTECT: - process_pda_packet_msg_long_freeze_protect(msg); - break; - case PM_AQUAPURE: - process_pda_packet_msg_long_SWG(msg); - break; - case PM_AUX_LABEL_DEVICE: - process_pda_packet_msg_long_level_aux_device(msg); - break; - - case PM_SET_TIME: - process_pda_packet_msg_long_set_time(msg); - break; - - //case PM_FW_VERSION: - // process_pda_packet_msg_long_FW_version(msg); - //break; - case PM_UNKNOWN: - default: - process_pda_packet_msg_long_unknown(msg); - break; - } - } - - // printf("** Line index='%d' Highligh='%s' Message='%.*s'\n",pda_m_hlightindex(), pda_m_hlight(), AQ_MSGLEN, msg); - LOG(PDA_LOG,LOG_INFO, "PDA Menu '%d' Selectedline '%s', Last line received '%.*s'\n", pda_m_type(), pda_m_hlight(), AQ_MSGLEN, msg); - break; - } - case CMD_PDA_0x1B: - { - LOG(PDA_LOG,LOG_DEBUG, "**** CMD_PDA_0x1B ****\n"); - // We get two of these on startup, one with 0x00 another with 0x01 at index 4. Just act on one. - // Think this is PDA finishd showing startup screen - if (packet[4] == 0x00) { - if (_initWithRS == false) + } + else if (_initWithRS == false && pda_m_type() == PM_FW_VERSION) { _initWithRS = true; LOG(PDA_LOG,LOG_DEBUG, "**** PDA INIT ****\n"); - //aq_programmer(AQ_PDA_INIT, NULL, _aqualink_data); + //printf("**** PDA INIT PUT BACK IN ****\n"); queueGetProgramData(AQUAPDA, _aqualink_data); - delay(50); // Make sure this one runs first. -#ifdef BETA_PDA_AUTOLABEL - if (_aqconfig_->use_panel_aux_labels) - aq_programmer(AQ_GET_AUX_LABELS, NULL, _aqualink_data); -#endif - aq_programmer(AQ_PDA_WAKE_INIT, NULL, _aqualink_data); - } else { - LOG(PDA_LOG,LOG_DEBUG, "**** PDA WAKE INIT ****\n"); - aq_programmer(AQ_PDA_WAKE_INIT, NULL, _aqualink_data); } - } - } - break; + break; + + case CMD_MSG_LONG: + msg = (char *)packet + PKT_DATA + 1; + index = packet[PKT_DATA] & 0xF; + if (packet[PKT_DATA] == 0x82) + { // Air & Water temp is always this ID + process_pda_packet_msg_long_temp(msg); + } + else if (packet[PKT_DATA] == 0x40) + { // Time is always on this ID + process_pda_packet_msg_long_time(msg); + } + else + { + switch (pda_m_type()) + { + case PM_EQUIPTMENT_CONTROL: + process_pda_packet_msg_long_equipment_control(msg); + break; + case PM_HOME: + case PM_BUILDING_HOME: + process_pda_packet_msg_long_home(msg); + break; + case PM_EQUIPTMENT_STATUS: + process_pda_packet_msg_long_equiptment_status(msg, index, false); + break; + case PM_SET_TEMP: + process_pda_packet_msg_long_set_temp(msg); + break; + case PM_SPA_HEAT: + process_pda_packet_msg_long_spa_heat(msg); + break; + case PM_POOL_HEAT: + process_pda_packet_msg_long_pool_heat(msg); + break; + case PM_FREEZE_PROTECT: + process_pda_packet_msg_long_freeze_protect(msg); + break; + case PM_AQUAPURE: + process_pda_packet_msg_long_SWG(msg); + break; + case PM_AUX_LABEL_DEVICE: + process_pda_packet_msg_long_level_aux_device(msg); + break; + case PM_SET_TIME: + process_pda_packet_msg_long_set_time(msg); + break; + //case PM_FW_VERSION: + // process_pda_packet_msg_long_FW_version(msg); + //break; + case PM_UNKNOWN: + default: + process_pda_packet_msg_long_unknown(msg); + break; + } + } + break; + + case CMD_PDA_0x1B: + LOG(PDA_LOG,LOG_DEBUG, "**** CMD_PDA_0x1B ****\n"); + // We get two of these on startup, one with 0x00 another with 0x01 at index 4. Just act on one. + // Think this is PDA finishd showing startup screen + if (packet[4] == 0x00) { + if (_initWithRS == false) + { + _initWithRS = true; + LOG(PDA_LOG,LOG_DEBUG, "**** PDA INIT ****\n"); + //aq_programmer(AQ_PDA_INIT, NULL, _aqualink_data); + queueGetProgramData(AQUAPDA, _aqualink_data); + delay(50); // Make sure this one runs first. +#ifdef BETA_PDA_AUTOLABEL + if (_aqconfig_->use_panel_aux_labels) + aq_programmer(AQ_GET_AUX_LABELS, NULL, _aqualink_data); +#endif + aq_programmer(AQ_PDA_WAKE_INIT, NULL, _aqualink_data); + } else { + LOG(PDA_LOG,LOG_DEBUG, "**** PDA WAKE INIT ****\n"); + aq_programmer(AQ_PDA_WAKE_INIT, NULL, _aqualink_data); + } + } + break; } if (packet[PKT_CMD] == CMD_MSG_LONG || packet[PKT_CMD] == CMD_PDA_HIGHLIGHT || @@ -1022,8 +926,14 @@ bool process_pda_packet(unsigned char *packet, int length) // We processed the next message, kick any threads waiting on the message. kick_aq_program_thread(_aqualink_data, AQUAPDA); } - + + // HERE AS A TEST. NEED TO FULLY TEST THIS IS GOES TO PROD. + else if (packet[PKT_CMD] == CMD_STATUS) + { + kick_aq_program_thread(_aqualink_data, AQUAPDA); + } return rtn; } + diff --git a/pda_aq_programmer.c b/pda_aq_programmer.c index 64a4e92..f8689a4 100644 --- a/pda_aq_programmer.c +++ b/pda_aq_programmer.c @@ -33,6 +33,7 @@ #include "pda_aq_programmer.h" #include "config.h" #include "aq_panel.h" +#include "rs_msg_utils.h" #ifdef AQ_DEBUG @@ -123,7 +124,8 @@ bool wait_pda_selected_item(struct aqualinkdata *aq_data) } bool waitForPDAnextMenu(struct aqualinkdata *aq_data) { - waitForPDAMessageType(aq_data,CMD_PDA_CLEAR,10); + if (!waitForPDAMessageType(aq_data,CMD_PDA_CLEAR,10)) + return false; return waitForPDAMessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,15); } @@ -250,10 +252,12 @@ bool find_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, int charli if ((min_index != -1) && ((index - i) > (i - min_index + max_index - index + 1))) { cnt = i - min_index + max_index - index + 1; for (i=0; i < cnt; i++) { + waitfor_queue2empty(); send_cmd(KEY_PDA_UP); } } else { for (i=pda_m_hlightindex(); i < index; i++) { + waitfor_queue2empty(); send_cmd(KEY_PDA_DOWN); } } @@ -261,10 +265,12 @@ bool find_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, int charli if ((min_index != -1) && ((i - index) > (index - min_index + max_index - i + 1))) { cnt = i - min_index + max_index - index + 1; for (i=0; i < cnt; i++) { + waitfor_queue2empty(); send_cmd(KEY_PDA_UP); } } else { for (i=pda_m_hlightindex(); i > index; i--) { + waitfor_queue2empty(); send_cmd(KEY_PDA_UP); } } @@ -291,7 +297,7 @@ bool _select_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, bool wa LOG(PDA_LOG,LOG_DEBUG, "PDA Device programmer selected menu item '%s'\n",menuText); if (waitForNextMenu) - waitForPDAnextMenu(aq_data); + return waitForPDAnextMenu(aq_data); return true; } @@ -306,6 +312,7 @@ bool _select_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, bool wa // https://www.jandy.com/-/media/zodiac/global/downloads/h/h0574200.pdf // and 6594 - AquaLink RS Control Panel Installation Manual // https://www.jandy.com/-/media/zodiac/global/downloads/0748-91071/6594.pdf + bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu) { bool ret = true; int cnt = 0; @@ -600,8 +607,10 @@ void *set_aqualink_PDA_init( void *ptr ) //printf("****** Version '%s' ********\n",aq_data->version); LOG(PDA_LOG,LOG_DEBUG, "PDA type=%d, version=%s\n", _PDA_Type, aq_data->version); // don't wait for version menu to time out press back to get to home menu faster - send_cmd(KEY_PDA_BACK); - if (! waitForPDAnextMenu(aq_data)) { + //send_cmd(KEY_PDA_BACK); + //if (! waitForPDAnextMenu(aq_data)) { // waitForPDAnextMenu waits for highlight chars, which we don't get on normal menu + + if (! waitForPDAMessageType(aq_data,CMD_PDA_CLEAR,10)) { LOG(PDA_LOG,LOG_ERR, "PDA Init :- wait for next menu failed\n"); } } @@ -626,6 +635,8 @@ void *set_aqualink_PDA_init( void *ptr ) pda_reset_sleep(); + goto_pda_menu(aq_data, PM_HOME); + cleanAndTerminateThread(threadCtrl); // just stop compiler error, ptr is not valid as it's just been freed @@ -678,7 +689,11 @@ bool get_PDA_aqualink_pool_spa_heater_temps(struct aqualinkdata *aq_data) { // Get heater setpoints if (! goto_pda_menu(aq_data, PM_SET_TEMP)) { - return false; + LOG(PDA_LOG,LOG_ERR, "Could not get heater setpoints, trying again!\n"); + // Going to try this twice. + if (! goto_pda_menu(aq_data, PM_SET_TEMP)) { + return false; + } } return true; @@ -715,19 +730,23 @@ bool waitForPDAMessageHighlight(struct aqualinkdata *aq_data, int highlighIndex, } -bool waitForPDAMessageType(struct aqualinkdata *aq_data, unsigned char mtype, int numMessageReceived) +bool _waitForPDAMessageType(struct aqualinkdata *aq_data, unsigned char mtype, int numMessageReceived, bool forceNext) { LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageType 0x%02hhx\n",mtype); int i=0; pthread_mutex_lock(&aq_data->active_thread.thread_mutex); + if (forceNext) { // Ignore current message type, and wait for next + pthread_cond_wait(&aq_data->active_thread.thread_cond, &aq_data->active_thread.thread_mutex); + } + while( ++i <= numMessageReceived) { LOG(PDA_LOG,LOG_DEBUG, "waitForPDAMessageType 0x%02hhx, last message type was 0x%02hhx (%d of %d)\n",mtype,aq_data->last_packet_type,i,numMessageReceived); - + if (aq_data->last_packet_type == mtype) break; - + pthread_cond_wait(&aq_data->active_thread.thread_cond, &aq_data->active_thread.thread_mutex); } @@ -743,6 +762,16 @@ bool waitForPDAMessageType(struct aqualinkdata *aq_data, unsigned char mtype, in return true; } +bool waitForPDAMessageType(struct aqualinkdata *aq_data, unsigned char mtype, int numMessageReceived){ + return _waitForPDAMessageType(aq_data, mtype, numMessageReceived, false); +} +bool waitForPDANextMessageType(struct aqualinkdata *aq_data, unsigned char mtype, int numMessageReceived){ + return _waitForPDAMessageType(aq_data, mtype, numMessageReceived, true); +} + + + + // Wait for Message, hit return on particular menu. bool waitForPDAMessageTypesOrMenu(struct aqualinkdata *aq_data, unsigned char mtype1, unsigned char mtype2, int numMessageReceived, char *text, int line) { @@ -785,6 +814,10 @@ bool waitForPDAMessageTypes(struct aqualinkdata *aq_data, unsigned char mtype1, return waitForPDAMessageTypesOrMenu(aq_data, mtype1, mtype2, numMessageReceived, NULL, 0); } +/* + Use -1 for cur_val if you want this to find the delected value and change it. + Use number for cur_val to increase / decrease from known start point +*/ bool set_PDA_numeric_field_value(struct aqualinkdata *aq_data, int val, int cur_val, char *select_label, int step) { int i=0; @@ -792,19 +825,43 @@ bool set_PDA_numeric_field_value(struct aqualinkdata *aq_data, int val, int cur_ // :TODO: Should probably change below to call find_pda_menu_item(), rather than doing it here // If we lease this, need to limit on the number of loops //while ( strncasecmp(pda_m_hlight(), select_label, 8) != 0 ) { - while ( strncasecmp(pda_m_hlight(), select_label, strlen(select_label)) != 0 ) { + //while ( strncasecmp(pda_m_hlight(), select_label, strlen(select_label)) != 0 ) { + while ( rsm_strncmp(pda_m_hlight(), select_label, strlen(select_label)) != 0 ) { + LOG(PDA_LOG,LOG_DEBUG, "Numeric selector selecting '%s' current selection '%s'\n", select_label, pda_m_hlight()); send_cmd(KEY_PDA_DOWN); - delay(500); // Last message probably was CMD_PDA_HIGHLIGHT, so wait before checking. - waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHT,2); + //delay(500); // Last message probably was CMD_PDA_HIGHLIGHT, so wait before checking. + waitfor_queue2empty(); + waitForPDAMessageType(aq_data,CMD_PDA_HIGHLIGHT,5); if (i > 10) { LOG(PDA_LOG,LOG_ERR, "Numeric selector could not find string '%s'\n", select_label); return false; } i++; } + LOG(PDA_LOG,LOG_DEBUG, "Numeric selector, selecting '%s'\n", pda_m_hlight()); send_cmd(KEY_PDA_SELECT); } + if (cur_val == -1) { + char *hghlight_chars; + int hlight_length=0; + int i=0; + //hghlight_chars = pda_m_hlightchars(&hlight_length); + while (hlight_length >= 15 || hlight_length <= 0) { + delay(500); + waitForPDANextMessageType(aq_data,CMD_PDA_HIGHLIGHTCHARS,5); + hghlight_chars = pda_m_hlightchars(&hlight_length); + LOG(PDA_LOG,LOG_DEBUG, "Numeric selector, highlight chars '%.*s'\n",hlight_length , hghlight_chars); + if (++i >= 20) { + LOG(PDA_LOG,LOG_ERR, "Numeric selector, didn't find highlight chars, current selection is '%.*s'\n",hlight_length , hghlight_chars); + return false; + } + } + + cur_val = atoi(hghlight_chars); + LOG(PDA_LOG,LOG_DEBUG, "Numeric selector, highlight chars '%.*s', numeric value using %d\n",hlight_length , hghlight_chars, cur_val); + } + if (val < cur_val) { LOG(PDA_LOG,LOG_DEBUG, "Numeric selector %s value : lower from %d to %d\n", select_label, cur_val, val); for (i = cur_val; i > val; i=i-step) { @@ -816,7 +873,7 @@ bool set_PDA_numeric_field_value(struct aqualinkdata *aq_data, int val, int cur_ send_cmd(KEY_PDA_UP); } } else { - LOG(PDA_LOG,LOG_INFO, "Numeric selector %s value : already at %d\n", select_label, val); + LOG(PDA_LOG,LOG_DEBUG, "Numeric selector %s value : already at %d\n", select_label, val); } send_cmd(KEY_PDA_SELECT); @@ -829,12 +886,15 @@ bool set_PDA_aqualink_SWG_setpoint(struct aqualinkdata *aq_data, int val) { if (! goto_pda_menu(aq_data, PM_AQUAPURE)) { LOG(PDA_LOG,LOG_ERR, "Error finding SWG setpoints menu\n"); + return false; } - if (aq_data->aqbuttons[SPA_INDEX].led->state != OFF) - return set_PDA_numeric_field_value(aq_data, val, aq_data->swg_percent, "SET SPA", 5); - else - return set_PDA_numeric_field_value(aq_data, val, aq_data->swg_percent, "SET POOL", 5); + if (aq_data->aqbuttons[SPA_INDEX].led->state != OFF) { + //int cur_val = atoi + return set_PDA_numeric_field_value(aq_data, val, -1, "SET SPA", 5); + } else { + return set_PDA_numeric_field_value(aq_data, val, -1, "SET POOL", 5); + } //return true; } diff --git a/pda_aq_programmer.h b/pda_aq_programmer.h index c4932b6..55ea22b 100644 --- a/pda_aq_programmer.h +++ b/pda_aq_programmer.h @@ -24,6 +24,14 @@ bool get_PDA_aqualink_aux_labels(struct aqualinkdata *aq_data); bool set_PDA_aqualink_boost(struct aqualinkdata *aq_data, bool val); bool set_PDA_aqualink_time(struct aqualinkdata *aq_data); + +// These are from aq_programmer.c , exposed here for PDA AQ PROGRAMMER +void send_cmd(unsigned char cmd); +bool push_aq_cmd(unsigned char cmd); +bool waitForMessage(struct aqualinkdata *aq_data, char* message, int numMessageReceived); +void waitfor_queue2empty(); +void longwaitfor_queue2empty(); + //void pda_programming_thread_check(struct aqualinkdata *aq_data); #endif // AQ_PDA_PROGRAMMER_H_ \ No newline at end of file diff --git a/pda_menu.c b/pda_menu.c index 8fb1e9f..f7654a4 100644 --- a/pda_menu.c +++ b/pda_menu.c @@ -44,7 +44,7 @@ void print_menu() } if (_hlightcharindexstart > -1) { - LOG(PDA_LOG,LOG_DEBUG, "PDA Menu highlighted characters numer=%d start=%d end=%d actual='%.*s'\n",(_hlightcharindexstop-_hlightcharindexstart),_hlightcharindexstart,_hlightcharindexstop,(_hlightcharindexstop-_hlightcharindexstart),&_menu[_hlightindex][_hlightcharindexstart+1]); + LOG(PDA_LOG,LOG_DEBUG, "PDA Menu highlighted characters line#=%d numer=%d start=%d end=%d actual='%.*s'\n",_hlightindex,(_hlightcharindexstop-_hlightcharindexstart),_hlightcharindexstart,_hlightcharindexstop,(_hlightcharindexstop-_hlightcharindexstart),&_menu[_hlightindex][_hlightcharindexstart+1]); } } @@ -69,7 +69,11 @@ char *pda_m_line(int index) char *pda_m_hlightchars(int *len) { - *len = _hlightcharindexstop - _hlightcharindexstart + 1; + if (_hlightindex <= -1) { + *len = 0; + return NULL; + } + *len = _hlightcharindexstop - _hlightcharindexstart; return &_menu[_hlightindex][_hlightcharindexstart]; } @@ -196,7 +200,7 @@ Line 0 = EQUIPMENT (Line 0 is first. Highlight when complete) */ -bool process_pda_menu_packet(unsigned char* packet, int length) +bool process_pda_menu_packet(unsigned char* packet, int length, bool force_print_menu) { bool rtn = true; signed char first_line; @@ -204,6 +208,7 @@ bool process_pda_menu_packet(unsigned char* packet, int length) signed char line_shift; signed char i; int index = 0; + static bool printed_page = false; switch (packet[PKT_CMD]) { @@ -212,6 +217,13 @@ bool process_pda_menu_packet(unsigned char* packet, int length) _hlightcharindexstart = -1; _hlightcharindexstop = -1; memset(_menu, 0, PDA_LINES * (AQ_MSGLEN+1)); + printed_page = false; + break; + case CMD_STATUS: + if ( printed_page == false && (getLogLevel(PDA_LOG) >= LOG_DEBUG)){ + print_menu(); + printed_page = true; + } break; case CMD_MSG_LONG: /* @@ -226,7 +238,7 @@ bool process_pda_menu_packet(unsigned char* packet, int length) strncpy(_menu[index], (char*)packet+PKT_DATA+1, AQ_MSGLEN); _menu[index][AQ_MSGLEN] = '\0'; } - if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();} + if (getLogLevel(PDA_LOG) >= LOG_DEBUG && force_print_menu ){print_menu();} break; case CMD_PDA_HIGHLIGHT: // when switching from hlight to hlightchars index 255 is sent to turn off hlight @@ -236,10 +248,11 @@ bool process_pda_menu_packet(unsigned char* packet, int length) _hlightcharindexstop = -1; } else { _hlightindex = -1; - _hlightcharindexstart = -1; + _hlightcharindexstart = -1; _hlightcharindexstop = -1; } - if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();} + //if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();} + if (getLogLevel(PDA_LOG) >= LOG_DEBUG && force_print_menu ){print_menu();} break; case CMD_PDA_HIGHLIGHTCHARS: // pkt[4] = line, pkt[5] = startchar, pkt[6] = endchar, pkt[7] = clr/inv @@ -253,13 +266,16 @@ bool process_pda_menu_packet(unsigned char* packet, int length) // https://github.com/ballle98/AqualinkD/issues/46 // Character highlight should not update highlight index if (packet[4] <= PDA_LINES) { + _hlightindex = packet[4]; _hlightcharindexstart = packet[5]; _hlightcharindexstop = packet[6]; } else { + _hlightindex = -1; _hlightcharindexstart = -1; _hlightcharindexstop = -1; } - if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();} + //if (getLogLevel(PDA_LOG) >= LOG_DEBUG){print_menu();} + if (getLogLevel(PDA_LOG) >= LOG_DEBUG && force_print_menu ){print_menu();} break; case CMD_PDA_SHIFTLINES: // press up from top - shift menu down by 1 diff --git a/pda_menu.h b/pda_menu.h index 86af3d2..f0c337a 100644 --- a/pda_menu.h +++ b/pda_menu.h @@ -68,7 +68,7 @@ typedef enum pda_menu_type { */ //bool pda_mode(); //void set_pda_mode(bool val); -bool process_pda_menu_packet(unsigned char* packet, int length); +bool process_pda_menu_packet(unsigned char* packet, int length, bool force_print_menu); int pda_m_hlightindex(); char *pda_m_hlight(); char *pda_m_line(int index); diff --git a/release/aqualinkd b/release/aqualinkd index ce86fc6..dcb725a 100755 Binary files a/release/aqualinkd and b/release/aqualinkd differ diff --git a/release/aqualinkd.conf b/release/aqualinkd.conf index 4731daa..087c92c 100755 --- a/release/aqualinkd.conf +++ b/release/aqualinkd.conf @@ -123,11 +123,14 @@ report_zero_pool_temp = no # MQTT will only post updated information, this option AqualinkD will re-post all MQTT information every ~5 minutes. #mqtt_timed_update = no -# Please see forum for this, only set to yes when logging information to support -# new devices. Inflrmation will be written to /tmp/RS485.log & /tmp/RS485_raw.log respectively +# Please see forum for this, only set to yes when logging information to support new devices. (or debugging protocol) +# Information will be written to /tmp/RS485.log & /tmp/RS485_raw.log respectively #debug_RSProtocol_packets = no #debug_RSProtocol_bytes = no +# Log any packets from this device. +#serial_debug_filter = 0x00 + # Not documented. These will change how RS485 / Serial works, Only use if asked to for problem solving purposes. #serial_readahead_b4_write = yes #thread_netservices = yes diff --git a/rs_msg_utils.c b/rs_msg_utils.c index 1ae3f11..606ee6b 100644 --- a/rs_msg_utils.c +++ b/rs_msg_utils.c @@ -103,7 +103,7 @@ int rsm_strncmp(const char *haystack, const char *needle, int length) while(isspace(*ep1)) ep1--; - //LOG(AQUA_LOG,LOG_DEBUG, "CHECK haystack SP1='%c' EP1='%c' SP2='%c' '%.*s' for '%s' length=%d\n",*sp1,*ep1,*sp2,(ep1-sp1)+1,sp1,sp2,(ep1-sp1)+1); + LOG(AQUA_LOG,LOG_DEBUG, "CHECK haystack SP1='%c' EP1='%c' SP2='%c' '%.*s' for '%s' length=%d\n",*sp1,*ep1,*sp2,(ep1-sp1)+1,sp1,sp2,(ep1-sp1)+1); // Need to write this myself for speed // Need to check if full length string (no space on end), that the +1 is accurate. MIN should do it return strncasecmp(sp1, sp2, MIN((ep1-sp1)+1,length)); diff --git a/utils.c b/utils.c index aeb61e0..5cb8441 100644 --- a/utils.c +++ b/utils.c @@ -82,7 +82,9 @@ int getLogLevel(int16_t from) // RSSD_LOG should default to INFO unless the mask is explicitly set. // IE Even if DEBUG is set, (Note ignored for the moment) - if ( ((_logforcemask & from) == from ) && _log_level < LOG_DEBUG_SERIAL) + if ( from == RSSD_LOG && ((_logforcemask & from) == from ) && _log_level < LOG_DEBUG_SERIAL) + return LOG_DEBUG_SERIAL; + else if ( ((_logforcemask & from) == from ) && _log_level < LOG_DEBUG_SERIAL) return LOG_DEBUG; return _log_level; diff --git a/web/config.js b/web/config.js index f80ce14..593a738 100644 --- a/web/config.js +++ b/web/config.js @@ -60,6 +60,22 @@ "Cool Cabaret - Show" ]; + // all SWG return a status number, some have different meanings. Change the text below to suit, NOT THE NUMBER. + var swgStatus = { + 0: "On", + 1: "No flow", + 2: "Low salt", + 4: "High salt", + 8: "Clean cell", + 9: "Turning off", + 16: "High current", + 32: "Low volts", + 64: "Low temp", + 128: "Check PCB", + 255: "Off" + } + + /* * BELOW IS NOT RELIVENT FOR simple.html or simple inteface * diff --git a/web/controller.html b/web/controller.html index 472d6ae..b1614dd 100644 --- a/web/controller.html +++ b/web/controller.html @@ -580,6 +580,25 @@ else var _link_spa_and_heater=false; + // If swgStatus was defined in config.js, use it, else create our own + if (typeof swgStatus !== 'undefined') { + var _swgStatus = swgStatus; + } else { + var _swgStatus = { + 0: "On", + 1: "No flow", + 2: "Low salt", + 4: "High salt", + 8: "Clean cell", + 9: "Turning off", + 16: "High current", + 32: "Low volts", + 64: "Low temp", + 128: "Check PCB", + 255: "Off" + } + } + function init() { setSizeSpecifics(); populateLightProgram(-1); @@ -1014,6 +1033,7 @@ return status; } + function setTileOn(id, status) { //console.log("setTileOn "+id+ " "+status); var tile; @@ -1052,7 +1072,12 @@ var type; if ((type = tile.getAttribute('type')) != null) { if (type == 'setpoint_swg') { - if (tile.getAttribute('Boost') == 'on') + var exstatus = parseInt(tile.getAttribute('fullstatus')) + // Could also ignore "Enabled" in below, that way we don't jump different stats on startup + if (exstatus > 0 && exstatus < 255) {// Not off or on + //text = swgFullstatus2String(exstatus); + text = _swgStatus[exstatus]; + } else if (tile.getAttribute('Boost') == 'on') text = "Boost"; else if (status == 'enabled') text = 'Enabled'; @@ -2035,11 +2060,14 @@ if (typeof(data.swg_ppm) !== 'undefined') setTileValue("SWG/PPM", data.swg_ppm); - + if (typeof(data.swg_fullstatus) !== 'undefined') + setTileAttribute('SWG', "fullstatus", data.swg_fullstatus); + if (typeof(data.chem_ph) !== 'undefined') setTileValue("CHEM/pH", data.chem_ph); if (typeof(data.chem_orp) !== 'undefined') setTileValue("CHEM/ORP", data.chem_orp); + /* setTileValue("Air", data.air_temp); setTileValue("Pool_Water", data.pool_temp); @@ -2050,8 +2078,8 @@ if (obj.toString() == 'SWG/Boost') { //console.log("BOOST IS "+data.leds[obj]); setTileAttribute('SWG', "Boost", data.leds[obj]); - setTileValue - } + //setTileValue + } } for (var obj in data.timers) { setTileOnText(obj.toString(),"On (timer)");