kopia lustrzana https://github.com/Hamlib/Hamlib
New TS-7400 based rotor backend
From Øystein Hårberg, LA7LKA, a backend for a rotor based on the TS-7400 embedded ARM board running Linux from http://www.embeddedarm.com/ Signed-off-by: Nate Bargmann <n0nb@n0nb.us>Hamlib-1.2.14
rodzic
9ebd14decd
commit
e53bfe96b8
|
@ -18,7 +18,7 @@ DIST_SUBDIRS = macros include lib $(subdirs) src c++ bindings tests doc \
|
|||
icom kenwood aor yaesu dummy pcr alinco uniden tentec kachina jrc \
|
||||
rpcrig winradio easycomm fodtrack rpcrot drake rotorez \
|
||||
flexradio sartek lowe rft rs tapr kit skanti prm80 wj racal tuner \
|
||||
gs232a heathkit spid ars m2 amsat scripts
|
||||
gs232a heathkit spid ars m2 amsat scripts ts7400
|
||||
|
||||
rpm: Makefile dist
|
||||
$(RPMBUILD) -ta $(PACKAGE)-$(VERSION).tar.gz
|
||||
|
|
|
@ -259,7 +259,7 @@ AC_SUBST(RIGMATRIX)
|
|||
|
||||
|
||||
BACKEND_LIST="icom kenwood aor yaesu dummy pcr alinco uniden tentec kachina jrc drake lowe rft rs kit skanti prm80 tapr flexradio wj racal tuner"
|
||||
ROT_BACKEND_LIST="dummy easycomm fodtrack gs232a heathkit kit rotorez sartek spid ars m2 amsat"
|
||||
ROT_BACKEND_LIST="dummy easycomm fodtrack gs232a heathkit kit rotorez sartek spid ars m2 amsat ts7400"
|
||||
BINDINGS=""
|
||||
BINDING_ALL=""
|
||||
BINDING_CHECK=""
|
||||
|
@ -539,6 +539,7 @@ rotorez/Makefile
|
|||
flexradio/Makefile
|
||||
m2/Makefile
|
||||
amsat/Makefile
|
||||
ts7400/Makefile
|
||||
scripts/Makefile
|
||||
hamlib.pc
|
||||
hamlib.spec]
|
||||
|
|
|
@ -254,6 +254,17 @@
|
|||
#define ROT_MODEL_IF100 ROT_MAKE_MODEL(ROT_AMSAT, 1)
|
||||
|
||||
|
||||
/*! \def ROT_MODEL_TS7400
|
||||
* \brief A macro that returns the model number of the TS7400 backend.
|
||||
*
|
||||
* The TS-7400 backend supports and embedded ARM board using the TS-7400
|
||||
* Linux board. More information is at http://www.embeddedarm.com
|
||||
*/
|
||||
#define ROT_TS7400 13
|
||||
#define ROT_BACKEND_TS7400 "ts7400"
|
||||
#define ROT_MODEL_TS7400 ROT_MAKE_MODEL(ROT_TS7400, 1)
|
||||
|
||||
|
||||
/*! \typedef typedef int rot_model_t
|
||||
\brief Convenience type definition for rotator model.
|
||||
*/
|
||||
|
@ -280,6 +291,7 @@ typedef int rot_model_t;
|
|||
{ ROT_M2, ROT_BACKEND_M2 }, \
|
||||
{ ROT_ARS, ROT_BACKEND_ARS }, \
|
||||
{ ROT_AMSAT, ROT_BACKEND_AMSAT }, \
|
||||
{ ROT_TS7400, ROT_BACKEND_TS7400 }, \
|
||||
{ 0, NULL }, /* end */ \
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
EXTRA_DIST = include/ep93xx_adc.h include/io.h include/peekpoke.h \
|
||||
include/readADC.h include/io.c include/peekpoke.c include/readADC.c \
|
||||
include/test7400ADC.c
|
||||
|
||||
pkglib_LTLIBRARIES = hamlib-ts7400.la
|
||||
hamlib_ts7400_la_SOURCES = ts7400.c
|
||||
hamlib_ts7400_la_LDFLAGS = -no-undefined -module -avoid-version
|
||||
hamlib_ts7400_la_LIBADD = $(top_builddir)/src/libhamlib.la \
|
||||
@MATH_LIBS@
|
||||
|
||||
noinst_HEADERS = ts7400.h
|
|
@ -0,0 +1,78 @@
|
|||
#define ADC_PAGE 0x80900000
|
||||
#define ADCRESULT_OFFSET 0x0008
|
||||
#define SDR_MASK 0x80000000
|
||||
#define DATA_OFFSET 0x0008
|
||||
#define DATA_MASK 0xFFFF
|
||||
#define ADCSWITCH_OFFSET 0x0018
|
||||
#define ADC_CH0 0x0608
|
||||
#define ADC_CH1 0x0680
|
||||
#define ADC_CH2 0x0640
|
||||
#define ADC_CH3 0x0620
|
||||
#define ADC_CH4 0x0610
|
||||
#define ADCSWLOCK_OFFSET 0x0020
|
||||
#define UNLOCK_VAL 0xAA
|
||||
|
||||
#define SYSCON_PAGE 0x80930000
|
||||
#define ADCCLKDIV_OFFSET 0x0090
|
||||
#define SYSCON_UNLOCK 0x00C0
|
||||
#define TSEN_MASK 0x80000000
|
||||
#define DEVICECFG_OFFSET 0x0080
|
||||
#define ADCPD_MASK 0x04
|
||||
#define ADCEN_MASK 0x20000
|
||||
|
||||
/* prototypes */
|
||||
void init_ADC(unsigned long adc_page, unsigned long syscon_page);
|
||||
int read_channel(unsigned long adc_page, unsigned short channel);
|
||||
static char is_ADC_busy(unsigned long adc_page);
|
||||
|
||||
void init_ADC(unsigned long adc_page, unsigned long syscon_page)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
/* set TSEN bit */
|
||||
val = PEEK32(syscon_page + ADCCLKDIV_OFFSET);
|
||||
//unlock the software lock
|
||||
POKE32(syscon_page + SYSCON_UNLOCK, UNLOCK_VAL);
|
||||
POKE32(syscon_page + ADCCLKDIV_OFFSET, TSEN_MASK | val);
|
||||
|
||||
/* set ADCEN bit */
|
||||
val = PEEK32(syscon_page + DEVICECFG_OFFSET);
|
||||
POKE32(syscon_page + SYSCON_UNLOCK, UNLOCK_VAL); //unlock the soft lock
|
||||
POKE32(syscon_page + DEVICECFG_OFFSET, val | ADCEN_MASK);
|
||||
|
||||
/* clear ADCPD bit */
|
||||
val = PEEK32(syscon_page + DEVICECFG_OFFSET);
|
||||
POKE32(adc_page + SYSCON_UNLOCK, UNLOCK_VAL); //unlock the soft lock
|
||||
POKE32(syscon_page + DEVICECFG_OFFSET, val & ~ADCPD_MASK);
|
||||
}
|
||||
|
||||
int read_channel(unsigned long adc_page, unsigned short channel)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
POKE32(adc_page + ADCSWLOCK_OFFSET, UNLOCK_VAL); //unlock the soft lock
|
||||
|
||||
//write ADCSwitch reg to select channel
|
||||
POKE32(adc_page + ADCSWITCH_OFFSET, channel);
|
||||
|
||||
while(is_ADC_busy(adc_page)); //poll ADCResult
|
||||
|
||||
//read result from data regisyyter
|
||||
val = PEEK32(adc_page + DATA_OFFSET) ;
|
||||
|
||||
val = val & DATA_MASK;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static char is_ADC_busy(unsigned long adc_page)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
val = PEEK32(adc_page + ADCRESULT_OFFSET);
|
||||
|
||||
if((val & SDR_MASK) == SDR_MASK)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// filename button.c
|
||||
// connect a button to DIO pin 1 and ground
|
||||
// blinks green and red led on the ts-7200 when button is pressed
|
||||
//
|
||||
// compile arm-linux-gcc -o button button.c
|
||||
//
|
||||
|
||||
#include<unistd.h>
|
||||
#include<sys/types.h>
|
||||
#include<sys/mman.h>
|
||||
#include<stdio.h>
|
||||
#include<fcntl.h>
|
||||
#include<string.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
volatile unsigned int *PEDR, *PEDDR, *PBDR, *PBDDR, *GPIOBDB;
|
||||
int i;
|
||||
unsigned char state;
|
||||
unsigned char *start;
|
||||
int fd = open("/dev/mem", O_RDWR|O_SYNC);
|
||||
|
||||
start = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x80840000);
|
||||
PBDR = (unsigned int *)(start + 0x04); // port b
|
||||
PBDDR = (unsigned int *)(start + 0x14); // port b direction register
|
||||
PEDR = (unsigned int *)(start + 0x20); // port e data
|
||||
PEDDR = (unsigned int *)(start + 0x24); // port e direction register
|
||||
GPIOBDB = (unsigned int *)(start + 0xC4); // debounce on port b
|
||||
|
||||
*PBDDR = 0xf0; // upper nibble output, lower nibble input
|
||||
*PEDDR = 0xff; // all output (just 2 bits)
|
||||
*GPIOBDB = 0x01; // enable debounce on bit 0
|
||||
|
||||
state = *PBDR; // read initial state
|
||||
while (state & 0x01) { // wait until button goes low
|
||||
state = *PBDR; // remember bit 0 is pulled up with 4.7k ohm
|
||||
}
|
||||
|
||||
|
||||
// blink 5 times, sleep 1 second so it's visible
|
||||
for (i = 0; i < 5; i++) {
|
||||
*PEDR = 0xff;
|
||||
sleep(1);
|
||||
*PEDR = 0x00;
|
||||
sleep(1);
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
#include<unistd.h>
|
||||
#include<sys/types.h>
|
||||
#include<sys/mman.h>
|
||||
#include<stdio.h>
|
||||
#include<fcntl.h>
|
||||
|
||||
unsigned int parseBinary(char *str) {
|
||||
unsigned int val = 0;
|
||||
|
||||
if (*str == 'b') {
|
||||
str++;
|
||||
while (*str) {
|
||||
if (*str == '0') {
|
||||
val <<= 1;
|
||||
} else if (*str == '1') {
|
||||
val = (val << 1) + 1;
|
||||
} else {
|
||||
goto binaryError;
|
||||
}
|
||||
}
|
||||
}
|
||||
return val;
|
||||
binaryError:
|
||||
fprintf(stderr,"Unrecognized numeric value: %s\n",str);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
unsigned int parseNumber(char *str) {
|
||||
unsigned int addr = 0;
|
||||
|
||||
if (!sscanf(str, "0x%x", &addr)) {
|
||||
if (!sscanf(str, "%u", &addr)) {
|
||||
addr = parseBinary(str);
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*
|
||||
Features that the old peekXX/pokeXX did not have:
|
||||
1. Support for 8/16/32 bit READ/WRITE in one function
|
||||
2. Support for decimal and binary values
|
||||
3. The value return is returned (to become the status code)
|
||||
*/
|
||||
int main(int argc, char **argv) {
|
||||
off_t addr, page;
|
||||
int fd,bits,dowrite=0,doread=1;
|
||||
unsigned char *start;
|
||||
unsigned char *chardat, charval;
|
||||
unsigned short *shortdat, shortval;
|
||||
unsigned int *intdat, intval;
|
||||
|
||||
if (argc < 3 || argc > 5) {
|
||||
fprintf(stderr,"Usage: peekpoke BIT_WIDTH ADDRESS <VALUE <x>>\n");
|
||||
fprintf(stderr,"<x> can be anything; supresses read-back on write\n");
|
||||
return 0;
|
||||
}
|
||||
sscanf(argv[1], "%d", &bits);
|
||||
if (bits != 8 && bits != 16 && bits != 32) {
|
||||
fprintf(stderr,"Error: BIT_WIDTH must be 8, 16, or 32\n");
|
||||
return 0;
|
||||
}
|
||||
addr = parseNumber(argv[2]);
|
||||
if (argc > 3 ) { // peekpoke BITS ADDRESS VALUE x
|
||||
intval = parseNumber(argv[3]);
|
||||
if (argc > 4) doread = 0;
|
||||
dowrite = 1;
|
||||
}
|
||||
fd = open("/dev/mem", O_RDWR|O_SYNC);
|
||||
if (fd == -1) {
|
||||
perror("open(/dev/mem):");
|
||||
return 0;
|
||||
}
|
||||
page = addr & 0xfffff000;
|
||||
start = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, page);
|
||||
if (start == MAP_FAILED) {
|
||||
perror("mmap:");
|
||||
return 0;
|
||||
}
|
||||
if (bits == 8) {
|
||||
charval = (unsigned char)intval;
|
||||
chardat = start + (addr & 0xfff);
|
||||
if (dowrite) {
|
||||
*chardat = charval;
|
||||
}
|
||||
if (doread) {
|
||||
intval = (unsigned int)*chardat;
|
||||
}
|
||||
} else if (bits == 16) {
|
||||
shortval = (unsigned short)intval;
|
||||
shortdat = (unsigned short *)(start + (addr & 0xfff));
|
||||
if (dowrite) {
|
||||
*shortdat = shortval;
|
||||
}
|
||||
if (doread) {
|
||||
intval = (unsigned int)*shortdat;
|
||||
}
|
||||
} else { // bits == 32
|
||||
intdat = (unsigned int *)(start + (addr & 0xfff));
|
||||
if (dowrite) {
|
||||
*intdat = intval;
|
||||
}
|
||||
if (doread) {
|
||||
intval = *intdat;
|
||||
}
|
||||
}
|
||||
if (doread) {
|
||||
printf("0x%X\n", intval);
|
||||
}
|
||||
close(fd);
|
||||
return intval;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
// We can't expect that a dereference of an unsigned short * always
|
||||
// produces a ldrh or strh since the compiler may choose to use
|
||||
// a byte write instead. Hence, we emit the peeks and pokes using
|
||||
// inline assembler. --JO
|
||||
static inline unsigned short PEEK16(unsigned long addr) {
|
||||
unsigned short ret;
|
||||
|
||||
asm volatile (
|
||||
"ldrh %0, [ %1 ]\n"
|
||||
: "=r" (ret)
|
||||
: "r" (addr)
|
||||
: "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void POKE16(unsigned long addr, unsigned short dat) {
|
||||
asm volatile (
|
||||
"strh %1, [ %0 ]\n"
|
||||
:
|
||||
: "r" (addr), "r" (dat)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
static inline unsigned long PEEK32(unsigned long addr) {
|
||||
unsigned long ret;
|
||||
|
||||
asm volatile (
|
||||
"ldr %0, [ %1 ]\n"
|
||||
: "=r" (ret)
|
||||
: "r" (addr)
|
||||
: "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void POKE32(unsigned long addr, unsigned long dat) {
|
||||
asm volatile (
|
||||
"str %1, [ %0 ]\n"
|
||||
:
|
||||
: "r" (addr), "r" (dat)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static inline unsigned char PEEK8(unsigned long addr) {
|
||||
unsigned char ret;
|
||||
|
||||
asm volatile (
|
||||
"ldrb %0, [ %1 ]\n"
|
||||
: "=r" (ret)
|
||||
: "r" (addr)
|
||||
: "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void POKE8(unsigned long addr, unsigned char dat) {
|
||||
asm volatile (
|
||||
"strb %1, [ %0 ]\n"
|
||||
:
|
||||
: "r" (addr), "r" (dat)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#define TRUE 0x01
|
||||
#define FALSE 0x00
|
|
@ -0,0 +1,451 @@
|
|||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "peekpoke.h"
|
||||
#include "ep93xx_adc.h"
|
||||
|
||||
#define DATA_PAGE 0x12C00000
|
||||
#define CALIB_LOC 2027 //location of calibration values
|
||||
#define NUM_SAMPLES 5
|
||||
#define NUM_CHANNELS 4
|
||||
|
||||
/* globals */
|
||||
static unsigned long adc_page, syscon_page;
|
||||
char *dr_page;
|
||||
double el,az;
|
||||
|
||||
/*Calculate the adc value corresponding to 0V*/
|
||||
//val1 is the ADC val coresponding to 0.833V
|
||||
//val2 is the ADC val corresponging to 2.5V
|
||||
int calcZeroVal(int val1, int val2)
|
||||
{
|
||||
val2 += 0x10000;
|
||||
return (int)(val1-(((val2-val1)/(2.5-0.833))*0.833));
|
||||
}
|
||||
|
||||
|
||||
//return value of 1 indicates the board has no calibration values
|
||||
//return value of 0 indicates the board has calibration values
|
||||
int read_calibration(int buf[NUM_CHANNELS][2])
|
||||
{
|
||||
int i,j,k = 0;
|
||||
unsigned short cal[NUM_CHANNELS*2];
|
||||
// read 16 calibration bytes into buffer
|
||||
FILE *f = fopen("/etc/ADC-calibration.dat","r");
|
||||
|
||||
if (!f) goto empty_calibration;
|
||||
|
||||
printf("Non-virgin board detected, evaluating stored "
|
||||
"calibration values\n");
|
||||
printf("Stored Calibration values [");
|
||||
|
||||
if (fread(cal,NUM_CHANNELS*4,1,f) == 1)
|
||||
{
|
||||
for(j=0;j<2;j++)
|
||||
for(i=0;i<NUM_CHANNELS;i++)
|
||||
{
|
||||
printf("0x%x", cal[k]);
|
||||
buf[i][j] = cal[k];
|
||||
k++;
|
||||
|
||||
if(k < NUM_CHANNELS*2)
|
||||
printf(", ");
|
||||
|
||||
}
|
||||
printf("]\n");
|
||||
return 1;
|
||||
}
|
||||
empty_calibration:
|
||||
|
||||
printf("/etc/ADC-calibration.dat not found or it's not readable\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void write_calibration(int cal[NUM_CHANNELS][2])
|
||||
{
|
||||
unsigned short buf[16];
|
||||
int i,j,k=0;
|
||||
FILE *f = fopen("/etc/ADC-calibration.dat","w");
|
||||
|
||||
//Convert 32 bit vals to 16 bit vals
|
||||
for(j=0;j<2;j++)
|
||||
for(i=0;i<NUM_CHANNELS;i++)
|
||||
{
|
||||
buf[k] = (unsigned short)cal[i][j];
|
||||
k++;
|
||||
|
||||
}
|
||||
if (!f) goto unwrite_calibration;
|
||||
|
||||
if (fwrite(buf,NUM_CHANNELS*4,1,f) == 1) return;
|
||||
|
||||
unwrite_calibration:
|
||||
|
||||
printf("Problem writing /etc/ADC-calibration.dat: %m\n");
|
||||
}
|
||||
|
||||
static void erase_calibration()
|
||||
{
|
||||
printf("Erasing calibration values...\n");
|
||||
unlink("/etc/ADC-calibration.dat");
|
||||
}
|
||||
|
||||
int check_calibration(int cal[NUM_CHANNELS][2],
|
||||
int stored_cal[NUM_CHANNELS][2], int state)
|
||||
{
|
||||
double pcnt_diff;
|
||||
int i,j,erase_cal =0;
|
||||
int failure = 0;
|
||||
|
||||
if(state == 0) //no calibration values
|
||||
{
|
||||
printf("Virgin board detected...\n");
|
||||
for(j=0;j<2;j++)
|
||||
{
|
||||
|
||||
for(i=0;i<NUM_CHANNELS;i++)
|
||||
{
|
||||
|
||||
if(j == 0)
|
||||
pcnt_diff = (((double)abs(0xa000 -
|
||||
cal[i][j])) / 0xa000) * 100;
|
||||
else
|
||||
pcnt_diff = (((double)abs(0x3300 -
|
||||
cal[i][j])) / 0x3300) * 100;
|
||||
|
||||
if(pcnt_diff > 10)
|
||||
{
|
||||
printf("Calculated calibration "
|
||||
"values out of range...\n");
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
write_calibration(cal);
|
||||
|
||||
} else //calibration values read
|
||||
{
|
||||
|
||||
for(j=0;j<2;j++)
|
||||
{
|
||||
for(i=0;i<NUM_CHANNELS;i++)
|
||||
{
|
||||
|
||||
pcnt_diff = (((double)abs(stored_cal[i][j] -
|
||||
cal[i][j])) / stored_cal[i][j])
|
||||
* 100;
|
||||
if(pcnt_diff > 0.25)
|
||||
{
|
||||
if(!failure)
|
||||
{
|
||||
printf("Calibration values out"
|
||||
"of range\n");
|
||||
failure = 1;
|
||||
erase_cal = 1;
|
||||
}
|
||||
printf("\tChannel %d: %3.3f%%\n",i
|
||||
, pcnt_diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(erase_cal) erase_calibration();
|
||||
if(failure) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void setDR(char *x,int n,int val)
|
||||
{
|
||||
if (n < 0 || n > 8)
|
||||
return;
|
||||
|
||||
x[0] = (x[0] & ~(1 << n)) | (val ? (1<<n) : 0);
|
||||
}
|
||||
|
||||
void setD(char *x,int n,int val)
|
||||
{
|
||||
if (n < 0 || n > 8)
|
||||
return;
|
||||
|
||||
x[2] = (x[2] & ~(1 << n)) | (val ? (1<<n) : 0);
|
||||
}
|
||||
|
||||
double get_volts(int val, int zero, int range)
|
||||
{
|
||||
if(val <= 0x7000)
|
||||
val = val + 0x10000;
|
||||
|
||||
val = val - zero;
|
||||
|
||||
return ((double)val * 3.3) / range;
|
||||
}
|
||||
|
||||
void calc_calibration(int calibration[NUM_CHANNELS][2],
|
||||
int adc_result_1[NUM_CHANNELS][NUM_SAMPLES],
|
||||
int adc_result_2[NUM_CHANNELS][NUM_SAMPLES])
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/* zero out our calibration values */
|
||||
for(i = 0; i < NUM_CHANNELS; i++)
|
||||
for(j = 0; j < 2; j++)
|
||||
calibration[i][j] = 0;
|
||||
|
||||
//convert 0.833V vals to 0V vals
|
||||
for(i=0;i<NUM_CHANNELS;i++)
|
||||
{
|
||||
for(j=0;j<NUM_SAMPLES;j++)
|
||||
{
|
||||
if(i % 2)//odd channels
|
||||
adc_result_1[i][j] =
|
||||
calcZeroVal(adc_result_1[i][j],
|
||||
adc_result_1[0][j]);
|
||||
else
|
||||
adc_result_2[i][j] =
|
||||
calcZeroVal(adc_result_2[i][j],
|
||||
adc_result_2[1][j]);
|
||||
}
|
||||
}
|
||||
|
||||
//sum the readings
|
||||
for(i = 0; i < NUM_CHANNELS; i++)
|
||||
{
|
||||
for(j = 0; j < NUM_SAMPLES; j++ )
|
||||
{
|
||||
if(i % 2 == 0 )
|
||||
{
|
||||
//0.833 volt values
|
||||
calibration[i][0] = adc_result_2[i][j]
|
||||
+ calibration[i][0];
|
||||
//2.5 volt values
|
||||
calibration[i][1] = adc_result_1[i][j]
|
||||
+ calibration[i][1];
|
||||
} else
|
||||
{
|
||||
//0.833 volt values
|
||||
calibration[i][0] = adc_result_1[i][j]
|
||||
+ calibration[i][0];
|
||||
//2.5 volt values
|
||||
calibration[i][1] = adc_result_2[i][j]
|
||||
+ calibration[i][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//printf("Calculated Calibration values [");
|
||||
for(j = 0; j < 2; j++)
|
||||
{
|
||||
for(i = 0; i < NUM_CHANNELS; i++)
|
||||
{
|
||||
calibration[i][j] = (calibration[i][j] / NUM_SAMPLES);
|
||||
|
||||
//printf("0x%x", calibration[i][j]);
|
||||
|
||||
//if((i == NUM_CHANNELS-1) && (j == 1))
|
||||
//printf("]\n");
|
||||
//else
|
||||
//printf(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
*DESCRIPTION: Read the EP93xx onboard ADC. Discard the first
|
||||
*two samples then save the next NUM_SAMPLES.
|
||||
***********************************************************************/
|
||||
static void read_7xxx_adc(int adc_result[NUM_CHANNELS][NUM_SAMPLES])
|
||||
{
|
||||
int i, j, cur_ch;
|
||||
|
||||
for(i = 0; i < NUM_CHANNELS; i++)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
case 0:
|
||||
cur_ch = ADC_CH0;
|
||||
break;
|
||||
case 1:
|
||||
cur_ch = ADC_CH1;
|
||||
break;
|
||||
case 2:
|
||||
cur_ch = ADC_CH2;
|
||||
break;
|
||||
case 3:
|
||||
cur_ch = ADC_CH3;
|
||||
break;
|
||||
case 4:
|
||||
cur_ch = ADC_CH4;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
//discard first two samples
|
||||
read_channel(adc_page, cur_ch);
|
||||
read_channel(adc_page, cur_ch);
|
||||
|
||||
//read more samples
|
||||
for(j = 0; j < NUM_SAMPLES; j++)
|
||||
{
|
||||
usleep(10000);
|
||||
adc_result[i][j] = read_channel(adc_page, cur_ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int test_ADC(int calibration[NUM_CHANNELS][2])
|
||||
{
|
||||
int adc_result_1[NUM_CHANNELS][NUM_SAMPLES];
|
||||
int adc_result_2[NUM_CHANNELS][NUM_SAMPLES];
|
||||
int i, j, return_val;
|
||||
int failure = 0;
|
||||
//double voltage,el,az;
|
||||
double voltage;
|
||||
|
||||
setD(dr_page, 0, 1); //ADC1 = ADC3 = 0.833V
|
||||
setD(dr_page, 2, 1); //ADC0 = ADC2 = 2.5V
|
||||
read_7xxx_adc(adc_result_1);
|
||||
|
||||
setD(dr_page, 0, 0); //ADC1 = ADC3 = 2.5V
|
||||
setD(dr_page, 2, 1); //ADC0 = ADC2 = 0.833V
|
||||
read_7xxx_adc(adc_result_2);
|
||||
|
||||
|
||||
el = get_volts(adc_result_1[0][0], 0x9E58, 0xC350);
|
||||
az = get_volts(adc_result_1[1][0], 0x9E58, 0xC350);
|
||||
|
||||
el = (el/3.3) * 180;
|
||||
az = (az/3.3) * 360;
|
||||
//printf("\t El.: %3.1f Az.: %3.1f \n", el, az);
|
||||
|
||||
//verify results are within range
|
||||
for(i=0;i<NUM_CHANNELS;i++)
|
||||
{
|
||||
for(j=0;j<NUM_SAMPLES;j++)
|
||||
{
|
||||
//use the datasheet values
|
||||
voltage = get_volts(adc_result_1[i][j], 0x9E58, 0xC350);
|
||||
//printf("\tChannel %d: %3.1f \n", i, voltage);
|
||||
//even channels 2.5V(+-150mV)
|
||||
if(i % 2 == 0 &&
|
||||
(voltage < 2.35 || voltage > 2.65))
|
||||
{
|
||||
if(!failure)
|
||||
{
|
||||
failure = 1;
|
||||
//printf("EP93XX ADC out of range\n");
|
||||
}
|
||||
//printf("\tChannel %d: %3.3fV"
|
||||
//"(expected 2.5V +- 150mV)\n", i, voltage);
|
||||
//odd channels 0.833(+-50mV)
|
||||
}
|
||||
else if(i % 2 == 1 &&
|
||||
(voltage < 0.333 || voltage > 1.333))
|
||||
{
|
||||
if(!failure)
|
||||
{
|
||||
failure = 1;
|
||||
//printf( "EP93xx ADC out of range\n");
|
||||
}
|
||||
|
||||
//printf("\tChannel %d: %3.3fV"
|
||||
// "(expected 0.833V +- 50mV)\n", i, voltage);
|
||||
}
|
||||
|
||||
|
||||
//use the datasheet values
|
||||
voltage = get_volts(adc_result_2[i][j], 0x9E58, 0xC350);
|
||||
|
||||
//odd channels 2.5V(+-150mV)
|
||||
if(i % 2 == 1 &&
|
||||
(voltage < 2.35 || voltage > 2.65))
|
||||
{
|
||||
if(!failure)
|
||||
{
|
||||
failure = 1;
|
||||
//printf("EP93XX ADC out of range\n");
|
||||
}
|
||||
//printf("\tChannel %d: %3.3fV"
|
||||
//"(expected 2.5V +- 150mV)\n", i, voltage);
|
||||
//even channels 0.833(+-50mV)
|
||||
}
|
||||
else if(i % 2 == 0 &&
|
||||
(voltage < 0.333 || voltage > 1.333))
|
||||
{
|
||||
if(!failure)
|
||||
{
|
||||
failure = 1;
|
||||
//printf( "EP93xx ADC out of range\n");
|
||||
}
|
||||
|
||||
///printf("\tChannel %d: %3.3fV" "(expected 0.833V +- 50mV)\n", i, voltage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
calc_calibration(calibration, adc_result_1, adc_result_2);
|
||||
|
||||
if(failure)
|
||||
return_val = 0;
|
||||
else return_val = 1;
|
||||
|
||||
return return_val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int calibration[NUM_CHANNELS][2];
|
||||
int stored_calibration[NUM_CHANNELS][2];
|
||||
int ret_val, state;
|
||||
int devmem = open("/dev/mem", O_RDWR|O_SYNC);
|
||||
assert(devmem != -1);
|
||||
|
||||
dr_page = mmap(0, getpagesize(), PROT_READ|PROT_WRITE,
|
||||
MAP_SHARED, devmem, DATA_PAGE);
|
||||
assert(&dr_page != MAP_FAILED);
|
||||
adc_page = (unsigned long)mmap(0, getpagesize(), PROT_READ|PROT_WRITE,
|
||||
MAP_SHARED, devmem, ADC_PAGE);
|
||||
assert(&adc_page != MAP_FAILED);
|
||||
syscon_page = (unsigned long)mmap(0, getpagesize(), PROT_READ|PROT_WRITE
|
||||
, MAP_SHARED, devmem, SYSCON_PAGE);
|
||||
assert(&syscon_page != MAP_FAILED);
|
||||
|
||||
init_ADC(adc_page, syscon_page);
|
||||
setDR(dr_page, 0, 1);
|
||||
setDR(dr_page, 1, 0);
|
||||
setDR(dr_page, 2, 1);
|
||||
setDR(dr_page, 3, 0);
|
||||
|
||||
|
||||
if(test_ADC(calibration))
|
||||
{
|
||||
printf("ADC tested ok(data sheet values)\n");
|
||||
state = read_calibration(stored_calibration);
|
||||
|
||||
if(check_calibration(calibration, stored_calibration, state))
|
||||
ret_val = 0;
|
||||
else
|
||||
ret_val = 1;
|
||||
|
||||
}
|
||||
else
|
||||
ret_val = 1;
|
||||
printf("\t El.: %3.1f Az.: %3.1f \n", el, az);
|
||||
close(devmem);
|
||||
return ret_val;
|
||||
}
|
|
@ -0,0 +1,438 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "peekpoke.h"
|
||||
#include "ep93xx_adc.h"
|
||||
|
||||
#define DATA_PAGE 0x12C00000
|
||||
#define CALIB_LOC 2027 //location of calibration values
|
||||
#define NUM_SAMPLES 5
|
||||
#define NUM_CHANNELS 4
|
||||
|
||||
/* globals */
|
||||
static unsigned long adc_page, syscon_page;
|
||||
char *dr_page;
|
||||
|
||||
/*Calculate the adc value corresponding to 0V*/
|
||||
//val1 is the ADC val coresponding to 0.833V
|
||||
//val2 is the ADC val corresponging to 2.5V
|
||||
int calcZeroVal(int val1, int val2)
|
||||
{
|
||||
val2 += 0x10000;
|
||||
return (int)(val1-(((val2-val1)/(2.5-0.833))*0.833));
|
||||
}
|
||||
|
||||
|
||||
//return value of 1 indicates the board has no calibration values
|
||||
//return value of 0 indicates the board has calibration values
|
||||
int read_calibration(int buf[NUM_CHANNELS][2])
|
||||
{
|
||||
int i,j,k = 0;
|
||||
unsigned short cal[NUM_CHANNELS*2];
|
||||
// read 16 calibration bytes into buffer
|
||||
FILE *f = fopen("/etc/ADC-calibration.dat","r");
|
||||
|
||||
if (!f) goto empty_calibration;
|
||||
|
||||
printf("Non-virgin board detected, evaluating stored "
|
||||
"calibration values\n");
|
||||
printf("Stored Calibration values [");
|
||||
|
||||
if (fread(cal,NUM_CHANNELS*4,1,f) == 1)
|
||||
{
|
||||
for(j=0;j<2;j++)
|
||||
for(i=0;i<NUM_CHANNELS;i++)
|
||||
{
|
||||
printf("0x%x", cal[k]);
|
||||
buf[i][j] = cal[k];
|
||||
k++;
|
||||
|
||||
if(k < NUM_CHANNELS*2)
|
||||
printf(", ");
|
||||
|
||||
}
|
||||
printf("]\n");
|
||||
return 1;
|
||||
}
|
||||
empty_calibration:
|
||||
|
||||
printf("/etc/ADC-calibration.dat not found or it's not readable\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void write_calibration(int cal[NUM_CHANNELS][2])
|
||||
{
|
||||
unsigned short buf[16];
|
||||
int i,j,k=0;
|
||||
FILE *f = fopen("/etc/ADC-calibration.dat","w");
|
||||
|
||||
//Convert 32 bit vals to 16 bit vals
|
||||
for(j=0;j<2;j++)
|
||||
for(i=0;i<NUM_CHANNELS;i++)
|
||||
{
|
||||
buf[k] = (unsigned short)cal[i][j];
|
||||
k++;
|
||||
|
||||
}
|
||||
if (!f) goto unwrite_calibration;
|
||||
|
||||
if (fwrite(buf,NUM_CHANNELS*4,1,f) == 1) return;
|
||||
|
||||
unwrite_calibration:
|
||||
|
||||
printf("Problem writing /etc/ADC-calibration.dat: %m\n");
|
||||
}
|
||||
|
||||
static void erase_calibration()
|
||||
{
|
||||
printf("Erasing calibration values...\n");
|
||||
unlink("/etc/ADC-calibration.dat");
|
||||
}
|
||||
|
||||
int check_calibration(int cal[NUM_CHANNELS][2],
|
||||
int stored_cal[NUM_CHANNELS][2], int state)
|
||||
{
|
||||
double pcnt_diff;
|
||||
int i,j,erase_cal =0;
|
||||
int failure = 0;
|
||||
|
||||
if(state == 0) //no calibration values
|
||||
{
|
||||
printf("Virgin board detected...\n");
|
||||
for(j=0;j<2;j++)
|
||||
{
|
||||
|
||||
for(i=0;i<NUM_CHANNELS;i++)
|
||||
{
|
||||
|
||||
if(j == 0)
|
||||
pcnt_diff = (((double)abs(0xa000 -
|
||||
cal[i][j])) / 0xa000) * 100;
|
||||
else
|
||||
pcnt_diff = (((double)abs(0x3300 -
|
||||
cal[i][j])) / 0x3300) * 100;
|
||||
|
||||
if(pcnt_diff > 10)
|
||||
{
|
||||
printf("Calculated calibration "
|
||||
"values out of range...\n");
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
write_calibration(cal);
|
||||
|
||||
} else //calibration values read
|
||||
{
|
||||
|
||||
for(j=0;j<2;j++)
|
||||
{
|
||||
for(i=0;i<NUM_CHANNELS;i++)
|
||||
{
|
||||
|
||||
pcnt_diff = (((double)abs(stored_cal[i][j] -
|
||||
cal[i][j])) / stored_cal[i][j])
|
||||
* 100;
|
||||
if(pcnt_diff > 0.25)
|
||||
{
|
||||
if(!failure)
|
||||
{
|
||||
printf("Calibration values out"
|
||||
"of range\n");
|
||||
failure = 1;
|
||||
erase_cal = 1;
|
||||
}
|
||||
printf("\tChannel %d: %3.3f%%\n",i
|
||||
, pcnt_diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(erase_cal) erase_calibration();
|
||||
if(failure) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void setDR(char *x,int n,int val)
|
||||
{
|
||||
if (n < 0 || n > 8)
|
||||
return;
|
||||
|
||||
x[0] = (x[0] & ~(1 << n)) | (val ? (1<<n) : 0);
|
||||
}
|
||||
|
||||
void setD(char *x,int n,int val)
|
||||
{
|
||||
if (n < 0 || n > 8)
|
||||
return;
|
||||
|
||||
x[2] = (x[2] & ~(1 << n)) | (val ? (1<<n) : 0);
|
||||
}
|
||||
|
||||
double get_volts(int val, int zero, int range)
|
||||
{
|
||||
if(val <= 0x7000)
|
||||
val = val + 0x10000;
|
||||
|
||||
val = val - zero;
|
||||
|
||||
return ((double)val * 3.3) / range;
|
||||
}
|
||||
|
||||
void calc_calibration(int calibration[NUM_CHANNELS][2],
|
||||
int adc_result_1[NUM_CHANNELS][NUM_SAMPLES],
|
||||
int adc_result_2[NUM_CHANNELS][NUM_SAMPLES])
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/* zero out our calibration values */
|
||||
for(i = 0; i < NUM_CHANNELS; i++)
|
||||
for(j = 0; j < 2; j++)
|
||||
calibration[i][j] = 0;
|
||||
|
||||
//convert 0.833V vals to 0V vals
|
||||
for(i=0;i<NUM_CHANNELS;i++)
|
||||
{
|
||||
for(j=0;j<NUM_SAMPLES;j++)
|
||||
{
|
||||
if(i % 2)//odd channels
|
||||
adc_result_1[i][j] =
|
||||
calcZeroVal(adc_result_1[i][j],
|
||||
adc_result_1[0][j]);
|
||||
else
|
||||
adc_result_2[i][j] =
|
||||
calcZeroVal(adc_result_2[i][j],
|
||||
adc_result_2[1][j]);
|
||||
}
|
||||
}
|
||||
|
||||
//sum the readings
|
||||
for(i = 0; i < NUM_CHANNELS; i++)
|
||||
{
|
||||
for(j = 0; j < NUM_SAMPLES; j++ )
|
||||
{
|
||||
if(i % 2 == 0 )
|
||||
{
|
||||
//0.833 volt values
|
||||
calibration[i][0] = adc_result_2[i][j]
|
||||
+ calibration[i][0];
|
||||
//2.5 volt values
|
||||
calibration[i][1] = adc_result_1[i][j]
|
||||
+ calibration[i][1];
|
||||
} else
|
||||
{
|
||||
//0.833 volt values
|
||||
calibration[i][0] = adc_result_1[i][j]
|
||||
+ calibration[i][0];
|
||||
//2.5 volt values
|
||||
calibration[i][1] = adc_result_2[i][j]
|
||||
+ calibration[i][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("Calculated Calibration values [");
|
||||
for(j = 0; j < 2; j++)
|
||||
{
|
||||
for(i = 0; i < NUM_CHANNELS; i++)
|
||||
{
|
||||
calibration[i][j] = (calibration[i][j] / NUM_SAMPLES);
|
||||
|
||||
printf("0x%x", calibration[i][j]);
|
||||
|
||||
if((i == NUM_CHANNELS-1) && (j == 1))
|
||||
printf("]\n");
|
||||
else
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
*DESCRIPTION: Read the EP93xx onboard ADC. Discard the first
|
||||
*two samples then save the next NUM_SAMPLES.
|
||||
***********************************************************************/
|
||||
static void read_7xxx_adc(int adc_result[NUM_CHANNELS][NUM_SAMPLES])
|
||||
{
|
||||
int i, j, cur_ch;
|
||||
|
||||
for(i = 0; i < NUM_CHANNELS; i++)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
case 0:
|
||||
cur_ch = ADC_CH0;
|
||||
break;
|
||||
case 1:
|
||||
cur_ch = ADC_CH1;
|
||||
break;
|
||||
case 2:
|
||||
cur_ch = ADC_CH2;
|
||||
break;
|
||||
case 3:
|
||||
cur_ch = ADC_CH3;
|
||||
break;
|
||||
case 4:
|
||||
cur_ch = ADC_CH4;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
//discard first two samples
|
||||
read_channel(adc_page, cur_ch);
|
||||
read_channel(adc_page, cur_ch);
|
||||
|
||||
//read more samples
|
||||
for(j = 0; j < NUM_SAMPLES; j++)
|
||||
{
|
||||
usleep(10000);
|
||||
adc_result[i][j] = read_channel(adc_page, cur_ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int test_ADC(int calibration[NUM_CHANNELS][2])
|
||||
{
|
||||
int adc_result_1[NUM_CHANNELS][NUM_SAMPLES];
|
||||
int adc_result_2[NUM_CHANNELS][NUM_SAMPLES];
|
||||
int i, j, return_val;
|
||||
int failure = 0;
|
||||
double voltage;
|
||||
|
||||
setD(dr_page, 0, 1); //ADC1 = ADC3 = 0.833V
|
||||
setD(dr_page, 2, 1); //ADC0 = ADC2 = 2.5V
|
||||
read_7xxx_adc(adc_result_1);
|
||||
|
||||
setD(dr_page, 0, 0); //ADC1 = ADC3 = 2.5V
|
||||
setD(dr_page, 2, 1); //ADC0 = ADC2 = 0.833V
|
||||
read_7xxx_adc(adc_result_2);
|
||||
|
||||
//verify results are within range
|
||||
for(i=0;i<NUM_CHANNELS;i++)
|
||||
{
|
||||
for(j=0;j<NUM_SAMPLES;j++)
|
||||
{
|
||||
//use the datasheet values
|
||||
voltage = get_volts(adc_result_1[i][j], 0x9E58, 0xC350);
|
||||
|
||||
//even channels 2.5V(+-150mV)
|
||||
if(i % 2 == 0 &&
|
||||
(voltage < 2.35 || voltage > 2.65))
|
||||
{
|
||||
if(!failure)
|
||||
{
|
||||
failure = 1;
|
||||
printf("EP93XX ADC out of range\n");
|
||||
}
|
||||
printf("\tChannel %d: %3.3fV"
|
||||
"(expected 2.5V +- 150mV)\n", i, voltage);
|
||||
//odd channels 0.833(+-50mV)
|
||||
}
|
||||
else if(i % 2 == 1 &&
|
||||
(voltage < 0.333 || voltage > 1.333))
|
||||
{
|
||||
if(!failure)
|
||||
{
|
||||
failure = 1;
|
||||
printf( "EP93xx ADC out of range\n");
|
||||
}
|
||||
|
||||
printf("\tChannel %d: %3.3fV"
|
||||
"(expected 0.833V +- 50mV)\n", i, voltage);
|
||||
}
|
||||
|
||||
|
||||
//use the datasheet values
|
||||
voltage = get_volts(adc_result_2[i][j], 0x9E58, 0xC350);
|
||||
|
||||
//odd channels 2.5V(+-150mV)
|
||||
if(i % 2 == 1 &&
|
||||
(voltage < 2.35 || voltage > 2.65))
|
||||
{
|
||||
if(!failure)
|
||||
{
|
||||
failure = 1;
|
||||
printf("EP93XX ADC out of range\n");
|
||||
}
|
||||
printf("\tChannel %d: %3.3fV"
|
||||
"(expected 2.5V +- 150mV)\n", i, voltage);
|
||||
//even channels 0.833(+-50mV)
|
||||
}
|
||||
else if(i % 2 == 0 &&
|
||||
(voltage < 0.333 || voltage > 1.333))
|
||||
{
|
||||
if(!failure)
|
||||
{
|
||||
failure = 1;
|
||||
printf( "EP93xx ADC out of range\n");
|
||||
}
|
||||
|
||||
printf("\tChannel %d: %3.3fV"
|
||||
"(expected 0.833V +- 50mV)\n", i, voltage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
calc_calibration(calibration, adc_result_1, adc_result_2);
|
||||
|
||||
if(failure)
|
||||
return_val = 0;
|
||||
else return_val = 1;
|
||||
|
||||
return return_val;
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int calibration[NUM_CHANNELS][2];
|
||||
int stored_calibration[NUM_CHANNELS][2];
|
||||
int ret_val, state;
|
||||
int devmem = open("/dev/mem", O_RDWR|O_SYNC);
|
||||
assert(devmem != -1);
|
||||
|
||||
dr_page = mmap(0, getpagesize(), PROT_READ|PROT_WRITE,
|
||||
MAP_SHARED, devmem, DATA_PAGE);
|
||||
assert(&dr_page != MAP_FAILED);
|
||||
adc_page = (unsigned long)mmap(0, getpagesize(), PROT_READ|PROT_WRITE,
|
||||
MAP_SHARED, devmem, ADC_PAGE);
|
||||
assert(&adc_page != MAP_FAILED);
|
||||
syscon_page = (unsigned long)mmap(0, getpagesize(), PROT_READ|PROT_WRITE
|
||||
, MAP_SHARED, devmem, SYSCON_PAGE);
|
||||
assert(&syscon_page != MAP_FAILED);
|
||||
|
||||
init_ADC(adc_page, syscon_page);
|
||||
setDR(dr_page, 0, 1);
|
||||
setDR(dr_page, 1, 0);
|
||||
setDR(dr_page, 2, 1);
|
||||
setDR(dr_page, 3, 0);
|
||||
|
||||
if(test_ADC(calibration))
|
||||
{
|
||||
printf("ADC tested ok(data sheet values)\n");
|
||||
state = read_calibration(stored_calibration);
|
||||
|
||||
if(check_calibration(calibration, stored_calibration, state))
|
||||
ret_val = 0;
|
||||
else
|
||||
ret_val = 1;
|
||||
|
||||
}
|
||||
else
|
||||
ret_val = 1;
|
||||
|
||||
close(devmem);
|
||||
|
||||
return ret_val;
|
||||
}
|
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* Hamlib ts7400 backend - main file
|
||||
* Copyright (c) 2001-2009 by Stephane Fillod
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Library 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 Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h> /* String function definitions */
|
||||
#include <unistd.h> /* UNIX standard function definitions */
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <hamlib/rotator.h>
|
||||
#include "serial.h"
|
||||
#include "misc.h"
|
||||
#include "register.h"
|
||||
|
||||
#include "ts7400.h"
|
||||
|
||||
struct ts7400_rot_priv_data {
|
||||
azimuth_t az;
|
||||
elevation_t el;
|
||||
|
||||
struct timeval tv; /* time last az/el update */
|
||||
azimuth_t target_az;
|
||||
elevation_t target_el;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int ts7400_rot_init(ROT *rot)
|
||||
{
|
||||
struct ts7400_rot_priv_data *priv;
|
||||
|
||||
priv = (struct ts7400_rot_priv_data*)
|
||||
malloc(sizeof(struct ts7400_rot_priv_data));
|
||||
|
||||
if (!priv)
|
||||
return -RIG_ENOMEM;
|
||||
rot->state.priv = (void*)priv;
|
||||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
rot->state.rotport.type.rig = RIG_PORT_NONE;
|
||||
|
||||
priv->az = priv->el = 0;
|
||||
|
||||
priv->target_az = priv->target_el = 0;
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
static int ts7400_rot_cleanup(ROT *rot)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
if (rot->state.priv)
|
||||
free(rot->state.priv);
|
||||
|
||||
rot->state.priv = NULL;
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
static int ts7400_rot_open(ROT *rot)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
static int ts7400_rot_close(ROT *rot)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
static int ts7400_rot_set_position(ROT *rot, azimuth_t az, elevation_t el)
|
||||
{
|
||||
struct ts7400_rot_priv_data *priv = (struct ts7400_rot_priv_data *)rot->state.priv;
|
||||
|
||||
rig_debug(RIG_DEBUG_VERBOSE,"%s called: %.2f %.2f\n", __func__,
|
||||
az, el);
|
||||
|
||||
priv->target_az = az;
|
||||
priv->target_el = el;
|
||||
|
||||
gettimeofday(&priv->tv, NULL);
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get position of rotor, simulating slow rotation
|
||||
*/
|
||||
static int ts7400_rot_get_position(ROT *rot, azimuth_t *az, elevation_t *el)
|
||||
{
|
||||
struct ts7400_rot_priv_data *priv = (struct ts7400_rot_priv_data *)rot->state.priv;
|
||||
struct timeval tv;
|
||||
unsigned elapsed; /* ms */
|
||||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
if (priv->az == priv->target_az &&
|
||||
priv->el == priv->target_el)
|
||||
{
|
||||
*az = priv->az;
|
||||
*el = priv->el;
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
elapsed = (tv.tv_sec - priv->tv.tv_sec) * 1000 +
|
||||
(tv.tv_usec - priv->tv.tv_usec) / 1000;
|
||||
|
||||
/*
|
||||
* Simulate rotation speed of 360 deg per minute
|
||||
*/
|
||||
#define DEG_PER_MS (360./60/1000)
|
||||
if (fabs(priv->target_az - priv->az)/DEG_PER_MS <= elapsed)
|
||||
{
|
||||
/* target reached */
|
||||
priv->az = priv->target_az;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (priv->az < priv->target_az)
|
||||
priv->az += (azimuth_t)elapsed*DEG_PER_MS;
|
||||
else
|
||||
priv->az -= (azimuth_t)elapsed*DEG_PER_MS;
|
||||
}
|
||||
|
||||
if (fabs(priv->target_el - priv->el)/DEG_PER_MS <= elapsed)
|
||||
{
|
||||
/* target reached */
|
||||
priv->el = priv->target_el;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (priv->el < priv->target_el)
|
||||
priv->el += (elevation_t)elapsed*DEG_PER_MS;
|
||||
else
|
||||
priv->el -= (elevation_t)elapsed*DEG_PER_MS;
|
||||
}
|
||||
|
||||
*az = priv->az;
|
||||
*el = priv->el;
|
||||
|
||||
priv->tv = tv;
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
|
||||
static int ts7400_rot_stop(ROT *rot)
|
||||
{
|
||||
struct ts7400_rot_priv_data *priv = (struct ts7400_rot_priv_data *)rot->state.priv;
|
||||
azimuth_t az;
|
||||
elevation_t el;
|
||||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
ts7400_rot_get_position(rot, &az, &el);
|
||||
|
||||
priv->target_az = priv->az = az;
|
||||
priv->target_el = priv->el = el;
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
|
||||
static int ts7400_rot_park(ROT *rot)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
/* Assume home is 0,0 */
|
||||
ts7400_rot_set_position(rot, 0, 0);
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
static int ts7400_rot_reset(ROT *rot, rot_reset_t reset)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
static int ts7400_rot_move(ROT *rot, int direction, int speed)
|
||||
{
|
||||
struct ts7400_rot_priv_data *priv = (struct ts7400_rot_priv_data *)rot->state.priv;
|
||||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
rig_debug(RIG_DEBUG_TRACE, "%s: Direction = %d, Speed = %d\n", __func__, direction, speed);
|
||||
|
||||
switch(direction) {
|
||||
case ROT_MOVE_UP:
|
||||
return ts7400_rot_set_position(rot, priv->target_az, 90);
|
||||
|
||||
case ROT_MOVE_DOWN:
|
||||
return ts7400_rot_set_position(rot, priv->target_az, 0);
|
||||
|
||||
case ROT_MOVE_CCW:
|
||||
return ts7400_rot_set_position(rot, -180, priv->target_el);
|
||||
|
||||
case ROT_MOVE_CW:
|
||||
return ts7400_rot_set_position(rot, 180, priv->target_el);
|
||||
|
||||
default:
|
||||
return -RIG_EINVAL;
|
||||
}
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
static const char *ts7400_rot_get_info(ROT *rot)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
return "ts7400 rotator";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* ts7400 rotator capabilities.
|
||||
*/
|
||||
|
||||
const struct rot_caps ts7400_rot_caps = {
|
||||
.rot_model = ROT_MODEL_TS7400,
|
||||
.model_name = "ts7400",
|
||||
.mfg_name = "LA7LKA",
|
||||
.version = "0.1",
|
||||
.copyright = "LGPL",
|
||||
.status = RIG_STATUS_BETA,
|
||||
.rot_type = ROT_TYPE_AZEL,
|
||||
.port_type = RIG_PORT_NONE,
|
||||
|
||||
.min_az = -180.,
|
||||
.max_az = 180.,
|
||||
.min_el = 0.,
|
||||
.max_el = 90.,
|
||||
|
||||
.priv = NULL, /* priv */
|
||||
|
||||
.rot_init = ts7400_rot_init,
|
||||
.rot_cleanup = ts7400_rot_cleanup,
|
||||
.rot_open = ts7400_rot_open,
|
||||
.rot_close = ts7400_rot_close,
|
||||
|
||||
.set_position = ts7400_rot_set_position,
|
||||
.get_position = ts7400_rot_get_position,
|
||||
.park = ts7400_rot_park,
|
||||
.stop = ts7400_rot_stop,
|
||||
.reset = ts7400_rot_reset,
|
||||
.move = ts7400_rot_move,
|
||||
|
||||
.get_info = ts7400_rot_get_info,
|
||||
};
|
||||
|
||||
DECLARE_INITROT_BACKEND(ts7400)
|
||||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "ts7400: _init called\n");
|
||||
|
||||
rot_register(&ts7400_rot_caps);
|
||||
|
||||
return RIG_OK;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Hamlib Dummy backend - main header
|
||||
* Copyright (c) 2001-2008 by Stephane Fillod
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Library 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 Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ROT_ts7400_H
|
||||
#define _ROT_ts7400_H 1
|
||||
|
||||
|
||||
extern const struct rot_caps ts7400_rot_caps;
|
||||
extern const struct rot_caps netrotctl_caps;
|
||||
|
||||
#endif /* _ROT_DUMMY_H */
|
Ładowanie…
Reference in New Issue