Initial import.
This commit is contained in:
76
aqhome/0BUILD
Normal file
76
aqhome/0BUILD
Normal 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
378
aqhome/serial.c
Normal 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
45
aqhome/serial.h
Normal 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
25
aqhome/serial_p.h
Normal 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
104
aqhome/sertest.c
Normal 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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user