Initial import.

This commit is contained in:
Martin Preuss
2023-01-16 23:12:09 +01:00
commit 112e15e41b
206 changed files with 286976 additions and 0 deletions

76
aqhome/0BUILD Normal file
View File

@@ -0,0 +1,76 @@
<?xml?>
<gwbuild>
<target type="InstallLibrary" name="aqhome"
so_current="$(project_so_current)"
so_age="$(project_so_age)"
so_revision="$(project_so_revision)"
install="$(libdir)" >
<includes type="c" >
$(gwenhywfar_cflags)
-I$(topsrcdir)
-I$(topbuilddir)
</includes>
<includes type="tm2" >
--include=$(builddir)
--include=$(srcdir)
</includes>
<define name="BUILDING_AQHOME" />
<setVar name="local/cflags">$(visibility_cflags)</setVar>
<setVar name="tm2flags" >
--api=AQHOME_API
</setVar>
<setVar name="local/typefiles" >
</setVar>
<setVar name="local/built_sources" >
</setVar>
<setVar name="local/built_headers_pub">
</setVar>
<setVar name="local/built_headers_priv" >
</setVar>
<headers dist="true" >
serial.h
serial_p.h
</headers>
<sources>
$(local/typefiles)
serial.c
</sources>
<useTargets>
</useTargets>
<libraries>
$(gwenhywfar_libs)
</libraries>
<subdirs>
</subdirs>
<extradist>
</extradist>
</target>
</gwbuild>

378
aqhome/serial.c Normal file
View File

