diff --git a/Makefile b/Makefile
index 1014394..7c20ab6 100755
--- a/Makefile
+++ b/Makefile
@@ -42,7 +42,7 @@ ifeq ($(DEBUG), true)
endif
SL_SRC = serial_logger.c aq_serial.c utils.c packetLogger.c
-LR_SRC = log_reader.c aq_serial.c utils.c
+LR_SRC = log_reader.c aq_serial.c utils.c packetLogger.c
PL_EXSRC = aq_serial.c
PL_EXOBJ = aq_serial_player.o
PL_SRC := $(filter-out aq_serial.c, $(SRCS))
diff --git a/README.md b/README.md
index 7cd0681..2f7cdc7 100644
--- a/README.md
+++ b/README.md
@@ -66,6 +66,10 @@ Designed to mimic AqualinkRS6 All Button keypad and (like the keypad) is used to
* http://aqualink.ip/simple.html <- (Simple opion if you don't like the above)
* http://aqualink.ip/simulator.html <- (RS8 All Button Control Panel simulator)
#
+# Update in Release 1.3.8
+* Fixed PDA mode from 1.3.7
+* Added SWG Boost to PDA
+* More updates to protocol code for Jandy and Pentair.
# Update in Release 1.3.7
* PDA SUPPORT IS BROKEN IN 1.3.7 DON'T UPGRADE IF YOU'RE USING PDA Mode
* PDA Note:- Due to changes to speed up programming the control panel, PDA mode does not function correctly, I will come back and fix this, but I don't have the time for this release.
diff --git a/aq_programmer.c b/aq_programmer.c
index 1a0cdbc..7cf40b3 100644
--- a/aq_programmer.c
+++ b/aq_programmer.c
@@ -121,7 +121,7 @@ unsigned char pop_aq_cmd(struct aqualinkdata *aq_data)
// 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) ||
- (aq_data->active_thread.ptype != AQ_SET_TIME && last_sent_was_cmd == false) ||
+ (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)
) {
@@ -132,8 +132,10 @@ unsigned char pop_aq_cmd(struct aqualinkdata *aq_data)
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 Waiting to send cmd '0x%02hhx'\n", _pgm_command);
+ 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];
@@ -286,7 +288,8 @@ void aq_programmer(program_type type, char *args, struct aqualinkdata *aq_data)
type != AQ_GET_AUX_LABELS &&
#endif
type != AQ_GET_POOL_SPA_HEATER_TEMPS &&
- type != AQ_SET_FRZ_PROTECTION_TEMP) {
+ 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;
}
@@ -646,6 +649,12 @@ STOP BOOST POOL
*/
int val = atoi((char*)threadCtrl->thread_args);
+ if (pda_mode() == true) {
+ set_PDA_aqualink_boost(aq_data, val);
+ cleanAndTerminateThread(threadCtrl);
+ return ptr;
+ }
+
logMessage(LOG_DEBUG, "programming BOOST to %s\n", val==true?"On":"Off");
if ( select_menu_item(aq_data, "BOOST POOL") != true ) {
@@ -1313,8 +1322,15 @@ void waitfor_queue2empty()
delay(50);
}
- if (_pgm_command != NUL)
+ if (_pgm_command != NUL) {
+ if (pda_mode()) {
+ // Wait for longer in PDA mode since it's slower.
+ while ( (_pgm_command != NUL) && ( i++ < 100) ) {
+ delay(100);
+ }
+ }
logMessage(LOG_WARNING, "Send command Queue did not empty, timeout\n");
+ }
}
diff --git a/aq_serial.c b/aq_serial.c
index 888d839..9f03850 100644
--- a/aq_serial.c
+++ b/aq_serial.c
@@ -31,8 +31,638 @@
#include "config.h"
#include "packetLogger.h"
+//#define USE_AQ_SERIAL_OLD
+
+#ifndef USE_AQ_SERIAL_OLD // Substansial changes to core component, make sure we can role back easily
+
+static struct termios _oldtio;
+
+void send_packet(int fd, unsigned char *packet, int length);
+//unsigned char getProtocolType(unsigned char* packet);
+
+bool _pda_mode = false;
+void set_pda_mode(bool mode)
+{
+ if (mode)
+ logMessage(LOG_NOTICE, "AqualinkD is using PDA mode\n");
+
+ _pda_mode = mode;
+}
+bool pda_mode()
+{
+ return _pda_mode;
+}
+
+const char* get_packet_type(unsigned char* packet , int length)
+{
+ static char buf[15];
+
+ if (length <= 0 )
+ return "";
+
+ switch (packet[PKT_CMD]) {
+ case CMD_ACK:
+ return "Ack";
+ break;
+ case CMD_STATUS:
+ return "Status";
+ break;
+ case CMD_MSG:
+ return "Message";
+ break;
+ case CMD_MSG_LONG:
+ return "Lng Message";
+ break;
+ case CMD_PROBE:
+ return "Probe";
+ break;
+ case CMD_GETID:
+ return "GetID";
+ break;
+ case CMD_PERCENT:
+ return "AR %%";
+ break;
+ case CMD_PPM:
+ return "AR PPM";
+ break;
+ case CMD_PDA_0x05:
+ return "PDA Unknown";
+ break;
+ case CMD_PDA_0x1B:
+ return "PDA Init (*guess*)";
+ break;
+ case CMD_PDA_HIGHLIGHT:
+ return "PDA Hlight";
+ break;
+ case CMD_PDA_CLEAR:
+ return "PDA Clear";
+ break;
+ case CMD_PDA_SHIFTLINES:
+ return "PDA Shiftlines";
+ break;
+ case CMD_PDA_HIGHLIGHTCHARS:
+ return "PDA C_HlightChar";
+ break;
+ case CMD_IAQ_MSG:
+ return "iAq Message";
+ break;
+ case CMD_IAQ_MENU_MSG:
+ return "iAq Menu";
+ break;
+ default:
+ sprintf(buf, "Unknown '0x%02hhx'", packet[PKT_CMD]);
+ return buf;
+ break;
+ }
+}
+
+// Generate and return checksum of packet.
+int generate_checksum(unsigned char* packet, int length)
+{
+ int i, sum, n;
+
+ n = length - 3;
+ sum = 0;
+ for (i = 0; i < n; i++)
+ sum += (int) packet[i];
+ return(sum & 0x0ff);
+}
+
+bool check_jandy_checksum(unsigned char* packet, int length)
+{
+ if (generate_checksum(packet, length) == packet[length-3])
+ return true;
+
+ return false;
+}
+
+bool check_pentair_checksum(unsigned char* packet, int length)
+{
+ //printf("check_pentair_checksum \n");
+ int i, sum, n;
+ n = packet[8] + 9;
+ //n = packet[8] + 8;
+ sum = 0;
+ for (i = 3; i < n; i++) {
+ //printf("Sum 0x%02hhx\n",packet[i]);
+ sum += (int) packet[i];
+ }
+
+ //printf("Check High 0x%02hhx = 0x%02hhx = 0x%02hhx\n",packet[n], packet[length-2],((sum >> 8) & 0xFF) );
+ //printf("Check Low 0x%02hhx = 0x%02hhx = 0x%02hhx\n",packet[n + 1], packet[length-1], (sum & 0xFF) );
+
+ // Check against caculated length
+ if (sum == (packet[length-2] * 256 + packet[length-1]))
+ return true;
+
+ // Check against actual # length
+ if (sum == (packet[n] * 256 + packet[n+1])) {
+ logMessage(LOG_ERR, "Pentair checksum is accurate but length is not\n");
+ return true;
+ }
+
+ return false;
+}
+
+
+void generate_pentair_checksum(unsigned char* packet, int length)
+{
+ int i, sum, n;
+ n = packet[8] + 9;
+ //n = packet[8] + 6;
+ sum = 0;
+ for (i = 3; i < n; i++) {
+ //printf("Sum 0x%02hhx\n",packet[i]);
+ sum += (int) packet[i];
+ }
+
+ packet[n+1] = (unsigned char) (sum & 0xFF); // Low Byte
+ packet[n] = (unsigned char) ((sum >> 8) & 0xFF); // High Byte
+
+}
+
+protocolType getProtocolType(unsigned char* packet) {
+ if (packet[0] == DLE)
+ return JANDY;
+ else if (packet[0] == PP1)
+ return PENTAIR;
+
+ return P_UNKNOWN;
+}
+/*
+unsigned char getProtocolType(unsigned char* packet) {
+ if (packet[0] == DLE)
+ return PCOL_JANDY;
+ else if (packet[0] == PP1)
+ return PCOL_PENTAIR;
+
+ return PCOL_UNKNOWN;
+}
+*/
+
+#ifndef PLAYBACK_MODE
+/*
+Open and Initialize the serial communications port to the Aqualink RS8 device.
+Arg is tty or port designation string
+returns the file descriptor
+*/
+int init_serial_port(const char* tty)
+{
+ long BAUD = B9600;
+ long DATABITS = CS8;
+ long STOPBITS = 0;
+ long PARITYON = 0;
+ long PARITY = 0;
+
+ struct termios newtio; //place for old and new port settings for serial port
+
+ //int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK);
+ int fd = open(tty, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
+ if (fd < 0) {
+ logMessage(LOG_ERR, "Unable to open port: %s\n", tty);
+ return -1;
+ }
+
+ logMessage(LOG_DEBUG_SERIAL, "Openeded serial port %s\n",tty);
+
+ int flags = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK | O_NDELAY);
+ newtio.c_cc[VMIN]= 0;
+ newtio.c_cc[VTIME]= 1;
+ logMessage(LOG_DEBUG_SERIAL, "Set serial port %s to non blocking mode\n",tty);
+
+ tcgetattr(fd, &_oldtio); // save current port settings
+ // set new port settings for canonical input processing
+ newtio.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
+ newtio.c_iflag = IGNPAR;
+ newtio.c_lflag = 0; // ICANON;
+ newtio.c_oflag = 0;
+
+ tcflush(fd, TCIFLUSH);
+ tcsetattr(fd, TCSANOW, &newtio);
+
+ logMessage(LOG_DEBUG_SERIAL, "Set serial port %s io attributes\n",tty);
+
+ return fd;
+}
+
+/* close tty port */
+void close_serial_port(int fd)
+{
+ tcsetattr(fd, TCSANOW, &_oldtio);
+ close(fd);
+ logMessage(LOG_DEBUG_SERIAL, "Closed serial port\n");
+}
+
+
+
+
+
+
+
+// Send an ack packet to the Aqualink RS8 master device.
+// fd: the file descriptor of the serial port connected to the device
+// command: the command byte to send to the master device, NUL if no command
+//
+// NUL = '\x00'
+// DLE = '\x10'
+// STX = '\x02'
+// ETX = '\x03'
+//
+// masterAddr = '\x00' # address of Aqualink controller
+//
+//msg = DLE+STX+dest+cmd+args
+//msg = msg+self.checksum(msg)+DLE+ETX
+// DLE+STX+DEST+CMD+ARGS+CHECKSUM+DLE+ETX
+
+
+void print_hex(char *pk, int length)
+{
+ int i=0;
+ for (i=0;i <-- type to from type-> <------------------------------ data ---------------------------------------->
+*/
+
+void send_pentair_command(int fd, unsigned char *packet_buffer, int size)
+{
+ unsigned char packet[AQ_MAXPKTLEN];
+ int i=0;
+
+ packet[0] = NUL;
+ packet[1] = PP1;
+ packet[2] = PP2;
+ packet[3] = PP3;
+ packet[4] = PP4;
+
+ //packet[i++] = 0x00; // from
+ //packet[i++] = // to
+ for (i=5; i-4 < size; i++) {
+ //printf("added 0x%02hhx at position %d\n",packet_buffer[i-4],i);
+ if (i==6) {
+ // Replace source
+ packet[i] = 0x00;
+ } else if (i==9) {
+ // Replace length
+ //packet[i] = 0xFF;
+ packet[i] = (unsigned char)size-6;
+ } else {
+ packet[i] = packet_buffer[i-4];
+ }
+
+ //packet[i] = packet_buffer[i-4];
+ }
+
+ packet[++i] = NUL; // Checksum
+ packet[++i] = NUL; // Checksum
+ generate_pentair_checksum(&packet[1], i);
+ packet[++i] = NUL;
+
+
+ //logPacket(packet, i);
+ send_packet(fd,packet,i);
+}
+
+//unsigned char packet_buffer[] = {PCOL_PENTAIR, 0x07, 0x0F, 0x10, 0x08, 0x0D, 0x55, 0x55, 0x5B, 0x2A, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00};
+//unsigned char packet_buffer[] = {PCOL_JANDY, 0x07, 0x0F, 0x00, 0x00};
+void send_command(int fd, unsigned char *packet_buffer, int size)
+{
+ unsigned char packet[AQ_MAXPKTLEN];
+ int i=0;
+
+ if (packet_buffer[0] != PCOL_JANDY) {
+ //logMessage(LOG_ERR, "Only Jandy protocol supported at present!\n");
+ send_pentair_command(fd, packet_buffer, size);
+ return;
+ }
+
+ packet[0] = NUL;
+ packet[1] = DLE;
+ packet[2] = STX;
+
+ for (i=3; i-2 < size; i++) {
+ //printf("added 0x%02hhx at position %d\n",packet_buffer[i-2],i);
+ packet[i] = packet_buffer[i-2];
+ }
+
+ packet[++i] = DLE;
+ packet[++i] = ETX;
+ packet[++i] = NUL;
+
+ packet[i-3] = generate_checksum(packet, i);
+
+ send_packet(fd,packet,++i);
+}
+
+void send_packet(int fd, unsigned char *packet, int length)
+{
+
+ int nwrite, i;
+ for (i=0; i= LOG_DEBUG_SERIAL) {
+ //char buf[30];
+ //sprintf(buf, "Sent %8.8s ", get_packet_type(packet+1, length));
+ //log_packet(buf, packet, length);
+ logPacket(packet, length);
+ }
+}
+
+void _send_ack(int fd, unsigned char ack_type, unsigned char command)
+{
+ const int length = 11;
+ // Default null ack with checksum generated, don't mess with it, just over right
+ unsigned char ackPacket[] = { NUL, DLE, STX, DEV_MASTER, CMD_ACK, NUL, NUL, 0x13, DLE, ETX, NUL };
+
+ // Update the packet and checksum if command argument is not NUL.
+ if(command != NUL || ack_type != NUL) {
+ //ackPacket[5] = 0x00 normal, 0x03 some pause, 0x01 some pause ending (0x01 = Screen Busy (also return from logn message))
+ ackPacket[5] = ack_type;
+ ackPacket[6] = command;
+ ackPacket[7] = generate_checksum(ackPacket, length-1);
+ }
+
+ send_packet(fd, ackPacket, length);
+}
+
+void send_ack(int fd, unsigned char command)
+{
+ _send_ack(fd, ACK_NORMAL, command);
+}
+
+// ack_typ should only be ACK_PDA, ACK_NORMAL, ACK_SCREEN_BUSY, ACK_SCREEN_BUSY_DISPLAY
+void send_extended_ack(int fd, unsigned char ack_type, unsigned char command)
+{
+ _send_ack(fd, ack_type, command);
+}
+
+int _get_packet(int fd, unsigned char* packet, bool rawlog);
+
+int get_packet(int fd, unsigned char* packet)
+{
+ return _get_packet(fd, packet, false);
+}
+int get_packet_lograw(int fd, unsigned char* packet)
+{
+ return _get_packet(fd, packet, true);
+}
+int _get_packet(int fd, unsigned char* packet, bool rawlog)
+{
+ unsigned char byte;
+ int bytesRead;
+ int index = 0;
+ bool endOfPacket = false;
+ //bool packetStarted = FALSE;
+ bool lastByteDLE = false;
+ int retry = 0;
+ bool jandyPacketStarted = false;
+ bool pentairPacketStarted = false;
+ //bool lastByteDLE = false;
+ int PentairPreCnt = 0;
+ int PentairDataCnt = -1;
+
+ // Read packet in byte order below
+ // DLE STX ........ ETX DLE
+ // sometimes we get ETX DLE and no start, so for now just ignoring that. Seem to be more applicable when busy RS485 traffic
+
+ while (!endOfPacket) {
+ bytesRead = read(fd, &byte, 1);
+ //if (bytesRead < 0 && errno == EAGAIN && packetStarted == FALSE && lastByteDLE == FALSE) {
+ if (bytesRead < 0 && errno == EAGAIN &&
+ jandyPacketStarted == false &&
+ pentairPacketStarted == false &&
+ lastByteDLE == false) {
+ // We just have nothing to read
+ return 0;
+ } else if (bytesRead < 0 && errno == EAGAIN) {
+ // If we are in the middle of reading a packet, keep going
+ if (retry > 20) {
+ logMessage(LOG_WARNING, "Serial read timeout\n");
+ //log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
+ logPacketError(packet, index);
+ return 0;
+ }
+ retry++;
+ delay(10);
+ #ifdef TESTING
+ } else if (bytesRead == 0 && jandyPacketStarted == false && pentairPacketStarted == false) {
+ // Probably set port to /dev/null for testing.
+ //printf("Read loop return\n");
+ return 0;
+ #endif
+ } else if (bytesRead == 1) {
+ if (rawlog)
+ logPacketByte(&byte);
+
+ if (lastByteDLE == true && byte == NUL)
+ {
+ // Check for DLE | NULL (that's escape DLE so delete the NULL)
+ //printf("IGNORE THIS PACKET\n");
+ lastByteDLE = false;
+ }
+ else if (lastByteDLE == true)
+ {
+ if (index == 0)
+ index++;
+
+ packet[index] = byte;
+ index++;
+ if (byte == STX && jandyPacketStarted == false)
+ {
+ jandyPacketStarted = true;
+ pentairPacketStarted = false;
+ }
+ else if (byte == ETX && jandyPacketStarted == true)
+ {
+ endOfPacket = true;
+ }
+ }
+ else if (jandyPacketStarted || pentairPacketStarted)
+ {
+ packet[index] = byte;
+ index++;
+ if (pentairPacketStarted == true && index == 9)
+ {
+ //printf("Read 0x%02hhx %d pentair\n", byte, byte);
+ PentairDataCnt = byte;
+ }
+ if (PentairDataCnt >= 0 && index - 11 >= PentairDataCnt && pentairPacketStarted == true)
+ {
+ endOfPacket = true;
+ PentairPreCnt = -1;
+ }
+ }
+ else if (byte == DLE && jandyPacketStarted == false)
+ {
+ packet[index] = byte;
+ }
+
+ // // reset index incase we have EOP before start
+ if (jandyPacketStarted == false && pentairPacketStarted == false)
+ {
+ index = 0;
+ }
+
+ if (byte == DLE && pentairPacketStarted == false)
+ {
+ lastByteDLE = true;
+ PentairPreCnt = -1;
+ }
+ else
+ {
+ lastByteDLE = false;
+ if (byte == PP1 && PentairPreCnt == 0)
+ PentairPreCnt = 1;
+ else if (byte == PP2 && PentairPreCnt == 1)
+ PentairPreCnt = 2;
+ else if (byte == PP3 && PentairPreCnt == 2)
+ PentairPreCnt = 3;
+ else if (byte == PP4 && PentairPreCnt == 3)
+ {
+ pentairPacketStarted = true;
+ jandyPacketStarted = false;
+ PentairDataCnt = -1;
+ packet[0] = PP1;
+ packet[1] = PP2;
+ packet[2] = PP3;
+ packet[3] = byte;
+ index = 4;
+ }
+ else if (byte != PP1) // Don't reset counter if multiple PP1's
+ PentairPreCnt = 0;
+ }
+ } else if(bytesRead < 0) {
+ // Got a read error. Wait one millisecond for the next byte to
+ // arrive.
+ logMessage(LOG_WARNING, "Read error: %d - %s\n", errno, strerror(errno));
+ if(errno == 9) {
+ // Bad file descriptor. Port has been disconnected for some reason.
+ // Return a -1.
+ return -1;
+ }
+ delay(100);
+ }
+
+ // Break out of the loop if we exceed maximum packet
+ // length.
+ if (index >= AQ_MAXPKTLEN) {
+ logPacketError(packet, index);
+ logMessage(LOG_WARNING, "Serial packet too large\n");
+ //log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
+ return 0;
+ break;
+ }
+ }
+
+ //logMessage(LOG_DEBUG, "Serial checksum, length %d got 0x%02hhx expected 0x%02hhx\n", index, packet[index-3], generate_checksum(packet, index));
+ if (jandyPacketStarted) {
+ if (check_jandy_checksum(packet, index) != true){
+ logPacketError(packet, index);
+ logMessage(LOG_WARNING, "Serial read bad Jandy checksum, ignoring\n");
+ //log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
+ return 0;
+ }
+ } else if (pentairPacketStarted) {
+ if (check_pentair_checksum(packet, index) != true){
+ logPacketError(packet, index);
+ logMessage(LOG_WARNING, "Serial read bad Pentair checksum, ignoring\n");
+ //log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
+ return 0;
+ }
+ }
+/*
+ if (generate_checksum(packet, index) != packet[index-3]){
+ logMessage(LOG_WARNING, "Serial read bad checksum, ignoring\n");
+ log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
+ return 0;
+ } else*/ if (index < AQ_MINPKTLEN && (jandyPacketStarted || pentairPacketStarted) ) { //NSF. Sometimes we get END sequence only, so just ignore.
+ logPacketError(packet, index);
+ logMessage(LOG_WARNING, "Serial read too small\n");
+ //log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
+ return 0;
+ }
+
+ logMessage(LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
+ logPacket(packet, index);
+ // Return the packet length.
+ return index;
+}
+
+#else // PLAYBACKMODE
+
+#endif
+
+
+#else //USE_AQ_SERIAL_OLD
+
+
+
+
//#define BLOCKING_MODE
-#define PENTAIR_LENGTH_FIX
static struct termios _oldtio;
@@ -77,21 +707,6 @@ void log_packet(int level, char *init_str, unsigned char* packet, int length)
//logMessage(LOG_DEBUG_SERIAL, buff);
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
const char* get_packet_type(unsigned char* packet , int length)
{
static char buf[15];
@@ -586,6 +1201,34 @@ bool check_jandy_checksum(unsigned char* packet, int length)
}
bool check_pentair_checksum(unsigned char* packet, int length)
+{
+ //printf("check_pentair_checksum \n");
+ int i, sum, n;
+ n = packet[8] + 9;
+ //n = packet[8] + 8;
+ sum = 0;
+ for (i = 3; i < n; i++) {
+ //printf("Sum 0x%02hhx\n",packet[i]);
+ sum += (int) packet[i];
+ }
+
+ //printf("Check High 0x%02hhx = 0x%02hhx = 0x%02hhx\n",packet[n], packet[length-2],((sum >> 8) & 0xFF) );
+ //printf("Check Low 0x%02hhx = 0x%02hhx = 0x%02hhx\n",packet[n + 1], packet[length-1], (sum & 0xFF) );
+
+ // Check against caculated length
+ if (sum == (packet[length-2] * 256 + packet[length-1]))
+ return true;
+
+ // Check against actual # length
+ if (sum == (packet[n] * 256 + packet[n+1])) {
+ //logMessage(LOG_ERR, "Pentair checksum is accurate but length is not\n");
+ return true;
+ }
+
+ return false;
+}
+/*
+bool check_pentair_checksum_old(unsigned char* packet, int length)
{
int i, sum, n;
n = packet[8] + 9;
@@ -594,17 +1237,12 @@ bool check_pentair_checksum(unsigned char* packet, int length)
sum += (int) packet[i];
}
-#ifndef PENTAIR_LENGTH_FIX
- if (sum == (packet[length-1] * 256 + packet[length]))
- return true;
-#else
if (sum == (packet[length-2] * 256 + packet[length-1]))
return true;
-#endif
return false;
}
-
+*/
int _get_packet(int fd, unsigned char* packet, bool rawlog);
int get_packet_new_lograw(int fd, unsigned char* packet)
@@ -693,9 +1331,6 @@ int _get_packet(int fd, unsigned char* packet, bool rawlog)
{
endOfPacket = true;
PentairPreCnt = -1;
-#ifndef PENTAIR_LENGTH_FIX
- index--;
-#endif
}
}
else if (byte == DLE && jandyPacketStarted == false)
@@ -1020,3 +1655,5 @@ int get_packet_old(int fd, unsigned char* packet)
return index;
}
+#endif // USE_OLD
+
diff --git a/aq_serial.h b/aq_serial.h
index fad7487..94b2d8f 100644
--- a/aq_serial.h
+++ b/aq_serial.h
@@ -6,6 +6,13 @@
#define CONNECTION_ERROR "ERROR No connection to RS control panel"
+
+// Protocol types
+#define PCOL_JANDY 0xFF
+#define PCOL_PENTAIR 0xFE
+#define PCOL_UNKNOWN 0xFD
+
+
// packet offsets
#define PKT_DEST 2
#define PKT_CMD 3
@@ -205,7 +212,8 @@ SPILLOVER IS DISABLED WHILE SPA IS ON
#define SWG_STATUS_CHECK_PCB 0x80 // check PCB 0x80
-#define CMD_PDA_0x05 0x05
+#define CMD_PDA_0x04 0x04 // No idea, might be building menu
+#define CMD_PDA_0x05 0x05 // No idea
#define CMD_PDA_0x1B 0x1b
#define CMD_PDA_HIGHLIGHT 0x08
#define CMD_PDA_CLEAR 0x09
@@ -245,7 +253,7 @@ typedef enum {
} protocolType;
-int init_serial_port(char* tty);
+int init_serial_port(const char* tty);
void close_serial_port(int file_descriptor);
void set_pda_mode(bool mode);
bool pda_mode();
@@ -257,6 +265,8 @@ void send_ack(int file_descriptor, unsigned char command);
void send_extended_ack(int fd, unsigned char ack_type, unsigned char command);
//void send_cmd(int file_descriptor, unsigned char cmd, unsigned char args);
int get_packet(int file_descriptor, unsigned char* packet);
+int get_packet_lograw(int fd, unsigned char* packet);
+
int get_packet_new(int fd, unsigned char* packet);
int get_packet_new_lograw(int fd, unsigned char* packet);
//void close_serial_port(int file_descriptor, struct termios* oldtio);
diff --git a/aqualinkd.c b/aqualinkd.c
index a709729..13fd664 100644
--- a/aqualinkd.c
+++ b/aqualinkd.c
@@ -1010,10 +1010,11 @@ void caculate_ack_packet(int rs_fd, unsigned char *packet_buffer) {
if (_config_parameters.pda_sleep_mode && pda_shouldSleep()) {
logMessage(LOG_DEBUG, "PDA Aqualink daemon in sleep mode\n");
return;
- } else if (packet_buffer[PKT_CMD] != CMD_STATUS)
- send_ack(rs_fd, NUL);
- else
- send_ack(rs_fd, pop_aq_cmd(&_aqualink_data));
+ //} else if (packet_buffer[PKT_CMD] != CMD_STATUS) // Moved logic to pop_aq_cmd()
+ // send_extended_ack(rs_fd, ACK_PDA, NUL);
+ } else {
+ send_extended_ack(rs_fd, ACK_PDA, pop_aq_cmd(&_aqualink_data));
+ }
} else if (_aqualink_data.simulate_panel && _aqualink_data.active_thread.thread_id == 0) {
// We are in simlator mode, ack get's complicated now.
@@ -1171,9 +1172,7 @@ void main_loop()
}
if (_config_parameters.log_raw_RS_bytes)
- packet_length = get_packet_new_lograw(rs_fd, packet_buffer);
- else if (_config_parameters.read_pentair_packets)
- packet_length = get_packet_new(rs_fd, packet_buffer);
+ packet_length = get_packet_lograw(rs_fd, packet_buffer);
else
packet_length = get_packet(rs_fd, packet_buffer);
diff --git a/log_reader.c b/log_reader.c
index 2d25c0c..23dfda1 100644
--- a/log_reader.c
+++ b/log_reader.c
@@ -22,6 +22,9 @@
#include
#include
#include
+#include
+#include
+#include
#include "aq_serial.h"
#include "utils.h"
@@ -49,6 +52,41 @@ void logiAqualinkMsg(unsigned char *packet_buffer, int packet_length) {
}
+void read_bin_file(char *filename)
+{
+ unsigned char packet_buffer[AQ_MAXPKTLEN];
+ int packet_length;
+ int i=0;
+
+ setLoggingPrms(LOG_DEBUG_SERIAL , false, NULL, NULL);
+ startPacketLogger(false,true);
+
+ int fd = open(filename, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY);
+ if (fd < 0) {
+ logMessage(LOG_ERR, "Unable to open port: %s\n", filename);
+ return;
+ }
+
+ while ( (packet_length = get_packet_new(fd, packet_buffer)) > -1){
+ printf("----------------\n");
+ //logPacket(packet_buffer, packet_length);
+ }
+
+}
+
+void create_bin_file(FILE *in, FILE *out) {
+ char hex[6];
+ unsigned char byte;
+
+ while ( fgets ( hex, 6, in ) != NULL ) /* read a line */
+ {
+ byte = (int)strtol(hex, NULL, 16);
+ //printf("read 0x%02hhx, %s\n",byte,hex);
+ fwrite(&byte, 1,1, out);
+ //return;
+ }
+}
+
int main(int argc, char *argv[]) {
//unsigned char packet_buffer[10];
@@ -56,13 +94,30 @@ int main(int argc, char *argv[]) {
int packet_length = 0;
char hex[5];
int i;
+ FILE *outfile = NULL;
+ bool writeb = false;
//int num;
//int pi;
- if (argc < 1 || access( argv[1], F_OK ) == -1 ) {
+ if (strcmp(argv[1], "-rb") == 0) {
+ read_bin_file(argv[2]);
+ return 0;
+ }
+ else if (argc < 1 || access( argv[1], F_OK ) == -1 ) {
fprintf(stderr, "ERROR, first param must be valid log file\n");
return 1;
}
+
+ else if (strcmp(argv[2], "-b") == 0) {
+ outfile = fopen ( argv[3], "w" );
+ if ( outfile == NULL )
+ {
+ fprintf(stderr, "ERROR, Couldn't open out file `%s`\n", argv[3]);
+ perror ( argv[3] ); /* why didn't the file open? */
+ return 1;
+ }
+ writeb = true;
+ }
FILE *file = fopen ( argv[1], "r" );
if ( file == NULL )
@@ -70,6 +125,13 @@ int main(int argc, char *argv[]) {
perror ( argv[1] ); /* why didn't the file open? */
return 1;
}
+
+ if (writeb) {
+ create_bin_file(file, outfile);
+ fclose ( file );
+ fclose ( outfile );
+ return 0;
+ }
char line [ 128 ]; /* or other suitable maximum line size */
while ( fgets ( line, sizeof line, file ) != NULL ) /* read a line */
@@ -85,20 +147,22 @@ int main(int argc, char *argv[]) {
}
packet_length--;
+
if (packet_buffer[PKT_DEST] == 0x33 && packet_buffer[PKT_CMD] == 0x25)
- logiAqualinkMsg(packet_buffer, packet_length);
+ logiAqualinkMsg(packet_buffer, packet_length);
//if (packet_buffer[PKT_CMD] == 0x24 || packet_buffer[PKT_CMD] == 0x25) {
- printf("To 0x%02hhx, type %15.15s, length %2.2d ", packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length),packet_length);
- fputs ( line, stdout );
+ printf("To 0x%02hhx, type %15.15s, length %2.2d\n", packet_buffer[PKT_DEST], get_packet_type(packet_buffer, packet_length),packet_length);
+ fputs ( line, stdout );
//printf("Message : '");
//fwrite(packet_buffer + 4, 1, packet_length-7, stdout);
//printf("'\n");
//}
+
}
+
fclose ( file );
-
return 0;
}
diff --git a/pda_aq_programmer.c b/pda_aq_programmer.c
index cbf01a9..d32e5cc 100644
--- a/pda_aq_programmer.c
+++ b/pda_aq_programmer.c
@@ -156,16 +156,25 @@ bool loopover_devices(struct aqualinkdata *aq_data) {
/*
if charlimit is set, use case insensitive match and limit chars.
+ if charlimit is -1, use VERY loose matching.
*/
bool find_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, int charlimit) {
int i=pda_m_hlightindex();
int min_index = -1;
int max_index = -1;
+ int index = -1;
int cnt = 0;
logMessage(LOG_DEBUG, "PDA Device programmer looking for menu text '%s'\n",menuText);
- int index = (charlimit == 0)?pda_find_m_index(menuText):pda_find_m_index_case(menuText, charlimit);
+ if (charlimit == 0)
+ index = pda_find_m_index(menuText);
+ else if (charlimit > 0)
+ index = pda_find_m_index_case(menuText, charlimit);
+ else if (charlimit == -1)
+ index = pda_find_m_index_loose(menuText);
+
+ //int index = (charlimit == 0)?pda_find_m_index(menuText):pda_find_m_index_case(menuText, charlimit);
if (index < 0) { // No menu, is there a page down. "PDA Line 9 = ^^ MORE __"
if (strncasecmp(pda_m_line(9)," ^^ MORE", 10) == 0) {
@@ -267,9 +276,18 @@ bool find_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, int charli
return waitForPDAMessageHighlight(aq_data, index, 10);
}
-bool select_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, bool waitForNextMenu) {
+bool _select_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, bool waitForNextMenu, bool loose);
- if ( find_pda_menu_item(aq_data, menuText, 0) ) {
+bool select_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, bool waitForNextMenu){
+ return _select_pda_menu_item(aq_data, menuText, waitForNextMenu, false);
+}
+bool select_pda_menu_item_loose(struct aqualinkdata *aq_data, char *menuText, bool waitForNextMenu){
+ return _select_pda_menu_item(aq_data, menuText, waitForNextMenu, true);
+}
+bool _select_pda_menu_item(struct aqualinkdata *aq_data, char *menuText, bool waitForNextMenu, bool loose) {
+
+ int matchType = loose?-1:0;
+ if ( find_pda_menu_item(aq_data, menuText, matchType) ) {
send_cmd(KEY_PDA_SELECT);
logMessage(LOG_DEBUG, "PDA Device programmer selected menu item '%s'\n",menuText);
@@ -386,6 +404,17 @@ bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu) {
ret = waitForPDAnextMenu(aq_data);
}
break;
+ case PM_BOOST:
+ if (pda_m_type() == PM_HOME) {
+ ret = select_pda_menu_item(aq_data, "MENU", true);
+ } else if (pda_m_type() == PM_MAIN) {
+ ret = select_pda_menu_item_loose(aq_data, "BOOST", true);
+ } else {
+ send_cmd(KEY_PDA_BACK);
+ ret = waitForPDAnextMenu(aq_data);
+ }
+ //printf("****MENU SELECT RETURN %d*****\n",ret);
+ break;
case PM_SET_TEMP:
if (pda_m_type() == PM_HOME) {
ret = select_pda_menu_item(aq_data, "MENU", true);
@@ -421,8 +450,7 @@ bool goto_pda_menu(struct aqualinkdata *aq_data, pda_menu_type menu) {
return false;
break;
}
- logMessage(LOG_DEBUG, "PDA Device programmer request for menu %d, current %d\n",
- menu, pda_m_type());
+ logMessage(LOG_DEBUG, "PDA Device programmer request for menu %d, current %d\n", menu, pda_m_type());
}
if (pda_m_type() != menu) {
logMessage(LOG_ERR, "PDA Device programmer didn't find a requested menu %d, current %d\n", menu, pda_m_type());
@@ -812,6 +840,49 @@ bool set_PDA_aqualink_SWG_setpoint(struct aqualinkdata *aq_data, int val) {
//return true;
}
+bool set_PDA_aqualink_boost(struct aqualinkdata *aq_data, bool val)
+{
+ if (! goto_pda_menu(aq_data, PM_BOOST)) {
+ logMessage(LOG_ERR, "Error finding BOOST menu\n");
+ return false;
+ }
+
+
+
+ // Should be on the START menu item
+ if (val == true) { // Turn on should just be enter
+ if (strstr(pda_m_hlight(), "START") != NULL)
+ send_cmd(KEY_PDA_SELECT);
+ else {
+ logMessage(LOG_ERR, "Error finding BOOST START menu\n");
+ return false;
+ }
+ } else {
+ /*
+ // Should be select options PAUSE | RESTART | STOP
+ int i=0;
+ for (i=0; i < 6; i++) {
+ send_cmd(KEY_PDA_DOWN);
+ waitForPDAMessageTypes(aq_data,CMD_PDA_HIGHLIGHT,CMD_PDA_HIGHLIGHTCHARS,10);
+ if (strstr(pda_m_hlight(), "STOP") != NULL) {
+ send_cmd(KEY_PDA_SELECT);
+ break;
+ }
+ }
+ if (i >= 6)
+ logMessage(LOG_ERR, "Error finding BOOST STOP menu\n");
+ // Should be select options PAUSE | RESTART | STOP
+ // so press down twice then select
+ */
+ // NSF This is really crap, but can't get above to work, need to come back and check menu items against selections.
+ send_cmd(KEY_PDA_DOWN);
+ send_cmd(KEY_PDA_DOWN);
+ send_cmd(KEY_PDA_SELECT);
+ }
+
+ return true;
+}
+
bool set_PDA_aqualink_heater_setpoint(struct aqualinkdata *aq_data, int val, bool isPool) {
char label[10];
int *cur_val;
diff --git a/pda_aq_programmer.h b/pda_aq_programmer.h
index 60034b0..8fae057 100644
--- a/pda_aq_programmer.h
+++ b/pda_aq_programmer.h
@@ -20,6 +20,8 @@ bool get_PDA_freeze_protect_temp(struct aqualinkdata *aq_data);
bool get_PDA_aqualink_aux_labels(struct aqualinkdata *aq_data);
+bool set_PDA_aqualink_boost(struct aqualinkdata *aq_data, bool val);
+
//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 86da6a3..f9f64b9 100644
--- a/pda_menu.c
+++ b/pda_menu.c
@@ -61,6 +61,7 @@ char *pda_m_line(int index)
// return NULL;
}
+// Find exact menu item
int pda_find_m_index(char *text)
{
int i;
@@ -73,6 +74,7 @@ int pda_find_m_index(char *text)
return -1;
}
+// Fine menu item case insensative
int pda_find_m_index_case(char *text, int limit)
{
int i;
@@ -85,6 +87,20 @@ int pda_find_m_index_case(char *text, int limit)
return -1;
}
+
+// Find menu item very loose
+int pda_find_m_index_loose(char *text)
+{
+ int i;
+
+ for (i = 0; i < PDA_LINES; i++) {
+ //printf ("+++ Compare '%s' to '%s' index %d\n",text,pda_m_line(i),i);
+ if (strstr(pda_m_line(i), text) != NULL)
+ return i;
+ }
+
+ return -1;
+}
/*
// Same as above but strip whitespace from menu item (NOT text parameter)
int pda_find_m_index_swcase(char *text, int limit)
@@ -148,7 +164,9 @@ pda_menu_type pda_m_type()
} else if (strncasecmp(_menu[0]," LABEL AUX", 12) == 0 && // Will have number ie AUX4
strncasecmp(_menu[2]," CURRENT LABEL ", 16) == 0) {
return PM_AUX_LABEL_DEVICE;
- }
+ } else if (strstr(_menu[0],"BOOST")) { // This is bad check, but PDA menus are BOOST | BOOST POOL | BOOST SPA, need to do better.
+ return PM_BOOST;
+ }
return PM_UNKNOWN;
}
diff --git a/pda_menu.h b/pda_menu.h
index 61c6f9d..2cb0677 100644
--- a/pda_menu.h
+++ b/pda_menu.h
@@ -27,7 +27,8 @@ typedef enum pda_menu_type {
PM_SETTINGS,
PM_EQUIPTMENT_CONTROL,
PM_EQUIPTMENT_STATUS,
- PM_PALM_OPTIONS // This seems to be only older revisions
+ PM_PALM_OPTIONS, // This seems to be only older revisions
+ PM_BOOST
} pda_menu_type;
/*
@@ -74,6 +75,7 @@ char *pda_m_line(int index);
pda_menu_type pda_m_type();
int pda_find_m_index(char *text);
int pda_find_m_index_case(char *text, int limit);
+int pda_find_m_index_loose(char *text);
//int pda_find_m_index_swcase(char *text, int limit);
#endif
diff --git a/release/aqualinkd b/release/aqualinkd
index 9b1e099..a817c68 100755
Binary files a/release/aqualinkd and b/release/aqualinkd differ
diff --git a/release/serial_logger b/release/serial_logger
index 2c96361..375dc65 100755
Binary files a/release/serial_logger and b/release/serial_logger differ
diff --git a/serial_logger.c b/serial_logger.c
index a402f1d..8f92df9 100644
--- a/serial_logger.c
+++ b/serial_logger.c
@@ -315,7 +315,7 @@ int main(int argc, char *argv[]) {
}
//packet_length = get_packet(rs_fd, packet_buffer);
- packet_length = get_packet_new(rs_fd, packet_buffer);
+ packet_length = get_packet(rs_fd, packet_buffer);
if (packet_length == -1) {
// Unrecoverable read error. Force an attempt to reconnect.
diff --git a/tmp.rs b/tmp.rs
new file mode 100644
index 0000000..25166ee
Binary files /dev/null and b/tmp.rs differ
diff --git a/version.h b/version.h
index f3c620d..bb2d4a4 100644
--- a/version.h
+++ b/version.h
@@ -1,4 +1,4 @@
#define AQUALINKD_NAME "Aqualink Daemon"
-#define AQUALINKD_VERSION "1.3.7"
+#define AQUALINKD_VERSION "1.3.8"