Version 1.3.8

pull/101/merge
sfeakes 2019-10-16 17:53:09 -05:00
parent 51a8b686a5
commit 62f776fa31
16 changed files with 876 additions and 53 deletions

View File

@ -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))

View File

@ -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)
#<a name="release"></a>
# 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.

View File

@ -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");
}
}

View File

@ -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<length;i++)
{
printf("0x%02hhx|",pk[i]);
}
printf("\n");
}
/*
void test_cmd()
{
const int length = 11;
unsigned char ackPacket[] = { NUL, DLE, STX, DEV_MASTER, CMD_ACK, NUL, NUL, 0x13, DLE, ETX, NUL };
//send_cmd(fd, CMD_ACK, command);
print_hex((char *)ackPacket, length);
ackPacket[7] = generate_checksum(ackPacket, length-1);
print_hex((char *)ackPacket, length);
ackPacket[6] = 0x02;
ackPacket[7] = generate_checksum(ackPacket, length-1);
print_hex((char *)ackPacket, length);
}
*/
/*
void send_test_cmd(int fd, unsigned char destination, unsigned char b1, unsigned char b2, unsigned char b3)
{
const int length = 11;
unsigned char ackPacket[] = { NUL, DLE, STX, DEV_MASTER, CMD_ACK, NUL, NUL, 0x13, DLE, ETX, NUL };
//unsigned char ackPacket[] = { NUL, DLE, STX, DEV_MASTER, NUL, NUL, NUL, 0x13, DLE, ETX, NUL };
// Update the packet and checksum if command argument is not NUL.
ackPacket[3] = destination;
ackPacket[4] = b1;
ackPacket[5] = b2;
ackPacket[6] = b3;
ackPacket[7] = generate_checksum(ackPacket, length-1);
#ifdef BLOCKING_MODE
write(fd, ackPacket, length);
#else
int nwrite, i;
for (i=0; i<length; i += nwrite) {
nwrite = write(fd, ackPacket + i, length - i);
if (nwrite < 0)
logMessage(LOG_ERR, "write to serial port failed\n");
}
//logMessage(LOG_DEBUG_SERIAL, "Send %d bytes to serial\n",length);
//tcdrain(fd);
//logMessage(LOG_DEBUG, "Send '0x%02hhx' to '0x%02hhx'\n", command, destination);
#endif
log_packet("Sent ", ackPacket, length);
}
*/
/*
unsigned char tp[] = {PCOL_PENTAIR, 0x07, 0x0F, 0x10, 0x08, 0x0D, 0x55, 0x55, 0x5B, 0x2A, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00};
send_command(0, tp, 19);
Should produce
{0xFF, 0x00, 0xFF, 0xA5, 0x07, 0x0F, 0x10, 0x08, 0x0D, 0x55, 0x55, 0x5B, 0x2A, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x02, 0x9E};
<------- headder ----> <-- type to from type-> <len> <------------------------------ data ----------------------------------------> <checksum>
*/
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<length; i += nwrite) {
nwrite = write(fd, packet + i, length - i);
if (nwrite < 0)
logMessage(LOG_ERR, "write to serial port failed\n");
}
if ( getLogLevel() >= 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

View File

@ -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);

View File

@ -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);

View File

@ -22,6 +22,9 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#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;
}

View File

@ -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;

View File

@ -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_

View File

@ -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;
}

View File

@ -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

Binary file not shown.

Binary file not shown.

View File

@ -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.

BIN
tmp.rs Normal file

Binary file not shown.

View File

@ -1,4 +1,4 @@
#define AQUALINKD_NAME "Aqualink Daemon"
#define AQUALINKD_VERSION "1.3.7"
#define AQUALINKD_VERSION "1.3.8"