@@ -0,0 +1,378 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "aqhome/serial_p.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/debug.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
int _attnLow(AQH_SERIAL *sr);
int _attnHigh(AQH_SERIAL *sr);
int _readForced(AQH_SERIAL *sr, uint8_t *buf, int len);
int _writeForced(AQH_SERIAL *sr, const uint8_t *buf, uint8_t len);
int _check(const uint8_t *ptr, uint8_t len);
uint8_t _calcChecksum(const uint8_t *ptr, uint8_t len);
AQH_SERIAL *AQH_Serial_new(const char *deviceName, uint8_t addr)
{
AQH_SERIAL *sr;
GWEN_NEW_OBJECT(AQH_SERIAL, sr);
sr->deviceName=deviceName?strdup(deviceName):NULL;
sr->address=addr;
sr->fd=-1;
return sr;
}
void AQH_Serial_free(AQH_SERIAL *sr)
{
if (sr) {
free(sr->deviceName);
GWEN_FREE_OBJECT(sr);
}
}
int AQH_Serial_Open(AQH_SERIAL *sr)
{
int fd;
int status;
int i;
struct termios options;
int rv;
fd=open(sr->deviceName,O_RDWR | O_NOCTTY );
if (fd<0) {
DBG_ERROR(NULL, "Error on open(%s): %s (%d)", sr->deviceName, strerror(errno), errno);
return GWEN_ERROR_IO;
}
rv=tcgetattr(fd, &options);
if (rv<0) {
DBG_ERROR(NULL, "Error on tcgetattr(%s): %s (%d)", sr->deviceName, strerror(errno), errno);
return GWEN_ERROR_IO;
}
rv=cfsetispeed(&options, B19200);
if (rv<0) {
DBG_ERROR(NULL, "Error on cfsetispeed(%s): %s (%d)", sr->deviceName, strerror(errno), errno);
return GWEN_ERROR_IO;
}
rv=cfsetospeed(&options, B19200);
if (rv<0) {
DBG_ERROR(NULL, "Error on cfsetospeed(%s): %s (%d)", sr->deviceName, strerror(errno), errno);
return GWEN_ERROR_IO;
}
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag &= ~CRTSCTS; /* disable HW flow control */
options.c_iflag &= ~(IXON | IXOFF | IXANY); /* disable SW flow control */
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* raw input */
rv=tcsetattr(fd, TCSANOW, &options);
if (rv<0) {
DBG_ERROR(NULL, "Error on tcsetattr(%s): %s (%d)", sr->deviceName, strerror(errno), errno);
return GWEN_ERROR_IO;
}
sr->fd=fd;
return 0;
}
void AQH_Serial_Close(AQH_SERIAL *sr)
{
if (sr->fd>=0) {
close (sr->fd);
sr->fd=-1;
}
}
int AQH_Serial_Recv(AQH_SERIAL *sr, uint8_t *buf, int len)
{
int rv;
uint8_t *bufSaved;
int bytesReceived=0;
int msgLen;
bufSaved=buf;
/* destination, msg length */
rv=_readForced(sr, buf, 2);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
msgLen=buf[1]+1; /* add one byte for XOR checksum */
buf+=2;
/* read message and XOR byte */
rv=_readForced(sr, buf, msgLen);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
buf+=msgLen;
bytesReceived=msgLen+3;
rv=_check(bufSaved, bytesReceived);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
return bytesReceived;
}
int AQH_Serial_Send(AQH_SERIAL *sr, const uint8_t *ptr, uint8_t len)
{
int rv;
rv=_check(ptr, len);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=_attnLow(sr);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
usleep(10);
rv=_writeForced(sr, ptr, len);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
_attnHigh(sr);
return rv;
}
_attnHigh(sr);
return 0;
}
int AQH_Serial_SendPacket(AQH_SERIAL *sr, uint8_t destAddr, const uint8_t *ptr, uint8_t len)
{
int rv;
uint8_t x=0;
rv=_attnLow(sr);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
usleep(10);
/* send dest address */
rv=_writeForced(sr, &destAddr, 1);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
_attnHigh(sr);
return rv;
}
x^=destAddr;
/* send msg len */
rv=_writeForced(sr, &len, 1);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
_attnHigh(sr);
return rv;
}
x^=len;
/* send message */
rv=_writeForced(sr, ptr, len);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
_attnHigh(sr);
return rv;
}
x^=_calcChecksum(ptr, len);
/* send XOR checksum */
rv=_writeForced(sr, &x, 1);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
_attnHigh(sr);
return rv;
}
_attnHigh(sr);
return 0;
}
int _attnLow(AQH_SERIAL *sr)
{
int status;
int rv;
rv=ioctl(sr->fd, TIOCMGET, &status); /* GET the State of MODEM bits in Status */
if (rv<0) {
DBG_ERROR(NULL, "Error on ioctl(%s): %s (%d)", sr->deviceName, strerror(errno), errno);
return GWEN_ERROR_IO;
}
status |= TIOCM_DTR; /* clear the DTR pin (cave: signals inverted!) */
rv=ioctl(sr->fd, TIOCMSET, &status);
if (rv<0) {
DBG_ERROR(NULL, "Error on ioctl(%s): %s (%d)", sr->deviceName, strerror(errno), errno);
return GWEN_ERROR_IO;
}
return 0;
}
int _attnHigh(AQH_SERIAL *sr)
{
int status;
int rv;
rv=ioctl(sr->fd, TIOCMGET, &status);
if (rv<0) {
DBG_ERROR(NULL, "Error on ioctl(%s): %s (%d)", sr->deviceName, strerror(errno), errno);
return GWEN_ERROR_IO;
}
status |= TIOCM_DTR; /* Set the DTR pin */
status &= ~ TIOCM_DTR; /* clear the DTR pin (cave: signals inverted!) */
rv=ioctl(sr->fd, TIOCMSET, &status);
if (rv<0) {
DBG_ERROR(NULL, "Error on ioctl(%s): %s (%d)", sr->deviceName, strerror(errno), errno);
return GWEN_ERROR_IO;
}
return 0;
}
int _readForced(AQH_SERIAL *sr, uint8_t *buf, int len)
{
while(len>0) {
int rv;
rv=(int) read(sr->fd, buf, len);
if (rv==0) {
DBG_ERROR(NULL, "EOF met on read(%s)", sr->deviceName);
return GWEN_ERROR_IO;
}
else if (rv<0) {
if (errno!=EINTR) {
DBG_ERROR(NULL, "Error on read(%s): %s (%d)", sr->deviceName, strerror(errno), errno);
return GWEN_ERROR_IO;
}
}
else {
len-=rv;
buf+=rv;
}
} /* while */
return 0;
}
int _writeForced(AQH_SERIAL *sr, const uint8_t *buf, uint8_t len)
{
while(len>0) {
int rv;
rv=(int) write(sr->fd, buf, len);
if (rv<0) {
if (errno!=EINTR) {
DBG_ERROR(NULL, "Error on write(%s): %s (%d)", sr->deviceName, strerror(errno), errno);
return GWEN_ERROR_IO;
}
}
else {
len-=rv;
buf+=rv;
}
} /* while */
return 0;
}
int _check(const uint8_t *ptr, uint8_t len)
{
int i;
uint8_t x=0;
for (i=0; i<len; i++, ptr++) {
x^=*ptr;
}
if (x) {
DBG_ERROR(NULL, "Bad checksum");
return GWEN_ERROR_GENERIC;
}
return 0;
}
uint8_t _calcChecksum(const uint8_t *ptr, uint8_t len)
{
int i;
uint8_t x=0;
for (i=0; i<len; i++, ptr++) {
x^=*ptr;
}
return x;
}

