/*
* Copyright (c) 2017 Shaun Feakes - All rights reserved
*
* You may use redistribute and/or modify this code under the terms of
* the GNU General Public License version 2 as published by the
* Free Software Foundation. For the terms of this license,
* see .
*
* You are free to use this software under the terms of the GNU General
* Public License, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* https://github.com/sfeakes/aqualinkd
*/
#include
#include
#include
#include
#include
#include
#include "aqualink.h"
#include "utils.h"
#include "aq_programmer.h"
#include "aq_serial.h"
#include "pda.h"
#include "pda_menu.h"
#include "init_buttons.h"
#include "pda_aq_programmer.h"
#ifdef AQ_DEBUG
#include
#include "timespec_subtract.h"
#endif
bool select_sub_menu_item(struct aqualinkdata *aq_data, char* item_string);
bool select_menu_item(struct aqualinkdata *aq_data, char* item_string);
//void send_cmd(unsigned char cmd, struct aqualinkdata *aq_data);
void cancel_menu();
void *set_aqualink_pool_heater_temps( void *ptr );
void *set_aqualink_spa_heater_temps( void *ptr );
void *set_aqualink_freeze_heater_temps( void *ptr );
void *set_aqualink_time( void *ptr );
void *get_aqualink_pool_spa_heater_temps( void *ptr );
void *get_aqualink_programs( void *ptr );
void *get_freeze_protect_temp( void *ptr );
void *get_aqualink_diag_model( void *ptr );
void *get_aqualink_aux_labels( void *ptr );
//void *threadded_send_cmd( void *ptr );
void *set_aqualink_light_colormode( void *ptr );
void *set_aqualink_PDA_init( void *ptr );
void *set_aqualink_SWG( void *ptr );
void *set_aqualink_boost( void *ptr );
//void *get_aqualink_PDA_device_status( void *ptr );
//void *set_aqualink_PDA_device_on_off( void *ptr );
bool waitForButtonState(struct aqualinkdata *aq_data, aqkey* button, aqledstate state, int numMessageReceived);
//bool waitForMessage(struct aqualinkdata *aq_data, char* message, int numMessageReceived);
bool waitForEitherMessage(struct aqualinkdata *aq_data, char* message1, char* message2, int numMessageReceived);
bool push_aq_cmd(unsigned char cmd);
void waitfor_queue2empty();
#define MAX_STACK 20
int _stack_place = 0;
unsigned char _commands[MAX_STACK];
//unsigned char pgm_commands[MAX_STACK];
unsigned char _pgm_command = NUL;
bool _last_sent_was_cmd = false;
// External view of adding to queue
void aq_send_cmd(unsigned char cmd) {
push_aq_cmd(cmd);
}
bool push_aq_cmd(unsigned char cmd) {
//logMessage(LOG_DEBUG, "push_aq_cmd '0x%02hhx'\n", cmd);
if (_stack_place < MAX_STACK) {
_commands[_stack_place] = cmd;
_stack_place++;
} else {
logMessage(LOG_ERR, "Command queue overflow, too many unsent commands to RS control panel\n");
return false;
}
return true;
}
int get_aq_cmd_length()
{
return _stack_place;
}
unsigned char pop_aq_cmd(struct aqualinkdata *aq_data)
{
unsigned char cmd = NUL;
// Only send commands on status messages
// Are we in programming mode
if (aq_data->active_thread.thread_id != 0) {
/*if ( (_pgm_command == KEY_MENU && aq_data->last_packet_type == CMD_STATUS) ||
// Need to not the key_menu below
( _pgm_command != NUL && (aq_data->last_packet_type == CMD_STATUS || aq_data->last_packet_type == CMD_MSG_LONG) )) {*/
if ( (_pgm_command != NUL && (aq_data->last_packet_type == CMD_STATUS)) ||
// Boost pool has to send commands to msg long
(aq_data->active_thread.ptype == AQ_SET_BOOST && (aq_data->last_packet_type == CMD_STATUS || aq_data->last_packet_type == CMD_MSG_LONG)) ) {
cmd = _pgm_command;
_pgm_command = NUL;
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx' (programming)\n", cmd);
} else if (_pgm_command != NUL) {
logMessage(LOG_DEBUG, "RS Waiting to send cmd '0x%02hhx' (programming)\n", _pgm_command);
} else {
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx' empty queue (programming)\n", cmd);
}
} else if (_stack_place > 0 && aq_data->last_packet_type == CMD_STATUS ) {
cmd = _commands[0];
_stack_place--;
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx'\n", cmd);
memmove(&_commands[0], &_commands[1], sizeof(unsigned char) * _stack_place ) ;
} else {
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx'\n", cmd);
}
//printf("RSM sending cmd '0x%02hhx' in reply to '0x%02hhx'\n",cmd,aq_data->last_packet_type);
return cmd;
}
//unsigned char pop_aq_cmd_old(struct aqualinkdata *aq_data);
unsigned char pop_aq_cmd_XXXXXX(struct aqualinkdata *aq_data)
{
unsigned char cmd = NUL;
static bool last_sent_was_cmd = false;
// USE BELOW IF PDA HAS ISSUES WITH NEW COMMAND LOGIC
//if ( pda_mode() == true ) {
// return pop_aq_cmd_old(aq_data);
//}
// Only press menu to a status command
// Only send commands on status messages when programming date
// Otherwise send every other command.
// Are we in programming mode
if (aq_data->active_thread.thread_id != 0) {
if ( ((_pgm_command == KEY_MENU || aq_data->active_thread.ptype == AQ_SET_TIME) && aq_data->last_packet_type == CMD_STATUS) ||
(pda_mode() == false && aq_data->active_thread.ptype != AQ_SET_TIME && last_sent_was_cmd == false) ||
(pda_mode() == true && aq_data->last_packet_type == CMD_STATUS)
//(pda_mode() == true && last_sent_was_cmd == false)
) {
cmd = _pgm_command;
_pgm_command = NUL;
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx' (programming)\n", cmd);
/*} else if (aq_data->active_thread.ptype != AQ_SET_TIME && last_sent_was_cmd == false) {
cmd = _pgm_command;
_pgm_command = NUL;
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx' (programming)\n", cmd);*/
} else if (_pgm_command != NUL) {
logMessage(LOG_DEBUG, "RS Waiting to send cmd '0x%02hhx' (programming)\n", _pgm_command);
} else {
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx' empty queue (programming)\n", cmd);
}
} else if (_stack_place > 0 && aq_data->last_packet_type == CMD_STATUS ) {
cmd = _commands[0];
_stack_place--;
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx'\n", cmd);
memmove(&_commands[0], &_commands[1], sizeof(unsigned char) * _stack_place ) ;
} else {
logMessage(LOG_DEBUG, "RS SEND cmd '0x%02hhx'\n", cmd);
}
if (cmd == NUL)
last_sent_was_cmd= false;
else
last_sent_was_cmd= true;
return cmd;
}
unsigned char pop_aq_cmd_old(struct aqualinkdata *aq_data)
{
unsigned char cmd = NUL;
//logMessage(LOG_DEBUG, "pop_aq_cmd\n");
// can only send a command every other ack.
if (_last_sent_was_cmd == true) {
_last_sent_was_cmd= false;
}
else if (aq_data->active_thread.thread_id != 0) {
cmd = _pgm_command;
_pgm_command = NUL;
//logMessage(LOG_DEBUG, "pop_aq_cmd '0x%02hhx' (programming)\n", cmd);
}
else if (_stack_place > 0) {
cmd = _commands[0];
_stack_place--;
//logMessage(LOG_DEBUG, "pop_aq_cmd '0x%02hhx'\n", cmd);
//memcpy(&_commands[0], &_commands[1], (sizeof(unsigned char) * MAX_STACK) - 1);
memmove(&_commands[0], &_commands[1], sizeof(unsigned char) * _stack_place ) ;
}
if (cmd == NUL)
_last_sent_was_cmd= false;
else
_last_sent_was_cmd= true;
return cmd;
}
int roundTo(int num, int denominator) {
return ((num + (denominator/2) ) / denominator )* denominator;
}
int setpoint_check(int type, int value, struct aqualinkdata *aqdata)
{
int rtn = value;
int max = 0;
int min = 0;
char *type_msg;
switch(type) {
case POOL_HTR_SETOINT:
type_msg = (aqdata->single_device?"Temp1":"Pool");
if ( aqdata->temp_units == CELSIUS ) {
max = HEATER_MAX_C;
min = (aqdata->single_device?HEATER_MIN_C:HEATER_MIN_C-1);
} else {
max = HEATER_MAX_F;
min = (aqdata->single_device?HEATER_MIN_F:HEATER_MIN_F-1);
}
// if single device then TEMP1 & 2 (not pool & spa), TEMP1 must be set higher than TEMP2
if (aqdata->single_device &&
aqdata->spa_htr_set_point != TEMP_UNKNOWN &&
min <= aqdata->spa_htr_set_point)
{
min = aqdata->spa_htr_set_point + 1;
}
break;
case SPA_HTR_SETOINT:
type_msg = (aqdata->single_device?"Temp2":"Spa");
if ( aqdata->temp_units == CELSIUS ) {
max = (aqdata->single_device?HEATER_MAX_C:HEATER_MAX_C-1);
min = HEATER_MIN_C;
} else {
max = (aqdata->single_device?HEATER_MAX_F:HEATER_MAX_F-1);
min = HEATER_MIN_F;
}
// if single device then TEMP1 & 2 (not pool & spa), TEMP2 must be set lower than TEMP1
if (aqdata->single_device &&
aqdata->pool_htr_set_point != TEMP_UNKNOWN &&
max >= aqdata->pool_htr_set_point)
{
max = aqdata->pool_htr_set_point - 1;
}
break;
case FREEZE_SETPOINT:
type_msg = "Freeze protect";
if ( aqdata->temp_units == CELSIUS ) {
max = FREEZE_PT_MAX_C;
min = FREEZE_PT_MIN_C;
} else {
max = FREEZE_PT_MAX_F;
min = FREEZE_PT_MIN_F;
}
break;
case SWG_SETPOINT:
type_msg = "Salt Water Generator";
max = SWG_PERCENT_MAX;
min = SWG_PERCENT_MIN;
break;
default:
type_msg = "Unknown";
break;
}
if (rtn > max)
rtn = max;
else if (rtn < min)
rtn = min;
// If SWG make sure it's 0,5,10,15,20......
if (type == SWG_SETPOINT) {
rtn = roundTo(rtn, 5);
}
if (rtn != value)
logMessage(LOG_WARNING, "Setpoint of %d for %s is outside range, using %d\n",value,type_msg,rtn);
else
logMessage(LOG_NOTICE, "Setting setpoint of %s to %d\n",type_msg,rtn);
return rtn;
}
void kick_aq_program_thread(struct aqualinkdata *aq_data)
{
if (aq_data->active_thread.thread_id != 0) {
logMessage(LOG_DEBUG, "Kicking thread %d,%p message '%s'\n",aq_data->active_thread.ptype, aq_data->active_thread.thread_id,aq_data->last_message);
pthread_cond_broadcast(&aq_data->active_thread.thread_cond);
}
}
void aq_programmer(program_type type, char *args, struct aqualinkdata *aq_data)
{
struct programmingThreadCtrl *programmingthread = malloc(sizeof(struct programmingThreadCtrl));
if (pda_mode() == true) {
pda_reset_sleep();
if (type != AQ_PDA_INIT &&
type != AQ_PDA_WAKE_INIT &&
type != AQ_PDA_DEVICE_STATUS &&
type != AQ_SET_POOL_HEATER_TEMP &&
type != AQ_SET_SPA_HEATER_TEMP &&
type != AQ_SET_SWG_PERCENT &&
type != AQ_PDA_DEVICE_ON_OFF &&
#ifdef BETA_PDA_AUTOLABEL
type != AQ_GET_AUX_LABELS &&
#endif
type != AQ_GET_POOL_SPA_HEATER_TEMPS &&
type != AQ_SET_FRZ_PROTECTION_TEMP &&
type != AQ_SET_BOOST) {
logMessage(LOG_ERR, "Selected Programming mode '%d' not supported with PDA mode control panel\n",type);
return;
}
}
programmingthread->aq_data = aq_data;
programmingthread->thread_id = 0;
//programmingthread->thread_args = args;
if (args != NULL /*&& type != AQ_SEND_CMD*/)
strncpy(programmingthread->thread_args, args, sizeof(programmingthread->thread_args)-1);
switch(type) {
/*
case AQ_SEND_CMD:
logMessage(LOG_INFO, "Queue send '0x%02hhx' to controller\n", &args[0]);
unsigned char cmd = (unsigned char) &args[0];
if (cmd == NUL) {
logMessage(LOG_INFO, "Queue send '0x%02hhx' to controller (NEW)\n", cmd);
push_aq_cmd( cmd );
} else {
logMessage(LOG_INFO, "Queue send '0x%02hhx' to controller (OLD)\n", cmd);
push_aq_cmd((unsigned char)*args);
}*/
//logMessage(LOG_INFO, "Queue send '0x%02hhx' to controller\n", (unsigned char)*args);
/*
if(aq_data->active_thread.thread_id == 0) { // No need to thread a plane send if no active threads
send_cmd( (unsigned char)*args, aq_data);
} else if( pthread_create( &programmingthread->thread_id , NULL , threadded_send_cmd, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
*/
//break;
case AQ_GET_POOL_SPA_HEATER_TEMPS:
if( pthread_create( &programmingthread->thread_id , NULL , get_aqualink_pool_spa_heater_temps, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_GET_FREEZE_PROTECT_TEMP:
if( pthread_create( &programmingthread->thread_id , NULL , get_freeze_protect_temp, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_TIME:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_time, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_POOL_HEATER_TEMP:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_pool_heater_temps, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_SPA_HEATER_TEMP:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_spa_heater_temps, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_FRZ_PROTECTION_TEMP:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_freeze_heater_temps, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_GET_DIAGNOSTICS_MODEL:
if( pthread_create( &programmingthread->thread_id , NULL , get_aqualink_diag_model, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_GET_PROGRAMS:
if( pthread_create( &programmingthread->thread_id , NULL , get_aqualink_programs, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_COLORMODE:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_light_colormode, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_PDA_INIT:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_PDA_init, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_PDA_WAKE_INIT:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_PDA_wakeinit, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_SWG_PERCENT:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_SWG, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_PDA_DEVICE_STATUS:
if( pthread_create( &programmingthread->thread_id , NULL , get_aqualink_PDA_device_status, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_PDA_DEVICE_ON_OFF:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_PDA_device_on_off, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_GET_AUX_LABELS:
if( pthread_create( &programmingthread->thread_id , NULL , get_aqualink_aux_labels, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
case AQ_SET_BOOST:
if( pthread_create( &programmingthread->thread_id , NULL , set_aqualink_boost, (void*)programmingthread) < 0) {
logMessage (LOG_ERR, "could not create thread\n");
return;
}
break;
default:
logMessage (LOG_ERR, "Don't understand thread type\n");
break;
}
if ( programmingthread->thread_id != 0 ) {
//logMessage (LOG_DEBUG, "********* DID pthread_detach %d\n",programmingthread->thread_id);
pthread_detach(programmingthread->thread_id);
} else {
//logMessage (LOG_DEBUG, "********* DID NOT pthread_detach\n");
}
}
void waitForSingleThreadOrTerminate(struct programmingThreadCtrl *threadCtrl, program_type type)
{
//static int tries = 120;
int tries = 120;
static int waitTime = 1;
int i=0;
i = 0;
while (get_aq_cmd_length() > 0 && ( i++ <= tries) ) {
logMessage (LOG_DEBUG, "Thread %p (%s) sleeping, waiting command queue to empty\n", &threadCtrl->thread_id, ptypeName(type));
sleep(waitTime);
}
if (i >= tries) {
logMessage (LOG_ERR, "Thread %p (%s) timeout waiting, ending\n",&threadCtrl->thread_id,ptypeName(type));
free(threadCtrl);
pthread_exit(0);
}
while ( (threadCtrl->aq_data->active_thread.thread_id != 0) && ( i++ <= tries) ) {
//logMessage (LOG_DEBUG, "Thread %d sleeping, waiting for thread %d to finish\n", threadCtrl->thread_id, threadCtrl->aq_data->active_thread.thread_id);
logMessage (LOG_DEBUG, "Thread %p (%s) sleeping, waiting for thread %p (%s) to finish\n",
&threadCtrl->thread_id, ptypeName(type),
threadCtrl->aq_data->active_thread.thread_id, ptypeName(threadCtrl->aq_data->active_thread.ptype));
sleep(waitTime);
}
if (i >= tries) {
//logMessage (LOG_ERR, "Thread %d timeout waiting, ending\n",threadCtrl->thread_id);
logMessage (LOG_ERR, "Thread %d,%p timeout waiting for thread %d,%p to finish\n",
type, &threadCtrl->thread_id, threadCtrl->aq_data->active_thread.ptype,
threadCtrl->aq_data->active_thread.thread_id);
free(threadCtrl);
pthread_exit(0);
}
// Clear out any messages to the UI.
threadCtrl->aq_data->last_display_message[0] = '\0';
threadCtrl->aq_data->active_thread.thread_id = &threadCtrl->thread_id;
threadCtrl->aq_data->active_thread.ptype = type;
#ifdef AQ_DEBUG
clock_gettime(CLOCK_REALTIME, &threadCtrl->aq_data->start_active_time);
#endif
//logMessage (LOG_DEBUG, "Thread %d is active\n", threadCtrl->aq_data->active_thread.thread_id);
logMessage (LOG_DEBUG, "Thread %d,%p is active (%s)\n",
threadCtrl->aq_data->active_thread.ptype,
threadCtrl->aq_data->active_thread.thread_id,
ptypeName(threadCtrl->aq_data->active_thread.ptype));
}
void cleanAndTerminateThread(struct programmingThreadCtrl *threadCtrl)
{
#ifndef AQ_DEBUG
logMessage(LOG_DEBUG, "Thread %d,%p (%s) finished\n",threadCtrl->aq_data->active_thread.ptype, threadCtrl->thread_id,ptypeName(threadCtrl->aq_data->active_thread.ptype));
#else
struct timespec elapsed;
clock_gettime(CLOCK_REALTIME, &threadCtrl->aq_data->last_active_time);
timespec_subtract(&elapsed, &threadCtrl->aq_data->last_active_time, &threadCtrl->aq_data->start_active_time);
logMessage(LOG_DEBUG, "Thread %d,%p (%s) finished in %d.%03ld sec\n",
threadCtrl->aq_data->active_thread.ptype,
threadCtrl->aq_data->active_thread.thread_id,
ptypeName(threadCtrl->aq_data->active_thread.ptype),
elapsed.tv_sec, elapsed.tv_nsec / 1000000L);
#endif
// Quick delay to allow for last message to be sent.
delay(500);
threadCtrl->aq_data->active_thread.thread_id = 0;
threadCtrl->aq_data->active_thread.ptype = AQP_NULL;
threadCtrl->thread_id = 0;
free(threadCtrl);
pthread_exit(0);
}
bool setAqualinkNumericField_new(struct aqualinkdata *aq_data, char *value_label, int value, int increment);
bool setAqualinkNumericField(struct aqualinkdata *aq_data, char *value_label, int value)
{
return setAqualinkNumericField_new(aq_data, value_label, value, 1);
}
bool setAqualinkNumericField_new(struct aqualinkdata *aq_data, char *value_label, int value, int increment)
{
logMessage(LOG_DEBUG,"Setting menu item '%s' to %d\n",value_label, value);
//char leading[10]; // description of the field (POOL, SPA, FRZ)
int current_val=-1; // integer value of the current set point
//char trailing[10]; // the degrees and scale
char searchBuf[20];
sprintf(searchBuf, "^%s", value_label);
int val_len = strlen(value_label);
int i=0;
do
{
if (waitForMessage(aq_data, searchBuf, 4) != true) {
logMessage(LOG_WARNING, "AQ_Programmer Could not set numeric input '%s', not found\n",value_label);
cancel_menu();
return false;
}
//logMessage(LOG_DEBUG,"WAITING for kick value=%d\n",current_val);
//sscanf(aq_data->last_message, "%s %d%s", leading, ¤t_val, trailing);
//sscanf(aq_data->last_message, "%*[^0123456789]%d", ¤t_val);
sscanf(&aq_data->last_message[val_len], "%*[^0123456789]%d", ¤t_val);
logMessage(LOG_DEBUG, "%s set to %d, looking for %d\n",value_label,current_val,value);
if(value > current_val) {
// Increment the field.
sprintf(searchBuf, "%s %d", value_label, current_val+increment);
send_cmd(KEY_RIGHT);
}
else if(value < current_val) {
// Decrement the field.
sprintf(searchBuf, "%s %d", value_label, current_val-increment);
send_cmd(KEY_LEFT);
}
else {
// Just send ENTER. We are at the right value.
sprintf(searchBuf, "%s %d", value_label, current_val);
send_cmd(KEY_ENTER);
}
if (i++ >= 100) {
logMessage(LOG_WARNING, "AQ_Programmer Could not set numeric input '%s', to '%d'\n",value_label,value);
break;
}
} while(value != current_val);
return true;
}
bool OLD_setAqualinkNumericField_OLD(struct aqualinkdata *aq_data, char *value_label, int value)
{ // Works for everything but not SWG
logMessage(LOG_DEBUG,"Setting menu item '%s' to %d\n",value_label, value);
char leading[10]; // description of the field (POOL, SPA, FRZ)
int current_val; // integer value of the current set point
char trailing[10]; // the degrees and scale
char searchBuf[20];
sprintf(searchBuf, "^%s", value_label);
do
{
if (waitForMessage(aq_data, searchBuf, 3) != true) {
logMessage(LOG_WARNING, "AQ_Programmer Could not set numeric input '%s', not found\n",value_label);
cancel_menu();
return false;
}
//logMessage(LOG_DEBUG,"WAITING for kick value=%d\n",current_val);
sscanf(aq_data->last_message, "%s %d%s", leading, ¤t_val, trailing);
logMessage(LOG_DEBUG, "%s set to %d, looking for %d\n",value_label,current_val,value);
if(value > current_val) {
// Increment the field.
sprintf(searchBuf, "%s %d", value_label, current_val+1);
send_cmd(KEY_RIGHT);
}
else if(value < current_val) {
// Decrement the field.
sprintf(searchBuf, "%s %d", value_label, current_val-1);
send_cmd(KEY_LEFT);
}
else {
// Just send ENTER. We are at the right value.
sprintf(searchBuf, "%s %d", value_label, current_val);
send_cmd(KEY_ENTER);
}
} while(value != current_val);
return true;
}
/*
void *threadded_send_cmd( void *ptr )
{
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
struct aqualinkdata *aq_data = threadCtrl->aq_data;
waitForSingleThreadOrTerminate(threadCtrl, AQ_SEND_CMD);
send_cmd( (unsigned char)*threadCtrl->thread_args, aq_data);
cleanAndTerminateThread(threadCtrl);
return ptr;
}
*/
void *set_aqualink_boost( void *ptr )
{
struct programmingThreadCtrl *threadCtrl;
threadCtrl = (struct programmingThreadCtrl *) ptr;
struct aqualinkdata *aq_data = threadCtrl->aq_data;
waitForSingleThreadOrTerminate(threadCtrl, AQ_SET_BOOST);
/*
menu
BOOST POOL
PRESS ENTER* TO START BOOST POOL