/*
* 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
#include
#include
#include
#include "aq_serial.h"
#include "utils.h"
#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-5 < size; i++) {
//printf("added 0x%02hhx at position %d\n",packet_buffer[i-4],i);
if (i==6) {
// Replace source
//packet[i] = 0x00;
// Don't replace source
packet[i] = packet_buffer[i-5];
} else if (i==9) {
// Replace length
//packet[i] = 0xFF;
packet[i] = (unsigned char)size-5;
} else {
packet[i] = packet_buffer[i-5];
}
//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);
}
void send_jandy_command(int fd, unsigned char *packet_buffer, int size)
{
unsigned char packet[AQ_MAXPKTLEN];
int i=0;
packet[0] = NUL;
packet[1] = DLE;
packet[2] = STX;
for (i=3; i-3 < size; i++) {
//printf("added 0x%02hhx at position %d\n",packet_buffer[i-2],i);
packet[i] = packet_buffer[i-3];
}
packet[++i] = DLE;
packet[++i] = ETX;
packet[++i] = NUL;
packet[i-3] = generate_checksum(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_jandy_command(fd, &packet_buffer[1], size-1);
return;
}
if (packet_buffer[0] == PCOL_PENTAIR) {
//logMessage(LOG_ERR, "Only Jandy protocol supported at present!\n");
send_pentair_command(fd, &packet_buffer[1], size-1);
return;
}
}
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);
logMessage(LOG_DEBUG_SERIAL, "Serial send %d bytes\n",length-2);
logPacket(&packet[1], length-2);
}
}
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;
}
if ( getLogLevel() >= LOG_DEBUG_SERIAL) {
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
static struct termios _oldtio;
//static struct aqconfig *_config_parameters;
//static struct aqconfig *_aqualink_config;
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;
}
void log_packet(int level, char *init_str, unsigned char* packet, int length)
{
if ( getLogLevel() < level) {
//logMessage(LOG_INFO, "Send '0x%02hhx'|'0x%02hhx' to controller\n", packet[5] ,packet[6]);
return;
}
int cnt;
int i;
char buff[MAXLEN * 2];
cnt = sprintf(buff, "%s", init_str);
cnt += sprintf(buff+cnt, " | %8.8s",getProtocolType(packet)==JANDY?"Jandy":"Pentair");
cnt += sprintf(buff+cnt, " | HEX: ");
//printHex(packet_buffer, packet_length);
for (i=0;i= LOG_DEBUG_SERIAL) {
char buf[30];
sprintf(buf, "Sent %8.8s ", get_packet_type(ackPacket+1 , length));
log_packet(LOG_DEBUG_SERIAL, buf, ackPacket, length);
}
}
void send_messaged(int fd, unsigned char destination, char *message)
{
const unsigned int length = 24;
unsigned int i;
//unsigned char ackPacket[] = { NUL, DLE, STX, DEV_MASTER, CMD_ACK, NUL, NUL, 0x13, DLE, ETX, NUL };
unsigned char msgPacket[] = { DLE,STX,DEV_MASTER,CMD_MSG,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,NUL,DLE,ETX };
//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.
msgPacket[2] = destination;
for (i=0; i < strlen(message) && i < AQ_MSGLEN; i++)
msgPacket[4+i] = message[i];
msgPacket[length-3] = generate_checksum(msgPacket, length-1);
#ifdef BLOCKING_MODE
write(fd, msgPacket, length);
#else
int nwrite;
for (i=0; i 20) {
logMessage(LOG_WARNING, "Serial read timeout\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
retry++;
delay(10);
} else if (bytesRead == 1) {
//printf("Byte 0x%02hhx\n",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 && packetStarted == FALSE) {
packetStarted = TRUE;
} else if (byte == ETX && packetStarted == TRUE) {
endOfPacket = TRUE;
}
} else if (packetStarted) {
packet[index] = byte;
index++;
} else if (byte == DLE && packetStarted == FALSE) {
packet[index] = byte;
}
// // reset index incase we have EOP before start
if (packetStarted == FALSE)
index=0;
if (byte == DLE) {
lastByteDLE = TRUE;
} else {
lastByteDLE = FALSE;
}
} 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) {
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 (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 && packetStarted) { //NSF. Sometimes we get END sequence only, so just ignore.
//} else if (index < AQ_MINPKTLEN) { //NSF. Sometimes we get END sequence only, so just ignore.
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);
// Return the packet length.
return index;
}
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;
}
/*
bool check_pentair_checksum_old(unsigned char* packet, int length)
{
int i, sum, n;
n = packet[8] + 9;
sum = 0;
for (i = 3; i < n; i++) {
sum += (int) packet[i];
}
if (sum == (packet[length-2] * 256 + packet[length-1]))
return true;
return false;
}
*/
int _get_packet(int fd, unsigned char* packet, bool rawlog);
int get_packet_new_lograw(int fd, unsigned char* packet)
{
return _get_packet(fd, packet, true);
}
int get_packet_new(int fd, unsigned char* packet)
{
return _get_packet(fd, packet, false);
}
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);
return 0;
}
retry++;
delay(10);
} 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 // PLAYBACK_MODE
#include
FILE *_fp;
bool check_pentair_checksum(unsigned char* packet, int length)
{
int i, sum, n;
n = packet[8] + 9;
sum = 0;
//printf("Pentair ");
for (i = 3; i < n; i++) {
sum += (int) packet[i];
//printf("+ (0x%02hhx) %d = %d ",packet[i],(int)packet[i],sum);
}
//printf("\nPentair checksum %d = %d (0x%02hhx) (0x%02hhx)\n",sum, (packet[length-1] * 256 + packet[length]),packet[length-1],packet[length]);
if (sum == (packet[length-1] * 256 + packet[length]))
return true;
return false;
}
int init_serial_port(char* file)
{
_fp = fopen ( file, "r" );
if ( _fp == NULL )
{
perror ( file ); /* why didn't the file open? */
return -1;
}
return 0;
}
void close_serial_port(int fd)
{
fclose(_fp);
}
int get_packet_new(int fd, unsigned char* packet_buffer)
{
return get_packet(fd, packet_buffer);
}
int get_packet(int fd, unsigned char* packet_buffer)
{
int packet_length = 0;
char line[256];
char hex[6];
int i;
if ( fgets ( line, sizeof line, _fp ) != NULL ) /* read a line */
{
packet_length=0;
for (i=0; i < strlen(line); i=i+5)
{
strncpy(hex, &line[i], 4);
hex[5] = '\0';
packet_buffer[packet_length] = (int)strtol(hex, NULL, 16);
//printf("%s = 0x%02hhx = %c\n", hex, packet_buffer[packet_length], packet_buffer[packet_length]);
packet_length++;
}
packet_length--;
logMessage(LOG_DEBUG_SERIAL, "PLAYBACK read %d bytes\n",packet_length);
//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 );
if (getProtocolType(packet_buffer)==JANDY) {
if (generate_checksum(packet_buffer, packet_length) != packet_buffer[packet_length-3]) {
logPacketError(packet_buffer, packet_length);
logMessage(LOG_WARNING, "Serial read bad Jandy checksum, ignoring\n");
} else
logPacket(packet_buffer, packet_length);
} else {
//check_pentair_checksum(packet_buffer, packet_length);
//check_pentair_checksum(packet_buffer, packet_length-1);
//check_pentair_checksum(packet_buffer, packet_length+1);
if (check_pentair_checksum(packet_buffer, packet_length-1) != true) {
logPacketError(packet_buffer, packet_length);
logMessage(LOG_WARNING, "Serial read bad Pentair checksum, ignoring\n");
} else
logPacket(packet_buffer, packet_length);
}
return packet_length;
}
return 0;
}
void send_extended_ack(int fd, unsigned char ack_type, unsigned char command)
{}
void send_ack(int fd, unsigned char command)
{}
void send_messaged(int fd, unsigned char destination, char *message)
{}
void send_command(int fd, unsigned char destination, unsigned char b1, unsigned char b2, unsigned char b3)
{}
#endif // PLAYBACK_MODE
// Reads the bytes of the next incoming packet, and
// returns when a good packet is available in packet
// fd: the file descriptor to read the bytes from
// packet: the unsigned char buffer to store the bytes in
// returns the length of the packet
int get_packet_old(int fd, unsigned char* packet)
{
unsigned char byte;
int bytesRead;
int index = 0;
int endOfPacket = FALSE;
int packetStarted = FALSE;
int foundDLE = FALSE;
bool started = FALSE;
int retry=0;
while (!endOfPacket) {
//printf("Read loop %d\n",++i);
bytesRead = read(fd, &byte, 1);
if (bytesRead < 0 && errno == EAGAIN && started == 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);
return 0;
}
retry++;
delay(10);
} else if (bytesRead == 1) {
started = TRUE;
//if (bytesRead == 1) {
if (byte == DLE) {
// Found a DLE byte. Set the flag, and record the byte.
foundDLE = TRUE;
packet[index] = byte;
}
else if (byte == STX && foundDLE == TRUE) {
// Found the DLE STX byte sequence. Start of packet detected.
// Reset the DLE flag, and record the byte.
foundDLE = FALSE;
packetStarted = TRUE;
packet[index] = byte;
}
else if (byte == NUL && foundDLE == TRUE) {
// Found the DLE NUL byte sequence. Detected a delimited data byte.
// Reset the DLE flag, and decrement the packet index to offset the
// index increment at the end of the loop. The delimiter, [NUL], byte
// is not recorded.
foundDLE = FALSE;
//trimmed = true;
index--;
}
else if (byte == ETX && foundDLE == TRUE) {
// Found the DLE ETX byte sequence. End of packet detected.
// Reset the DLE flag, set the end of packet flag, and record
// the byte.
foundDLE = FALSE;
packetStarted = FALSE;
endOfPacket = TRUE;
packet[index] = byte;
}
else if (packetStarted == TRUE) {
// Found a data byte. Reset the DLE flag just in case it is set
// to prevent anomalous detections, and record the byte.
foundDLE = FALSE;
packet[index] = byte;
}
else {
// Found an extraneous byte. Probably a NUL between packets.
// Ignore it, and decrement the packet index to offset the
// index increment at the end of the loop.
index--;
}
// Finished processing the byte. Increment the packet index for the
// next byte.
index++;
// Break out of the loop if we exceed maximum packet
// length.
if (index >= AQ_MAXPKTLEN) {
break;
}
}
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);
}
}
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) {
logMessage(LOG_WARNING, "Serial read too small\n");
log_packet(LOG_WARNING, "Bad receive packet ", packet, index);
return 0;
}
//if (_config_parameters.debug_RSProtocol_packets || getLogLevel() >= LOG_DEBUG_SERIAL)
// logPacket(packet_buffer, packet_length);
logMessage(LOG_DEBUG_SERIAL, "Serial read %d bytes\n",index);
// Return the packet length.
return index;
}
#endif // USE_OLD