first commit
This commit is contained in:
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Raspberry PI / Zero AddOn Board specially for Ham Radio Applications
|
||||
* ====================================================================
|
||||
* Author: DJ0ABR
|
||||
*
|
||||
* (c) DJ0ABR
|
||||
* www.dj0abr.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
kmhelper.cpp
|
||||
===========
|
||||
|
||||
useful functions
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../qo100trx.h"
|
||||
#include <pwd.h>
|
||||
|
||||
int keeprunning = 1; // set to 0 at program end to exit all processes
|
||||
char configfile[512] = {0};
|
||||
|
||||
// check if it is already running
|
||||
int isRunning(char *prgname)
|
||||
{
|
||||
int num = 0;
|
||||
char s[256];
|
||||
sprintf(s,"ps -e | grep %s",prgname);
|
||||
|
||||
FILE *fp = popen(s,"r");
|
||||
if(fp)
|
||||
{
|
||||
// gets the output of the system command
|
||||
while (fgets(s, sizeof(s)-1, fp) != NULL)
|
||||
{
|
||||
if(strstr(s,prgname) && !strstr(s,"grep"))
|
||||
{
|
||||
if(++num == 2)
|
||||
{
|
||||
printf("%s is already running, do not start twice !\n",prgname);
|
||||
pclose(fp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
pclose(fp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void (*sigfunc)();
|
||||
|
||||
// signal handler
|
||||
void sighandler(int signum)
|
||||
{
|
||||
//printf("\n\nprogram stopped by signal\n");
|
||||
|
||||
(*sigfunc)();
|
||||
}
|
||||
|
||||
void install_signal_handler(void (*signalfunction)())
|
||||
{
|
||||
sigfunc = signalfunction;
|
||||
// signal handler, mainly used if the user presses Ctrl-C
|
||||
struct sigaction sigact;
|
||||
sigact.sa_handler = sighandler;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
sigaction(SIGINT, &sigact, NULL);
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGQUIT, &sigact, NULL);
|
||||
sigaction(SIGABRT, &sigact, NULL); // assert() error
|
||||
|
||||
//sigaction(SIGSEGV, &sigact, NULL);
|
||||
|
||||
// switch off signal 13 (broken pipe)
|
||||
// instead handle the return value of the write or send function
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
|
||||
void getParameters(int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "c:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'c':
|
||||
// specify config file name
|
||||
if(optarg && strlen(optarg) > 2 && strlen(optarg) < (sizeof(configfile)-1))
|
||||
{
|
||||
strcpy(configfile,optarg);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("invalid Config File Parameter [-c Configfilename]: %s\n", optarg);
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run external program and return it's output
|
||||
char *runProgram(char *parameter, int maxlen)
|
||||
{
|
||||
//printf("run:<%s>\n",parameter);
|
||||
FILE *fp = popen(parameter,"r");
|
||||
if(fp)
|
||||
{
|
||||
*parameter = 0;
|
||||
while (fgets(parameter+strlen(parameter), maxlen-1-strlen(parameter), fp) != NULL)
|
||||
{
|
||||
//printf("returns:<%s>\n", parameter);
|
||||
}
|
||||
pclose(fp);
|
||||
return parameter;
|
||||
}
|
||||
else
|
||||
printf("ERROR: cannot run: %s\n",parameter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void showbitstring(char* title, uint8_t* data, int totallen, int anz)
|
||||
{
|
||||
printf("%s. len %d: ", title, totallen);
|
||||
for (int i = 0; i < anz; i++)
|
||||
printf("%01X ", data[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void showbytestring(char *title, uint8_t *data, int totallen, int anz)
|
||||
{
|
||||
printf("%s. len % 4d: ",title, totallen);
|
||||
for(int i=0; i<anz; i++)
|
||||
printf("%02X ",data[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void showbytestring16(char *title, uint16_t *data, int anz)
|
||||
{
|
||||
printf("%s. len %d: ",title,anz);
|
||||
for(int i=0; i<anz; i++)
|
||||
printf("%04X ",data[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void showbytestring32(char* title, uint32_t* data, int anz)
|
||||
{
|
||||
printf("%s. len %d: ", title, anz);
|
||||
for (int i = 0; i < anz; i++)
|
||||
printf("%08X ", data[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void showbytestringf(char* title, float* data, int totallen, int anz)
|
||||
{
|
||||
printf("%s. len %d: ", title, totallen);
|
||||
for (int i = 0; i < anz; i++)
|
||||
printf("%7.4f ", data[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// get own IP adress
|
||||
char* ownIP()
|
||||
{
|
||||
static char ip[20] = { 0 };
|
||||
|
||||
struct ifaddrs* ifaddr, * ifa;
|
||||
int s;
|
||||
char host[NI_MAXHOST];
|
||||
|
||||
if (getifaddrs(&ifaddr) == -1)
|
||||
{
|
||||
printf("cannot read own IP address, getifaddrs faield. Check Networking\n");
|
||||
return ip;
|
||||
}
|
||||
|
||||
|
||||
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
|
||||
{
|
||||
if (ifa->ifa_addr == NULL)
|
||||
continue;
|
||||
|
||||
s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
|
||||
|
||||
if (ifa->ifa_addr->sa_family == AF_INET)
|
||||
{
|
||||
if (s != 0)
|
||||
{
|
||||
printf("getnameinfo() failed: %s\n", gai_strerror(s));
|
||||
printf("cannot read own IP address, getnameinfo failed: %s. Check Networking\n", gai_strerror(s));
|
||||
break;
|
||||
}
|
||||
if (strncmp(host, "127", 3) != 0)
|
||||
{
|
||||
strcpy(ip, host);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
return ip;
|
||||
}
|
||||
|
||||
char* cleanStr(char *s)
|
||||
{
|
||||
if(s[0] > ' ')
|
||||
{
|
||||
// remove trailing crlf
|
||||
for(size_t j=0; j<strlen(s); j++)
|
||||
if(s[j] == '\n' || s[j] == '\r') s[j] = 0;
|
||||
return s; // nothing to do
|
||||
}
|
||||
|
||||
for(size_t i=0; i<strlen(s); i++)
|
||||
{
|
||||
if(s[i] >= '0')
|
||||
{
|
||||
// i is on first character
|
||||
memmove(s,s+i,strlen(s)-i);
|
||||
s[strlen(s)-i] = 0;
|
||||
// remove trailing crlf
|
||||
for(size_t j=0; j<strlen(s); j++)
|
||||
if(s[j] == 'n' || s[j] == '\r') s[j] = 0;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return NULL; // no text found in string
|
||||
}
|
||||
|
||||
char *getword(char *s, int idx)
|
||||
{
|
||||
if(idx == 0)
|
||||
{
|
||||
for(size_t i=0; i<strlen(s); i++)
|
||||
{
|
||||
if(s[i] < '0')
|
||||
{
|
||||
s[i] = 0;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(size_t j=0; j<strlen(s); j++)
|
||||
{
|
||||
if(s[j] > ' ')
|
||||
{
|
||||
char *start = s+j;
|
||||
for(size_t k=0; k<strlen(start); k++)
|
||||
{
|
||||
if(start[k] == ' ' || start[k] == '\r' || start[k] == '\n')
|
||||
{
|
||||
start[k] = 0;
|
||||
return start;
|
||||
}
|
||||
}
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// read the value of an element from the config file
|
||||
// Format:
|
||||
// # ... comment
|
||||
// ElementName-space-ElementValue
|
||||
// the returned value is a static string and must be copied somewhere else
|
||||
// before this function can be called again
|
||||
char *getConfigElement(char *elemname)
|
||||
{
|
||||
if(strlen(configfile) < 2) return NULL;
|
||||
|
||||
static char s[501];
|
||||
int found = 0;
|
||||
char fn[1024];
|
||||
|
||||
if(strlen(configfile) > 512)
|
||||
{
|
||||
printf("config file path+name too long: %s\n",configfile);
|
||||
exit(0);
|
||||
}
|
||||
strcpy(fn,configfile);
|
||||
|
||||
if(fn[0] == '~')
|
||||
{
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
sprintf(fn,"%s%s",homedir,configfile+1);
|
||||
}
|
||||
|
||||
//printf("read Configuration file %s\n",fn);
|
||||
FILE *fr = fopen(fn,"rb");
|
||||
if(!fr)
|
||||
{
|
||||
printf("!!! Configuration file %s not found !!!\n",fn);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
if(fgets(s,500,fr) == NULL) break;
|
||||
// remove leading SPC or TAB
|
||||
if(cleanStr(s) == 0) continue;
|
||||
// check if its a comment
|
||||
if(s[0] == '#') continue;
|
||||
// get word on index
|
||||
char *p = getword(s,0);
|
||||
if(!p) break;
|
||||
if(strcmp(p, elemname) == 0)
|
||||
{
|
||||
char val[500];
|
||||
if(*(s+strlen(p)+1) == 0) continue;
|
||||
p = getword(s+strlen(p)+1,1);
|
||||
if(!p) break;
|
||||
// replace , with .
|
||||
char *pkomma = strchr(p,',');
|
||||
if(pkomma) *pkomma = '.';
|
||||
strcpy(val,p);
|
||||
strcpy(s,val);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fclose(fr);
|
||||
if(found == 0) return NULL;
|
||||
return s;
|
||||
}
|
||||
|
||||
void getConfigElement_double(char *elemname, double *pv, double multiplier)
|
||||
{
|
||||
char *p = getConfigElement(elemname);
|
||||
if(p) *pv = atof(p) * multiplier;
|
||||
}
|
||||
|
||||
void getConfigElement_longlong(char *elemname, long long *pv, double multiplier)
|
||||
{
|
||||
char *p = getConfigElement(elemname);
|
||||
if(p) *pv = (long long)(atof(p) * multiplier);
|
||||
}
|
||||
|
||||
void getConfigElement_int(char *elemname, int *pv, double multiplier)
|
||||
{
|
||||
char *p = getConfigElement(elemname);
|
||||
if(p) *pv = (int)(atof(p) * multiplier);
|
||||
}
|
||||
|
||||
float measure_samplerate(int id, int samp, int prt)
|
||||
{
|
||||
static unsigned long lastus[10];
|
||||
static unsigned long samples[10];
|
||||
static int f[10];
|
||||
static int cnt[10];
|
||||
static int first=1;
|
||||
|
||||
if(first)
|
||||
{
|
||||
first = 0;
|
||||
for(int i=0; i<10; i++)
|
||||
{
|
||||
f[i] = 1;
|
||||
cnt[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// measure sample rate
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
if(f[id])
|
||||
{
|
||||
f[id] = 0;
|
||||
lastus[id] = tv.tv_sec * 1000000 + tv.tv_usec;
|
||||
samples[id] = samp;
|
||||
}
|
||||
samples[id] += samp;
|
||||
unsigned long tnow = tv.tv_sec * 1000000 + tv.tv_usec;
|
||||
|
||||
float sr = 0;
|
||||
if(++(cnt[id]) >= prt)
|
||||
{
|
||||
cnt[id] = 0;
|
||||
sr = (samples[id]*1e6)/(tnow - lastus[id]);
|
||||
printf("%d: %.6f\n",id,sr/1e6);
|
||||
}
|
||||
return sr;
|
||||
}
|
||||
|
||||
int measure_maxval(double v, int anz)
|
||||
{
|
||||
static double max = - 99999999;
|
||||
static int cnt = 0;
|
||||
|
||||
v = fabs(v);
|
||||
if(v > max)
|
||||
{
|
||||
max = v;
|
||||
//printf("maxval: %f\n",max);
|
||||
}
|
||||
|
||||
if(++cnt >= anz)
|
||||
{
|
||||
printf("maxval: %f\n",max);
|
||||
max = - 99999999;
|
||||
cnt = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <netdb.h>
|
||||
|
||||
int isRunning(char *prgname);
|
||||
void install_signal_handler(void (*signalfunction)());
|
||||
void showbitstring(char* title, uint8_t* data, int totallen, int anz);
|
||||
void showbytestring(char *title, uint8_t *data, int totallen, int anz);
|
||||
void showbytestring16(char *title, uint16_t *data, int anz);
|
||||
void showbytestring32(char* title, uint32_t* data, int anz);
|
||||
void showbytestringf(char* title, float* data, int totallen, int anz);
|
||||
char* ownIP();
|
||||
char *getConfigElement(char *elemname);
|
||||
void getConfigElement_double(char *elemname, double *pv, double multiplier);
|
||||
void getConfigElement_longlong(char *elemname, long long *pv, double multiplier);
|
||||
void getConfigElement_int(char *elemname, int *pv, double multiplier);
|
||||
float measure_samplerate(int id, int samp, int prt);
|
||||
int measure_maxval(double v, int anz);
|
||||
char *runProgram(char *parameter, int maxlen);
|
||||
|
||||
extern int keeprunning;
|
||||
Binary file not shown.
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Raspberry PI / Zero AddOn Board specially for Ham Radio Applications
|
||||
* ====================================================================
|
||||
* Author: DJ0ABR
|
||||
*
|
||||
* (c) DJ0ABR
|
||||
* www.dj0abr.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* universal thread safe fifo, used by many drivers and applications
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include "kmfifo.h"
|
||||
|
||||
|
||||
FIFOOBJ fifo[MAXFIFOS];
|
||||
int fifonum = 0;
|
||||
|
||||
#define LOCK(id) pthread_mutex_lock(&fifo[id].crit_sec)
|
||||
#define UNLOCK(id) pthread_mutex_unlock(&fifo[id].crit_sec)
|
||||
|
||||
// creates a new fifo
|
||||
// maxelem_num ... max. number of elements in fifo
|
||||
// maxelem_len ... max. length of one element (shorter elements are allowed)
|
||||
// returns: ID of a fifo object, to be used for fifo functions
|
||||
int create_fifo(int maxelem_num, int maxelem_len)
|
||||
{
|
||||
// create the fifo memory and init variables
|
||||
fifo[fifonum].fifomem = malloc(maxelem_num * maxelem_len);
|
||||
fifo[fifonum].plen = (int *)malloc(maxelem_num * sizeof(int));
|
||||
fifo[fifonum].maxelemlen =maxelem_len;
|
||||
fifo[fifonum].maxelem = maxelem_num;
|
||||
fifo[fifonum].rdidx = 0;
|
||||
fifo[fifonum].wridx = 0;
|
||||
|
||||
pthread_mutex_init(&fifo[fifonum].crit_sec, NULL);
|
||||
|
||||
int id = fifonum;
|
||||
fifonum++;
|
||||
return id;
|
||||
}
|
||||
|
||||
void destroy_fifos()
|
||||
{
|
||||
for(int i=0; i<fifonum; i++)
|
||||
{
|
||||
free(fifo[fifonum].fifomem);
|
||||
free(fifo[fifonum].plen);
|
||||
if (&fifo[fifonum].crit_sec != NULL) pthread_mutex_destroy(&fifo[fifonum].crit_sec);
|
||||
}
|
||||
}
|
||||
|
||||
// write into the fifo
|
||||
// ignore data if the fifo is full
|
||||
void write_fifo(int id, uint8_t *pdata, int len)
|
||||
{
|
||||
FIFOOBJ *pfo = &fifo[id];
|
||||
|
||||
if(len > pfo->maxelemlen)
|
||||
{
|
||||
printf("element too long\n");
|
||||
return;
|
||||
}
|
||||
|
||||
LOCK(id);
|
||||
|
||||
if (((pfo->wridx + 1) % pfo->maxelem) == pfo->rdidx)
|
||||
{
|
||||
printf("cannot WRITE fifo %d full\n",id);
|
||||
UNLOCK(id);
|
||||
return;
|
||||
}
|
||||
|
||||
// insert length of new data
|
||||
*(pfo->plen) = len; // real length of the element
|
||||
|
||||
// insert new data
|
||||
void *dst = (void *)((uint8_t *)pfo->fifomem + pfo->wridx * pfo->maxelemlen);
|
||||
memcpy(dst, pdata, len);
|
||||
if(++pfo->wridx >= pfo->maxelem) pfo->wridx = 0;
|
||||
|
||||
UNLOCK(id);
|
||||
}
|
||||
|
||||
// read from the fifo
|
||||
// return: number of bytes read
|
||||
int read_fifo(int id, uint8_t* pdata, int maxlen)
|
||||
{
|
||||
FIFOOBJ *pfo = &fifo[id];
|
||||
LOCK(id);
|
||||
|
||||
if(pfo->rdidx == pfo->wridx)
|
||||
{
|
||||
// Fifo empty, no data available
|
||||
//printf("read: no data\n");
|
||||
UNLOCK(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// read length
|
||||
int len = *pfo->plen; // length of an element
|
||||
|
||||
if (len > maxlen)
|
||||
{
|
||||
printf("read_fifo: %d, pdata too small. Need:%d has:%d\n", id, len, maxlen);
|
||||
return 0; // pdata too small
|
||||
}
|
||||
|
||||
// read data
|
||||
void *src = (void *)((uint8_t *)pfo->fifomem + pfo->rdidx * pfo->maxelemlen);
|
||||
memcpy(pdata, src, len);
|
||||
if (++pfo->rdidx >= pfo->maxelem) pfo->rdidx = 0;
|
||||
|
||||
UNLOCK(id);
|
||||
return len;
|
||||
}
|
||||
|
||||
void fifo_clear(int id)
|
||||
{
|
||||
fifo[id].wridx = fifo[id].rdidx = 0;
|
||||
}
|
||||
|
||||
int fifo_freespace(int id)
|
||||
{
|
||||
int freebuf = 0;
|
||||
|
||||
LOCK(id);
|
||||
|
||||
int elemInFifo = (fifo[id].wridx + fifo[id].maxelem - fifo[id].rdidx) % fifo[id].maxelem;
|
||||
freebuf = fifo[id].maxelem - elemInFifo;
|
||||
|
||||
UNLOCK(id);
|
||||
return freebuf;
|
||||
}
|
||||
|
||||
int fifo_dataavail(int id)
|
||||
{
|
||||
LOCK(id);
|
||||
|
||||
if (fifo[id].rdidx == fifo[id].wridx)
|
||||
{
|
||||
// Fifo empty, no data available
|
||||
UNLOCK(id);
|
||||
return 0;
|
||||
}
|
||||
UNLOCK(id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fifo_usedspace(int id)
|
||||
{
|
||||
int us = fifo[id].maxelem - fifo_freespace(id);
|
||||
return us;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// max number of fifo, just a high number, never really used
|
||||
#define MAXFIFOS 200
|
||||
|
||||
typedef struct _FIFOOBJ_ {
|
||||
int maxelem;
|
||||
int maxelemlen;
|
||||
int rdidx;
|
||||
int wridx;
|
||||
void *fifomem;
|
||||
int *plen; // real length of an element
|
||||
pthread_mutex_t crit_sec;
|
||||
} FIFOOBJ;
|
||||
|
||||
int create_fifo(int elem_num, int elem_len);
|
||||
void destroy_fifos();
|
||||
void write_fifo(int id, uint8_t *pdata, int len);
|
||||
int read_fifo(int id, uint8_t* pdata, int maxlen);
|
||||
void fifo_clear(int id);
|
||||
int fifo_freespace(int id);
|
||||
int fifo_dataavail(int id);
|
||||
int fifo_usedspace(int id);
|
||||
Binary file not shown.
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Linux multithreaded timer
|
||||
* =========================
|
||||
* Author: DJ0ABR
|
||||
*
|
||||
* (c) DJ0ABR
|
||||
* www.dj0abr.de
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
* Repeatable Timer for various needs
|
||||
* ==================================
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kmtimer.h"
|
||||
|
||||
/*
|
||||
usage:
|
||||
|
||||
// this function is called every time_in_ms milliseconds
|
||||
void timerhandler_function(void)
|
||||
{
|
||||
// called every time_in_ms
|
||||
}
|
||||
|
||||
// start a new timer
|
||||
int timernum = start_timer(time_in_ms, &timerhandler_function);
|
||||
|
||||
stop_timer(timernum);
|
||||
|
||||
*/
|
||||
|
||||
|
||||
typedef struct _TIMERDEF_ {
|
||||
int to_ms; // timeout value in ms
|
||||
timer_t timerid;
|
||||
void(*timer_func_handler_pntr)(void); // this user supplied function is called on timeout
|
||||
struct itimerspec in, out;
|
||||
} TIMERDEF;
|
||||
|
||||
#define MAXTIMERS 20
|
||||
TIMERDEF timers[MAXTIMERS];
|
||||
int timernum = 0;
|
||||
|
||||
// callback function. The timer number is in val.sival_int
|
||||
void sighler (union sigval val)
|
||||
{
|
||||
int tnum = val.sival_int;
|
||||
timers[tnum].timer_func_handler_pntr();
|
||||
}
|
||||
|
||||
int start_timer(int mSec, void(*timer_func_handler)(void))
|
||||
{
|
||||
timers[timernum].timer_func_handler_pntr = timer_func_handler;
|
||||
timers[timernum].to_ms = mSec;
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init( &attr );
|
||||
|
||||
struct sched_param parm;
|
||||
parm.sched_priority = 255;
|
||||
pthread_attr_setschedparam(&attr, &parm);
|
||||
|
||||
struct sigevent sig;
|
||||
sig.sigev_notify = SIGEV_THREAD;
|
||||
sig.sigev_notify_function = sighler;
|
||||
sig.sigev_value.sival_int = timernum;
|
||||
sig.sigev_notify_attributes = &attr;
|
||||
|
||||
|
||||
int ret = timer_create(CLOCK_REALTIME, &sig, &(timers[timernum].timerid));
|
||||
if (ret == 0)
|
||||
{
|
||||
timers[timernum].in.it_value.tv_sec = mSec / 1000;
|
||||
timers[timernum].in.it_value.tv_nsec = (mSec % 1000) * 1000000;
|
||||
timers[timernum].in.it_interval.tv_sec = mSec / 1000;
|
||||
timers[timernum].in.it_interval.tv_nsec = (mSec % 1000) * 1000000;
|
||||
|
||||
ret = timer_settime(timers[timernum].timerid, 0, &timers[timernum].in, &timers[timernum].out);
|
||||
if(ret == -1)
|
||||
{
|
||||
printf("timer_settime() failed with %d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("timer_create() failed with %d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int r = timernum;
|
||||
timernum++;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void stop_timer(int timer)
|
||||
{
|
||||
timer_delete(timers[timer].timerid);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
int start_timer(int mSec, void(*timer_func_handler)(void));
|
||||
void stop_timer(int timer);
|
||||
void sleep_ms(int ms);
|
||||
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
this is an extract from kmclib (see github, dj0abr repos)
|
||||
it works on raspberry pi only
|
||||
|
||||
* Raspberry PI / Zero AddOn Board specially for Ham Radio Applications
|
||||
* ====================================================================
|
||||
* Author: DJ0ABR
|
||||
*
|
||||
* (c) DJ0ABR
|
||||
* www.dj0abr.de
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
encoder.cpp
|
||||
===========
|
||||
|
||||
function to handle rotary encoder
|
||||
|
||||
Usage:
|
||||
======
|
||||
initialize and assign ports to the encoders
|
||||
-------------------------------------------
|
||||
up to 3 encoders are supported, If not used, then assign port nunmber -1
|
||||
init_rotencoder(int portA1, int portB1, int portA2, int portB2, int portA3, int portB3)
|
||||
see gpio.h _INPUTS_ for valid port numbers
|
||||
|
||||
read encoder:
|
||||
-------------
|
||||
int getEncSteps(int idx)
|
||||
idx ... encoder number 0,1 or 2
|
||||
returns the number of steps since last read
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../qo100trx.h"
|
||||
|
||||
|
||||
int init_gpio();
|
||||
int getPort(char *port);
|
||||
|
||||
#define NUM_OF_ENCODERS 2
|
||||
|
||||
pthread_mutex_t rotenc_crit_sec;
|
||||
#define LOCK pthread_mutex_lock(&(rotenc_crit_sec))
|
||||
#define UNLOCK pthread_mutex_unlock(&(rotenc_crit_sec))
|
||||
|
||||
void *rotencproc(void *);
|
||||
|
||||
char portA[NUM_OF_ENCODERS][3] = {"fa","va"};
|
||||
char portB[NUM_OF_ENCODERS][3] = {"fb","vb"};
|
||||
|
||||
int encsteps[NUM_OF_ENCODERS];
|
||||
|
||||
pthread_t rotenc_tid;
|
||||
|
||||
// port numbers see gpio.h _INPORTS_
|
||||
// -1 if not used
|
||||
void init_rotencoder()
|
||||
{
|
||||
// use the rotary encoder on a raspberry board only
|
||||
// RASPI is passed to the Makefile as: make RASPI='-DRASPI'
|
||||
#ifndef RASPI
|
||||
return;
|
||||
#endif
|
||||
|
||||
if(init_gpio() == -1) return;
|
||||
|
||||
memset(&encsteps, 0, sizeof(int)*NUM_OF_ENCODERS);
|
||||
|
||||
int pret = pthread_create(&rotenc_tid,NULL,rotencproc, NULL);
|
||||
if(pret)
|
||||
{
|
||||
printf("rotenc process NOT started\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
int getEncSteps(int idx)
|
||||
{
|
||||
int v;
|
||||
LOCK;
|
||||
v = encsteps[idx];
|
||||
encsteps[idx] = 0;
|
||||
UNLOCK;
|
||||
return v;
|
||||
}
|
||||
|
||||
void *rotencproc(void *pdata)
|
||||
{
|
||||
pthread_detach(pthread_self());
|
||||
|
||||
printf("rotenc process started\n");
|
||||
|
||||
int aval[NUM_OF_ENCODERS];
|
||||
int bval[NUM_OF_ENCODERS];
|
||||
int oldaval[NUM_OF_ENCODERS]={0,0};
|
||||
while(keeprunning)
|
||||
{
|
||||
for(int i=0; i<NUM_OF_ENCODERS; i++)
|
||||
{
|
||||
aval[i] = getPort(portA[i]);
|
||||
bval[i] = getPort(portB[i]);
|
||||
|
||||
if(aval[i]==1 && oldaval[i]==0)
|
||||
{
|
||||
// falling edge of port A
|
||||
int dir = -1;
|
||||
if(bval[i] == 1) dir = 1;
|
||||
LOCK;
|
||||
encsteps[i] += dir;
|
||||
UNLOCK;
|
||||
}
|
||||
oldaval[i] = aval[i];
|
||||
}
|
||||
|
||||
usleep(100);
|
||||
}
|
||||
|
||||
printf("exit rotenc thread\n");
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
// 0=RX, 1=TX, 2=just released, 3=just pressed
|
||||
int test_ptt_gpio()
|
||||
{
|
||||
#ifndef RASPI
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
static int gold = -1;
|
||||
int ret = 0;
|
||||
|
||||
int ptt = getPort("p");
|
||||
|
||||
if(gold != -1)
|
||||
{
|
||||
if(ptt == 0)
|
||||
{
|
||||
// PTT is pressed
|
||||
if(gold == 0) ret = 1;
|
||||
else ret = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
// PTT is released
|
||||
if(gold == 0) ret = 2;
|
||||
else ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
gold = ptt;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 0=unmuted, 1=muted, 2=just unmuted, 3=just muted
|
||||
int test_mute_gpio()
|
||||
{
|
||||
#ifndef RASPI
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
static int gold = -1;
|
||||
int ret = 0;
|
||||
|
||||
int mute = getPort("m");
|
||||
|
||||
if(gold != -1)
|
||||
{
|
||||
if(mute == 0)
|
||||
{
|
||||
// mute is pressed
|
||||
if(gold == 0) ret = 1;
|
||||
else ret = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
// mute is released
|
||||
if(gold == 0) ret = 2;
|
||||
else ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
gold = mute;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ============= Linux GPIO interface =============
|
||||
requires packages: gpiod libgpiod-dev
|
||||
|
||||
command line interface see:
|
||||
https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/README
|
||||
|
||||
C-Functions see: /usr/include/gpiod.h
|
||||
|
||||
connect rotary encoders to these pins:
|
||||
|
||||
frequency-encoder A ... GPIO17 (Pin11)
|
||||
frequency-encoder B ... GPIO27 (Pin13)
|
||||
volume -encoder A ... GPIO4 (Pin 7)
|
||||
volume -encoder B ... GPIO22 (Pin15)
|
||||
|
||||
PTT input ... GPIO18 (Pin12)
|
||||
Mute ... GPIO23 (Pin16)
|
||||
|
||||
PTT output ... GPIO24 (Pin18)
|
||||
*/
|
||||
|
||||
#include <gpiod.h>
|
||||
|
||||
struct gpiod_chip *chip = NULL;
|
||||
struct gpiod_line *fa = NULL;
|
||||
struct gpiod_line *fb = NULL, *va = NULL, *vb = NULL, *gptt = NULL, *gmute = NULL, *pttout = NULL;
|
||||
|
||||
int init_gpio()
|
||||
{
|
||||
int ret;
|
||||
|
||||
chip= gpiod_chip_open("/dev/gpiochip0");
|
||||
if(!chip)
|
||||
{
|
||||
printf("cannot open GPIO chip\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//fa= gpiod_chip_get_info(chip,17);
|
||||
if (!fa) {
|
||||
printf("cannot access GPIO17\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//fb= gpiod_chip_get_line(chip,27);
|
||||
if (!fb) {
|
||||
printf("cannot access GPIO27\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//va= gpiod_chip_get_line(chip,4);
|
||||
if (!va) {
|
||||
printf("cannot access GPIO4\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//vb= gpiod_chip_get_line(chip,22);
|
||||
if (!vb) {
|
||||
printf("cannot access GPIO22\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//gptt = gpiod_chip_get_line(chip,18);
|
||||
if (!gptt) {
|
||||
printf("cannot access GPIO18\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//gmute = gpiod_chip_get_line(chip,23);
|
||||
if (!gmute) {
|
||||
printf("cannot access GPIO23\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//pttout = gpiod_chip_get_line(chip,24);
|
||||
if (!pttout) {
|
||||
printf("cannot access GPIO24\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//ret = gpiod_line_request_get_fd(fa, "huhu");
|
||||
if (ret) {
|
||||
printf("cannot init GPIO17 for input\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//ret = gpiod_line_request_input(fb, "huhu");
|
||||
if (ret) {
|
||||
printf("cannot init GPIO27 for input\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//ret = gpiod_line_request_input(va, "huhu");
|
||||
if (ret) {
|
||||
printf("cannot init GPIO4 for input\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//ret = gpiod_line_request_input(vb, "huhu");
|
||||
if (ret) {
|
||||
printf("cannot init GPIO22 for input\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//ret = gpiod_line_request_input(gptt, "huhu");
|
||||
if (ret) {
|
||||
printf("cannot init GPIO18 for input\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//ret = gpiod_line_request_input(gmute, "huhu");
|
||||
if (ret) {
|
||||
printf("cannot init GPIO23 for input\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//ret = gpiod_line_request_get_fd(pttout, "huhu", 0);
|
||||
if (ret) {
|
||||
printf("cannot init GPIO24 for output\n");
|
||||
gpiod_chip_close(chip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("GPIOs initialized\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
void close_gpio()
|
||||
{
|
||||
/* if(fa) gpiod_line_request(fa);
|
||||
if(fb) gpiod_line_request(fb);
|
||||
if(va) gpiod_line_request(va);
|
||||
if(vb) gpiod_line_request(vb);
|
||||
if(gptt) gpiod_line_request(gptt);
|
||||
if(gmute) gpiod_line_request(gmute);
|
||||
*/
|
||||
if(chip) gpiod_chip_close(chip);
|
||||
}
|
||||
|
||||
// get status of physical port
|
||||
int getPort(char *port)
|
||||
{
|
||||
#ifndef RASPI
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if(port[0] == 'f')
|
||||
{
|
||||
//if(port[1] == 'a') return gpiod_line_value(fa);
|
||||
//return gpiod_line_value(fb);
|
||||
}
|
||||
|
||||
if(port[0] == 'v')
|
||||
{
|
||||
//if(port[1] == 'a') return gpiod_line_value(va);
|
||||
//return gpiod_line_value(vb);
|
||||
}
|
||||
|
||||
//if(port[0] == 'p')
|
||||
//return gpiod_line_value(gptt);
|
||||
|
||||
//if(port[0] == 'm')
|
||||
//return gpiod_line_value(gmute);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setPort(char *port, int value)
|
||||
{
|
||||
#ifndef RASPI
|
||||
return;
|
||||
#endif
|
||||
|
||||
if(port[0] == 'p')
|
||||
{
|
||||
//gpiod_line_value(pttout,value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
void init_rotencoder();
|
||||
void close_gpio();
|
||||
int getEncSteps(int idx);
|
||||
int test_ptt_gpio();
|
||||
int test_mute_gpio();
|
||||
void setPort(char *port, int value);
|
||||
int getPort(char *port);
|
||||
Binary file not shown.
Reference in New Issue
Block a user