diff --git a/Makefile.am b/Makefile.am index a4022435a..5db784f51 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/configure.ac b/configure.ac index e121ee033..29a806fef 100644 --- a/configure.ac +++ b/configure.ac @@ -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] diff --git a/include/hamlib/rotlist.h b/include/hamlib/rotlist.h index 8754fffd8..86bb7863d 100644 --- a/include/hamlib/rotlist.h +++ b/include/hamlib/rotlist.h @@ -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 */ \ } diff --git a/ts7400/Makefile.am b/ts7400/Makefile.am new file mode 100644 index 000000000..7d190c528 --- /dev/null +++ b/ts7400/Makefile.am @@ -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 diff --git a/ts7400/include/ep93xx_adc.h b/ts7400/include/ep93xx_adc.h new file mode 100644 index 000000000..d6131703e --- /dev/null +++ b/ts7400/include/ep93xx_adc.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; +} diff --git a/ts7400/include/io.c b/ts7400/include/io.c new file mode 100644 index 000000000..0c3da6892 --- /dev/null +++ b/ts7400/include/io.c @@ -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 +#include +#include +#include +#include +#include + +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; +} diff --git a/ts7400/include/io.h b/ts7400/include/io.h new file mode 100644 index 000000000..e69de29bb diff --git a/ts7400/include/peekpoke.c b/ts7400/include/peekpoke.c new file mode 100644 index 000000000..38db5c890 --- /dev/null +++ b/ts7400/include/peekpoke.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include + +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 >\n"); + fprintf(stderr," 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; +} diff --git a/ts7400/include/peekpoke.h b/ts7400/include/peekpoke.h new file mode 100644 index 000000000..a592e75f7 --- /dev/null +++ b/ts7400/include/peekpoke.h @@ -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 diff --git a/ts7400/include/readADC.c b/ts7400/include/readADC.c new file mode 100644 index 000000000..ded70094f --- /dev/null +++ b/ts7400/include/readADC.c @@ -0,0 +1,451 @@ + +#include +#include +#include +#include +#include +#include +#include + +#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 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 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< 8) + return; + + x[2] = (x[2] & ~(1 << n)) | (val ? (1< 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; +} diff --git a/ts7400/include/readADC.h b/ts7400/include/readADC.h new file mode 100644 index 000000000..e69de29bb diff --git a/ts7400/include/test7400ADC.c b/ts7400/include/test7400ADC.c new file mode 100644 index 000000000..81416cf02 --- /dev/null +++ b/ts7400/include/test7400ADC.c @@ -0,0 +1,438 @@ +#include +#include +#include +#include +#include +#include +#include + +#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 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 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< 8) + return; + + x[2] = (x[2] & ~(1 << n)) | (val ? (1< 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; +} diff --git a/ts7400/ts7400.c b/ts7400/ts7400.c new file mode 100644 index 000000000..b0429bea0 --- /dev/null +++ b/ts7400/ts7400.c @@ -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 +#include /* String function definitions */ +#include /* UNIX standard function definitions */ +#include +#include +#include + +#include +#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; +} diff --git a/ts7400/ts7400.h b/ts7400/ts7400.h new file mode 100644 index 000000000..213acec57 --- /dev/null +++ b/ts7400/ts7400.h @@ -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 */