45
aqhome/serial.h Normal file
View File

@@ -0,0 +1,45 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQH_SERIAL_H
#define AQH_SERIAL_H
#include <gwenhywfar/buffer.h>
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct AQH_SERIAL AQH_SERIAL;
AQH_SERIAL *AQH_Serial_new(const char *deviceName, uint8_t addr);
void AQH_Serial_free(AQH_SERIAL *sr);
uint8_t AQH_Serial_GetAddress(const AQH_SERIAL *sr);
int AQH_Serial_Open(AQH_SERIAL *sr);
void AQH_Serial_Close(AQH_SERIAL *sr);
int AQH_Serial_Recv(AQH_SERIAL *sr, uint8_t *buf, int len);
int AQH_Serial_Send(AQH_SERIAL *sr, const uint8_t *ptr, uint8_t len);
int AQH_Serial_SendPacket(AQH_SERIAL *sr, uint8_t destAddr, const uint8_t *ptr, uint8_t len);
#ifdef __cplusplus
}
#endif
#endif

25
aqhome/serial_p.h Normal file
View File

@@ -0,0 +1,25 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQH_SERIAL_P_H
#define AQH_SERIAL_P_H
#include "aqhome/serial.h"
#include <inttypes.h>
struct AQH_SERIAL {
char *deviceName;
int fd;
uint8_t address;
};
#endif

104
aqhome/sertest.c Normal file
View File

@@ -0,0 +1,104 @@
#include <stdio.h>
#include <fcntl.h> /* File Control Definitions */
#include <termios.h> /* POSIX Terminal Control Definitions */
#include <unistd.h> /* UNIX Standard Definitions */
#include <errno.h> /* ERROR Number Definitions */
#include <sys/ioctl.h> /* ioctl() */
#include <ctype.h>
void testSend(int fd);
int main(void)
{
int fd; /*File Descriptor*/
int status;
int i;
struct termios options;
fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY ); //Opening the serial port
tcgetattr(fd, &options);
cfsetispeed(&options, B19200);
cfsetospeed(&options, B19200);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag &= ~CRTSCTS; /* disable HW flow control */
options.c_iflag &= ~(IXON | IXOFF | IXANY); /* disable SW flow control */
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* raw input */
tcsetattr(fd, TCSANOW, &options);
for (i=0;; i++) {
char r;
testSend(fd);
r=getchar(); //To view the change in status pins before closing the port
if (r=='q' || r=='Q')
break;
}
close(fd);
return 0;
}
void testSend(int fd)
{
int status;
const unsigned char bufOut[2]="B";
unsigned char bufIn[256];
ssize_t len;
ioctl(fd,TIOCMGET,&status); /* GET the State of MODEM bits in Status */
status |= TIOCM_DTR; // Set the DTR pin
ioctl(fd, TIOCMSET, &status);
usleep(10);
write(fd, bufOut, 1);
usleep(10);
ioctl(fd,TIOCMGET,&status); /* GET the State of MODEM bits in Status */
status &= ~ TIOCM_DTR; // Set the DTR pin HIGH (cave: signals inverted!)
ioctl(fd, TIOCMSET, &status);
#if 1
len=read(fd, bufIn, sizeof(bufIn)-1);
if (len<1) {
fprintf(stderr, "ERROR on read\n");
}
else {
ssize_t i;
fprintf(stderr, "Received: ");
for(i=0; i<len; i++) {
fprintf(stderr, "%02x", bufIn[i]);
}
fprintf(stderr, " ");
for(i=0; i<len; i++) {
char j;
j=bufIn[i];
if (iscntrl(j))
j='?';
fprintf(stderr, "%c", j);
}
fprintf(stderr, "\n");
}
#endif
}