diff --git a/apps/rp_bmp180/Makefile b/apps/rp_bmp180/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c7bf5a39a8cb5960855936bb10794b1d28ca02aa --- /dev/null +++ b/apps/rp_bmp180/Makefile @@ -0,0 +1,9 @@ + +SENSOR=bmp180 + +all: + gcc -Wall -c $(SENSOR).c -o $(SENSOR).o -lm + gcc -Wall $(SENSOR).o test.c -o test -lm + +clean: + rm *.o > /dev/null 2>&1 & diff --git a/apps/rp_bmp180/bmp180.c b/apps/rp_bmp180/bmp180.c new file mode 100644 index 0000000000000000000000000000000000000000..8b08e4006ba97725fc980e21da87e3110e7bab90 --- /dev/null +++ b/apps/rp_bmp180/bmp180.c @@ -0,0 +1,558 @@ +/** + * $Id: $ + * + * @brief A C driver for BMP180 sesor + * + * @Author L. Horacio Arnaldi <lharnaldi@gmail.com> + * @date 01.04.2016 + * + * (c) LabDPR http://labdpr.cab.cnea.gov.ar + * + * This part of code is written in C programming language. + * Please visit http://en.wikipedia.org/wiki/C_(programming_language) + * for more details on the language used herein. + */ + +#ifndef __BMP180__ +#define __BMP180__ +#include <stdint.h> +#include "bmp180.h" +#include <string.h> +#include <stdbool.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <linux/i2c-dev.h> +#include <time.h> +#include <math.h> +#endif + + +/* + * AC register + */ +#define BMP180_REG_AC1_H 0xAA +#define BMP180_REG_AC2_H 0xAC +#define BMP180_REG_AC3_H 0xAE +#define BMP180_REG_AC4_H 0xB0 +#define BMP180_REG_AC5_H 0xB2 +#define BMP180_REG_AC6_H 0xB4 + +/* + * B1 register + */ +#define BMP180_REG_B1_H 0xB6 + +/* + * B2 register + */ +#define BMP180_REG_B2_H 0xB8 + +/* + * MB register + */ +#define BMP180_REG_MB_H 0xBA + +/* + * MC register + */ +#define BMP180_REG_MC_H 0xBC + +/* + * MD register + */ +#define BMP180_REG_MD_H 0xBE + +/* + * AC register + */ +#define BMP180_CTRL 0xF4 + +/* + * Temperature register + */ +#define BMP180_REG_TMP 0xF6 + +/* + * Pressure register + */ +#define BMP180_REG_PRE 0xF6 + +/* + * Temperature read command + */ +#define BMP180_TMP_READ_CMD 0x2E + +/* + * Waiting time in us for reading temperature values + */ +#define BMP180_TMP_READ_WAIT_US 5000 + +/* + * Pressure oversampling modes + */ +#define BMP180_PRE_OSS0 0 // ultra low power +#define BMP180_PRE_OSS1 1 // standard +#define BMP180_PRE_OSS2 2 // high resolution +#define BMP180_PRE_OSS3 3 // ultra high resoultion + +/* + * Pressure read commands + */ +#define BMP180_PRE_OSS0_CMD 0x34 +#define BMP180_PRE_OSS1_CMD 0x74 +#define BMP180_PRE_OSS2_CMD 0xB4 +#define BMP180_PRE_OSS3_CMD 0xF4 + +/* + * Waiting times in us for reading pressure values + */ +#define BMP180_PRE_OSS0_WAIT_US 5000 +#define BMP180_PRE_OSS1_WAIT_US 8000 +#define BMP180_PRE_OSS2_WAIT_US 14000 +#define BMP180_PRE_OSS3_WAIT_US 26000 + +/* + * Average sea-level pressure in hPa + */ +#define BMP180_SEA_LEVEL 1013.25 + + +/* + * Define debug function. + */ + +//#define __BMP180_DEBUG__ +#ifdef __BMP180_DEBUG__ +#define DEBUG(...) printf(__VA_ARGS__) +#else +#define DEBUG(...) +#endif + + +/* + * Shortcut to cast void pointer to a bmp180_t pointer + */ +#define TO_BMP(x) (bmp180_t*) x + + + +/* + * Basic structure for the bmp180 sensor + */ +typedef struct { + /* file descriptor */ + int file; + + /* i2c device address */ + int address; + + /* BMP180 oversampling mode */ + int oss; + + /* i2c device file path */ + char *i2c_device; + + /* Eprom values */ + int32_t ac1; + int32_t ac2; + int32_t ac3; + int32_t ac4; + int32_t ac5; + int32_t ac6; + int32_t b1; + int32_t b2; + int32_t mb; + int32_t mc; + int32_t md; +} bmp180_t; + + +/* + * Lookup table for BMP180 register addresses + */ +int32_t bmp180_register_table[11][2] = { + {BMP180_REG_AC1_H, 1}, + {BMP180_REG_AC2_H, 1}, + {BMP180_REG_AC3_H, 1}, + {BMP180_REG_AC4_H, 0}, + {BMP180_REG_AC5_H, 0}, + {BMP180_REG_AC6_H, 0}, + {BMP180_REG_B1_H, 1}, + {BMP180_REG_B2_H, 1}, + {BMP180_REG_MB_H, 1}, + {BMP180_REG_MC_H, 1}, + {BMP180_REG_MD_H, 1} +}; + + +/* + * Prototypes for helper functions + */ +int bmp180_set_addr(void *_bmp); +void bmp180_read_eprom_reg(void *_bmp, int32_t *_data, uint8_t reg, int32_t sign); +void bmp180_read_eprom(void *_bmp); +int32_t bmp180_read_raw_pressure(void *_bmp, uint8_t oss); +int32_t bmp180_read_raw_temperature(void *_bmp); +void bmp180_init_error_cleanup(void *_bmp); + + +/* + * Implemetation of the helper functions + */ + + +/* + * Sets the address for the i2c device file. + * + * @param bmp180 sensor + */ +int bmp180_set_addr(void *_bmp) { + bmp180_t* bmp = TO_BMP(_bmp); + int error; + + if((error = ioctl(bmp->file, I2C_SLAVE, bmp->address)) < 0) { + DEBUG("error: ioctl() failed\n"); + } + + return error; +} + + + +/* + * Frees allocated memory in the init function. + * + * @param bmp180 sensor + */ +void bmp180_init_error_cleanup(void *_bmp) { + bmp180_t* bmp = TO_BMP(_bmp); + + if(bmp->i2c_device != NULL) { + free(bmp->i2c_device); + bmp->i2c_device = NULL; + } + + free(bmp); + bmp = NULL; +} + + + +/* + * Reads a single calibration coefficient from the BMP180 eprom. + * + * @param bmp180 sensor + */ +void bmp180_read_eprom_reg(void *_bmp, int32_t *_store, uint8_t reg, int32_t sign) { + bmp180_t *bmp = TO_BMP(_bmp); + int32_t data = i2c_smbus_read_word_data(bmp->file, reg) & 0xFFFF; + + // i2c_smbus_read_word_data assumes little endian + // but ARM uses big endian. Thus the ordering of the bytes is reversed. + // data = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 bit position + // | lsb | msb | + + // msb + lsb + *_store = ((data << 8) & 0xFF00) + (data >> 8); + + if(sign && (*_store > 32767)) { + *_store -= 65536; + } +} + + +/* + * Reads the eprom of this BMP180 sensor. + * + * @param bmp180 sensor + */ +void bmp180_read_eprom(void *_bmp) { + bmp180_t *bmp = TO_BMP(_bmp); + + int32_t *bmp180_register_addr[11] = { + &bmp->ac1, &bmp->ac2, &bmp->ac3, &bmp->ac4, &bmp->ac5, &bmp->ac6, + &bmp->b1, &bmp->b2, &bmp->mb, &bmp->mc, &bmp->md + }; + + uint8_t sign, reg; + int32_t *data; + int i; + for(i = 0; i < 11; i++) { + reg = (uint8_t) bmp180_register_table[i][0]; + sign = (uint8_t) bmp180_register_table[i][1]; + data = bmp180_register_addr[i]; + bmp180_read_eprom_reg(_bmp, data, reg, sign); + } +} + + +/* + * Returns the raw measured temperature value of this BMP180 sensor. + * + * @param bmp180 sensor + */ +int32_t bmp180_read_raw_temperature(void *_bmp) { + bmp180_t* bmp = TO_BMP(_bmp); + i2c_smbus_write_byte_data(bmp->file, BMP180_CTRL, BMP180_TMP_READ_CMD); + + usleep(BMP180_TMP_READ_WAIT_US); + int32_t data = i2c_smbus_read_word_data(bmp->file, BMP180_REG_TMP) & 0xFFFF; + + data = ((data << 8) & 0xFF00) + (data >> 8); + + return data; +} + + +/* + * Returns the raw measured pressure value of this BMP180 sensor. + * + * @param bmp180 sensor + */ +int32_t bmp180_read_raw_pressure(void *_bmp, uint8_t oss) { + bmp180_t* bmp = TO_BMP(_bmp); + uint16_t wait; + uint8_t cmd; + + switch(oss) { + case BMP180_PRE_OSS1: + wait = BMP180_PRE_OSS1_WAIT_US; cmd = BMP180_PRE_OSS1_CMD; + break; + + case BMP180_PRE_OSS2: + wait = BMP180_PRE_OSS2_WAIT_US; cmd = BMP180_PRE_OSS2_CMD; + break; + + case BMP180_PRE_OSS3: + wait = BMP180_PRE_OSS3_WAIT_US; cmd = BMP180_PRE_OSS3_CMD; + break; + + case BMP180_PRE_OSS0: + default: + wait = BMP180_PRE_OSS0_WAIT_US; cmd = BMP180_PRE_OSS0_CMD; + break; + } + + i2c_smbus_write_byte_data(bmp->file, BMP180_CTRL, cmd); + + usleep(wait); + + int32_t msb, lsb, xlsb, data; + msb = i2c_smbus_read_byte_data(bmp->file, BMP180_REG_PRE) & 0xFF; + lsb = i2c_smbus_read_byte_data(bmp->file, BMP180_REG_PRE+1) & 0xFF; + xlsb = i2c_smbus_read_byte_data(bmp->file, BMP180_REG_PRE+2) & 0xFF; + + data = ((msb << 16) + (lsb << 8) + xlsb) >> (8 - bmp->oss); + + return data; +} + +/* + * Implementation of the interface functions + */ + +/** + * Dumps the eprom values of this BMP180 sensor. + * + * @param bmp180 sensor + * @param bmp180 eprom struct + */ +void bmp180_dump_eprom(void *_bmp, bmp180_eprom_t *eprom) { + bmp180_t *bmp = TO_BMP(_bmp); + eprom->ac1 = bmp->ac1; + eprom->ac2 = bmp->ac2; + eprom->ac3 = bmp->ac3; + eprom->ac4 = bmp->ac4; + eprom->ac5 = bmp->ac5; + eprom->ac6 = bmp->ac6; + eprom->b1 = bmp->b1; + eprom->b2 = bmp->b2; + eprom->mb = bmp->mb; + eprom->mc = bmp->mc; + eprom->md = bmp->md; +} + + +/** + * Creates a BMP180 sensor object. + * + * @param i2c device address + * @param i2c device file path + * @return bmp180 sensor + */ +void *bmp180_init(int address, const char* i2c_device_filepath) { + DEBUG("device: init using address %#x and i2cbus %s\n", address, i2c_device_filepath); + + // setup BMP180 + void *_bmp = malloc(sizeof(bmp180_t)); + if(_bmp == NULL) { + DEBUG("error: malloc returns NULL pointer\n"); + return NULL; + } + + bmp180_t *bmp = TO_BMP(_bmp); + bmp->address = address; + + // setup i2c device path + bmp->i2c_device = (char*) malloc(strlen(i2c_device_filepath) * sizeof(char)); + if(bmp->i2c_device == NULL) { + DEBUG("error: malloc returns NULL pointer!\n"); + bmp180_init_error_cleanup(bmp); + return NULL; + } + + // copy string + strcpy(bmp->i2c_device, i2c_device_filepath); + + // open i2c device + int file; + if((file = open(bmp->i2c_device, O_RDWR)) < 0) { + DEBUG("error: %s open() failed\n", bmp->i2c_device); + bmp180_init_error_cleanup(bmp); + return NULL; + } + bmp->file = file; + + // set i2c device address + if(bmp180_set_addr(_bmp) < 0) { + bmp180_init_error_cleanup(bmp); + return NULL; + } + + // setup i2c device + bmp180_read_eprom(_bmp); + bmp->oss = 0; + + DEBUG("device: open ok\n"); + + return _bmp; +} + + +/** + * Closes a BMP180 object. + * + * @param bmp180 sensor + */ +void bmp180_close(void *_bmp) { + if(_bmp == NULL) { + return; + } + + DEBUG("close bmp180 device\n"); + bmp180_t *bmp = TO_BMP(_bmp); + + if(close(bmp->file) < 0) { + DEBUG("error: %s close() failed\n", bmp->i2c_device); + } + + free(bmp->i2c_device); // free string + bmp->i2c_device = NULL; + free(bmp); // free bmp structure + _bmp = NULL; +} + + +/** + * Returns the measured temperature in celsius. + * + * @param bmp180 sensor + * @return temperature + */ +float bmp180_temperature(void *_bmp) { + bmp180_t* bmp = TO_BMP(_bmp); + long UT, X1, X2, B5; + float T; + + UT = bmp180_read_raw_temperature(_bmp); + + DEBUG("UT=%lu\n",UT); + + X1 = ((UT - bmp->ac6) * bmp->ac5) >> 15; + X2 = (bmp->mc << 11) / (X1 + bmp->md); + B5 = X1 + X2; + T = ((B5 + 8) >> 4) / 10.0; + + return T; +} + + +/** + * Returns the measured pressure in pascal. + * + * @param bmp180 sensor + * @return pressure + */ +long bmp180_pressure(void *_bmp) { + bmp180_t* bmp = TO_BMP(_bmp); + long UT, UP, B6, B5, X1, X2, X3, B3, p; + unsigned long B4, B7; + + UT = bmp180_read_raw_temperature(_bmp); + UP = bmp180_read_raw_pressure(_bmp, bmp->oss); + + X1 = ((UT - bmp->ac6) * bmp->ac5) >> 15; + X2 = (bmp->mc << 11) / (X1 + bmp->md); + + B5 = X1 + X2; + + B6 = B5 - 4000; + + X1 = (bmp->b2 * (B6 * B6) >> 12) >> 11; + X2 = (bmp->ac2 * B6) >> 11; + X3 = X1 + X2; + + B3 = ((((bmp->ac1 * 4) + X3) << bmp->oss) + 2) / 4; + X1 = (bmp->ac3 * B6) >> 13; + X2 = (bmp->b1 * ((B6 * B6) >> 12)) >> 16; + X3 = ((X1 + X2) + 2) >> 2; + + + B4 = bmp->ac4 * (unsigned long)(X3 + 32768) >> 15; + B7 = ((unsigned long) UP - B3) * (50000 >> bmp->oss); + + if(B7 < 0x80000000) { + p = (B7 * 2) / B4; + } else { + p = (B7 / B4) * 2; + } + + X1 = (p >> 8) * (p >> 8); + X1 = (X1 * 3038) >> 16; + X2 = (-7357 * p) >> 16; + p = p + ((X1 + X2 + 3791) >> 4); + + return p; +} + + +/** + * Returns altitude in meters based on the measured pressure + * and temperature of this sensor. + * + * @param bmp180 sensor + * @return altitude + */ +float bmp180_altitude(void *_bmp) { + float p, alt; + p = bmp180_pressure(_bmp); + alt = 44330 * (1 - pow(( (p/100) / BMP180_SEA_LEVEL),1/5.255)); + + return alt; +} + + +/** + * Sets the oversampling setting for this sensor. + * + * @param bmp180 sensor + * @param oversampling mode + */ +void bmp180_set_oss(void *_bmp, int oss) { + bmp180_t* bmp = TO_BMP(_bmp); + bmp->oss = oss; +} + diff --git a/apps/rp_bmp180/bmp180.h b/apps/rp_bmp180/bmp180.h new file mode 100644 index 0000000000000000000000000000000000000000..3cf73df53144f426df96afd23b5d8d714d3bc3aa --- /dev/null +++ b/apps/rp_bmp180/bmp180.h @@ -0,0 +1,53 @@ +/** + * $Id: $ + * + * @brief A C driver for BMP180 sesor + * + * @Author L. Horacio Arnaldi <lharnaldi@gmail.com> + * @date 01.04.2016 + * + * (c) LabDPR http://labdpr.cab.cnea.gov.ar + * + * This part of code is written in C programming language. + * Please visit http://en.wikipedia.org/wiki/C_(programming_language) + * for more details on the language used herein. + */ + +/* + * pressure oversampling modes + */ +#define BMP180_PRE_OSS0 0 // ultra low power +#define BMP180_PRE_OSS1 1 // standard +#define BMP180_PRE_OSS2 2 // high resolution +#define BMP180_PRE_OSS3 3 // ultra high resoultion + + +typedef struct { + /* Eprom values */ + int ac1; + int ac2; + int ac3; + int ac4; + int ac5; + int ac6; + int b1; + int b2; + int mb; + int mc; + int md; +} bmp180_eprom_t; + +void *bmp180_init(int address, const char* i2c_device_filepath); + +void bmp180_close(void *_bmp); + +long bmp180_pressure(void *_bmp); + +void bmp180_set_oss(void *_bmp, int oss); + +float bmp180_temperature(void *_bmp); + +float bmp180_altitude(void *_bmp); + +void bmp180_dump_eprom(void *_bmp, bmp180_eprom_t *eprom); + diff --git a/apps/rp_bmp180/test.c b/apps/rp_bmp180/test.c new file mode 100644 index 0000000000000000000000000000000000000000..1f0d851f328cf812040eae892d35a846cbabef7d --- /dev/null +++ b/apps/rp_bmp180/test.c @@ -0,0 +1,31 @@ +#include "bmp180.h" +#include <unistd.h> +#include <stdio.h> + +int main(int argc, char **argv){ + char *i2c_device = "/dev/i2c-0"; + int address = 0x77; + + void *bmp = bmp180_init(address, i2c_device); + + bmp180_eprom_t eprom; + bmp180_dump_eprom(bmp, &eprom); + + + bmp180_set_oss(bmp, 1); + + if(bmp != NULL){ + int i; + for(i = 0; i < 10; i++) { + float t = bmp180_temperature(bmp); + long p = bmp180_pressure(bmp); + float alt = bmp180_altitude(bmp); + printf("Temperature = %.1f, Pressure = %lu, Altitude= %.1f\n", t, p, alt); + usleep(2 * 1000 * 1000); + } + + bmp180_close(bmp); + } + + return 0; +} diff --git a/apps/rp_tinygps/Makefile b/apps/rp_tinygps/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d2810b15dc3a4307964739789881e69fab69ce2c --- /dev/null +++ b/apps/rp_tinygps/Makefile @@ -0,0 +1,14 @@ +CC=gcc +FLAGS=-Wall -O3 + +#### +PROG=rp_gps +EXTRA=tinygps.c + +all: $(PROG) + +$(PROG): $(PROG).c $(EXTRA) + $(CC) $(FLAGS) -o $(PROG) $(PROG).c $(EXTRA) -lm + +clean: + rm -f $(PROG) diff --git a/apps/rp_tinygps/rp_gps.c b/apps/rp_tinygps/rp_gps.c new file mode 100644 index 0000000000000000000000000000000000000000..d736afae47723110a49794e7287046528eeaf6fa --- /dev/null +++ b/apps/rp_tinygps/rp_gps.c @@ -0,0 +1,105 @@ +#include <stdio.h> +#include <stdlib.h> +#include "tinygps.h" + +#define BAUDRATE B9600 // Configuración UART para GPS - Velocidad +#define FALSE 0 +#define TRUE 1 +#define VERSION "0.1" + +/*GPS*/ +long alt; // Variable donde se guardara la altitud +long satellites; +float flat, flon; // Variables donde se guardarán la latitud y longitud +unsigned long age, fage; +int fyear; +byte fmes, fdia, fhora, fminutos, fs, fhs; // variables para la hora y fecha +int newdata = 0; +int res, fd; +int count=0, aux; +char buf[255]; +struct termios newtio; +struct sigaction saio; +int res, fd; +int wait_flag=TRUE; +char devicename[80] = "/dev/ttyPS1"; // Nombre del dispositivo GPS para UART +int i; // Variable utilizada para los lazos FOR + +void signal_handler_IO (int status) +{ +wait_flag = FALSE; +} + + +int main(void) { + + // Abir la comunicacion UART para el GPS + + fd = open(devicename, O_RDWR | O_NOCTTY | O_NONBLOCK); + + if (fd < 0) + { + perror(devicename); + exit(1); + } + + //Se installa el serial handler para el GPS + saio.sa_handler = signal_handler_IO; + sigemptyset(&saio.sa_mask); //saio.sa_mask = 0; + saio.sa_flags = 0; + saio.sa_restorer = NULL; + sigaction(SIGIO,&saio,NULL); + + fcntl(fd, F_SETOWN, getpid()); + fcntl(fd, F_SETFL, FASYNC); + newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; + newtio.c_iflag = IGNPAR; + newtio.c_oflag = 0; + newtio.c_lflag = 0; + newtio.c_cc[VMIN]=1; + newtio.c_cc[VTIME]=0; + tcflush(fd, TCIFLUSH); + tcsetattr(fd,TCSANOW,&newtio); + // + count=0; + aux = 0; + + while (count != 2 && aux < 10 )//Si no se recibe una señal valida del GPS en este lapso el programa contnua + { + usleep (10); + + aux++; + res = read(fd,buf,255); + if (res > 0) + { + for (i=0; i < res; i++) //Lee todos los caracteres del string + { + if(gps_encode(buf[i])) + newdata = 1; + } + + if (newdata) + { + alt = gps_f_altitude(); + satellites = gps_satellites(); + gps_crack_datetime(&fyear, &fmes, &fdia, &fhora, &fminutos, &fs, &fhs, &fage); + if (fhora < 5) + { + fhora = 24 + fhora; + fdia = fdia -1; + } + + gps_f_get_position(&flat, &flon, &age); + newdata = 0; + count++; + } + } + printf("# ------------------------------\n# Fecha:%d/%d/%d \n# Hora:%d:%d:%d:%d \n# Latitud= %f \n# Longitud= %f \n# Altitud: %lum\n# Satélites: %lu\n# -------------------------------\n",fyear, fmes, fdia, fhora-5, fminutos, fs, fhs, flat, flon, alt, satellites); + + } + + close(fd); + + +} + diff --git a/apps/rp_tinygps/tinygps.c b/apps/rp_tinygps/tinygps.c new file mode 100644 index 0000000000000000000000000000000000000000..842ec36abc879b69a08c2ceb34b8777eafc79a60 --- /dev/null +++ b/apps/rp_tinygps/tinygps.c @@ -0,0 +1,464 @@ + +#include "tinygps.h" + +// properties +unsigned long _time, _new_time; +unsigned long _date, _new_date; +long _latitude, _new_latitude; +long _longitude, _new_longitude; +long _altitude, _new_altitude; +unsigned long _speed, _new_speed; +unsigned long _course, _new_course; +unsigned long _hdop, _new_hdop; +unsigned short _numsats, _new_numsats; + +unsigned long _last_time_fix, _new_time_fix; +unsigned long _last_position_fix, _new_position_fix; + +// parsing state variables +byte _parity; +bool _is_checksum_term; +char _term[15]; +byte _sentence_type; +byte _term_number = 0; +byte _term_offset = 0; +bool _is_gps_data_good; + +#ifndef GPS_NO_STATS + // statistics +unsigned long _encoded_characters; +unsigned short _good_sentences; +unsigned short _failed_checksum; +unsigned short _passed_checksum; +#endif + +// +// public methods +// + +// verify is character is a digit +bool gpsisdigit(char c) { return c >= '0' && c <= '9'; } + +// signed altitude in centimeters (from GPGGA sentence) +inline long altitude() { return _altitude; } + +// course in last full GPRMC sentence in 100th of a degree +inline unsigned long course() { return _course; } + +// speed in last full GPRMC sentence in 100ths of a knot +inline unsigned long speed() { return _speed; } + +// satellites used in last full GPGGA sentence +unsigned short gps_satellites() { return _numsats; } + +// horizontal dilution of precision in 100ths +inline unsigned long gps_hdop() { return _hdop; } + + +clock_t uptime() +{ + return clock() / (CLOCKS_PER_SEC / 1000); +} + +float radians(float deg) +{ + return deg * (PI/180); +} + +float degrees(float rad) +{ + return rad * (180/PI); +} + +bool gps_encode(char c) +{ + bool valid_sentence = false; + +#ifndef GPS_NO_STATS + _encoded_characters++; +#endif + switch(c) + { + case ',': // term terminators + _parity ^= c; + case '\r': + case '\n': + case '*': + if (_term_offset < sizeof(_term)) + { + _term[_term_offset] = 0; + valid_sentence = gps_term_complete(); + } + ++_term_number; + _term_offset = 0; + _is_checksum_term = c == '*'; + return valid_sentence; + + case '$': // sentence begin + _term_number = 0; + _term_offset = 0; + _parity = 0; + _sentence_type = GPS_SENTENCE_OTHER; + _is_checksum_term = false; + _is_gps_data_good = false; + return valid_sentence; + } + + // ordinary characters + if (_term_offset < sizeof(_term) - 1) + _term[_term_offset++] = c; + if (!_is_checksum_term) + _parity ^= c; + + return valid_sentence; +} + +#ifndef GPS_NO_STATS +void gps_stats(unsigned long *chars, unsigned short *sentences, unsigned short *failed_cs) +{ + if (chars) + *chars = _encoded_characters; + if (sentences) + *sentences = _good_sentences; + if (failed_cs) + *failed_cs = _failed_checksum; +} +#endif + +/* + * internal utilities +*/ + +int from_hex(char a) +{ + if (a >= 'A' && a <= 'F') + return a - 'A' + 10; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else + return a - '0'; +} + +unsigned long gps_parse_decimal() +{ + char *p; + bool isneg; + unsigned long ret; + + p = _term; + isneg = (*p == '-'); + if (isneg) + ++p; + + ret = 100UL * gpsatol(p); + + while (gpsisdigit(*p)) + ++p; + + if (*p == '.') + { + if (gpsisdigit(p[1])) + { + ret += 10 * (p[1] - '0'); + if (gpsisdigit(p[2])) + ret += p[2] - '0'; + } + } + return isneg ? -ret : ret; +} + +unsigned long gps_parse_degrees() +{ + char *p; + unsigned long left; + unsigned long tenk_minutes; + + left = gpsatol(_term); + tenk_minutes = (left % 100UL) * 10000UL; + + for (p=_term; gpsisdigit(*p); ++p); + + if (*p == '.') + { + unsigned long mult = 1000; + while (gpsisdigit(*++p)) + { + tenk_minutes += mult * (*p - '0'); + mult /= 10; + } + } + return (left / 100) * 100000 + tenk_minutes / 6; +} + +#define COMBINE(sentence_type, term_number) (((unsigned)(sentence_type) << 5) | term_number) + +/* Processes a just-completed term + * Returns true if new sentence has just passed checksum test and is validated + */ +bool gps_term_complete() +{ + if (_is_checksum_term) + { + byte checksum; + checksum = 16 * from_hex(_term[0]) + from_hex(_term[1]); + if (checksum == _parity) + { + if (_is_gps_data_good) + { +#ifndef GPS_NO_STATS + ++_good_sentences; +#endif + _last_time_fix = _new_time_fix; + _last_position_fix = _new_position_fix; + + switch(_sentence_type) + { + case GPS_SENTENCE_GPRMC: + _time = _new_time; + _date = _new_date; + _latitude = _new_latitude; + _longitude = _new_longitude; + _speed = _new_speed; + _course = _new_course; + break; + case GPS_SENTENCE_GPGGA: + _altitude = _new_altitude; + _time = _new_time; + _latitude = _new_latitude; + _longitude = _new_longitude; + _numsats = _new_numsats; + _hdop = _new_hdop; + break; + } + + return true; + } + } + +#ifndef GPS_NO_STATS + else + ++_failed_checksum; +#endif + return false; + } + + // the first term determines the sentence type + if (_term_number == 0) + { + if (!gpsstrcmp(_term, GPRMC_TERM)) + _sentence_type = GPS_SENTENCE_GPRMC; + else if (!gpsstrcmp(_term, GPGGA_TERM)) + _sentence_type = GPS_SENTENCE_GPGGA; + else + _sentence_type = GPS_SENTENCE_OTHER; + return false; + } + + if (_sentence_type != GPS_SENTENCE_OTHER && _term[0]) + switch(COMBINE(_sentence_type, _term_number)) + { + case COMBINE(GPS_SENTENCE_GPRMC, 1): // Time in both sentences + case COMBINE(GPS_SENTENCE_GPGGA, 1): + _new_time = gps_parse_decimal(); + _new_time_fix = uptime(); + break; + case COMBINE(GPS_SENTENCE_GPRMC, 2): // GPRMC validity + _is_gps_data_good = (_term[0] == 'A'); + break; + case COMBINE(GPS_SENTENCE_GPRMC, 3): // Latitude + case COMBINE(GPS_SENTENCE_GPGGA, 2): + _new_latitude = gps_parse_degrees(); + _new_position_fix = uptime(); + break; + case COMBINE(GPS_SENTENCE_GPRMC, 4): // N/S + case COMBINE(GPS_SENTENCE_GPGGA, 3): + if (_term[0] == 'S') + _new_latitude = -_new_latitude; + break; + case COMBINE(GPS_SENTENCE_GPRMC, 5): // Longitude + case COMBINE(GPS_SENTENCE_GPGGA, 4): + _new_longitude = gps_parse_degrees(); + break; + case COMBINE(GPS_SENTENCE_GPRMC, 6): // E/W + case COMBINE(GPS_SENTENCE_GPGGA, 5): + if (_term[0] == 'W') + _new_longitude = -_new_longitude; + break; + case COMBINE(GPS_SENTENCE_GPRMC, 7): // Speed (GPRMC) + _new_speed = gps_parse_decimal(); + break; + case COMBINE(GPS_SENTENCE_GPRMC, 8): // Course (GPRMC) + _new_course = gps_parse_decimal(); + break; + case COMBINE(GPS_SENTENCE_GPRMC, 9): // Date (GPRMC) + _new_date = gpsatol(_term); + break; + case COMBINE(GPS_SENTENCE_GPGGA, 6): // Fix data (GPGGA) + _is_gps_data_good = (_term[0] > '0'); + break; + case COMBINE(GPS_SENTENCE_GPGGA, 7): // Satellites used (GPGGA) + _new_numsats = (unsigned char)atoi(_term); + break; + case COMBINE(GPS_SENTENCE_GPGGA, 8): // HDOP + _new_hdop = gps_parse_decimal(); + break; + case COMBINE(GPS_SENTENCE_GPGGA, 9): // Altitude (GPGGA) + _new_altitude = gps_parse_decimal(); + break; + } + + return false; +} + +long gpsatol(const char *str) +{ + long ret = 0; + while (gpsisdigit(*str)) + ret = 10 * ret + *str++ - '0'; + return ret; +} + +int gpsstrcmp(const char *str1, const char *str2) +{ + while (*str1 && *str1 == *str2) + ++str1, ++str2; + return *str1; +} + +/* static */ +float gps_distance_between (float lat1, float long1, float lat2, float long2) +{ + // returns distance in meters between two positions, both specified + // as signed decimal-degrees latitude and longitude. Uses great-circle + // distance computation for hypothetical sphere of radius 6372795 meters. + // Because Earth is no exact sphere, rounding errors may be up to 0.5%. + // Courtesy of Maarten Lamers + float delta = radians(long1-long2); + float sdlong = (float)sin(delta); + float cdlong = (float)cos(delta); + lat1 = radians(lat1); + lat2 = radians(lat2); + float slat1 = sin(lat1); + float clat1 = cos(lat1); + float slat2 = sin(lat2); + float clat2 = cos(lat2); + delta = (clat1 * slat2) - (slat1 * clat2 * cdlong); + delta = sq(delta); + delta += sq(clat2 * sdlong); + delta = sqrt(delta); + float denom = (slat1 * slat2) + (clat1 * clat2 * cdlong); + delta = atan2(delta, denom); + return delta * 6372795; +} + +float gps_course_to (float lat1, float long1, float lat2, float long2) +{ + // returns course in degrees (North=0, West=270) from position 1 to position 2, + // both specified as signed decimal-degrees latitude and longitude. + // Because Earth is no exact sphere, calculated course may be off by a tiny fraction. + // Courtesy of Maarten Lamers + float dlon = radians(long2-long1); + lat1 = radians(lat1); + lat2 = radians(lat2); + float a1 = sin(dlon) * cos(lat2); + float a2 = sin(lat1) * cos(lat2) * cos(dlon); + a2 = cos(lat1) * sin(lat2) - a2; + a2 = atan2(a1, a2); + if (a2 < 0.0) + { + a2 += TWO_PI; + } + return degrees(a2); +} + +const char *gps_cardinal (float course) +{ + static const char* directions[] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"}; + + int direction = (int)((course + 11.25f) / 22.5f); + return directions[direction % 16]; +} + +// lat/long in hundred thousandths of a degree and age of fix in milliseconds +void gps_get_position(long *latitude, long *longitude, unsigned long *fix_age) +{ + if (latitude) + *latitude = _latitude; + if (longitude) + *longitude = _longitude; + if (fix_age) + *fix_age = (_last_position_fix == GPS_INVALID_FIX_TIME) ? + GPS_INVALID_AGE : uptime() - _last_position_fix; +} + +// date as ddmmyy, time as hhmmsscc, and age in milliseconds +void gps_get_datetime(unsigned long *date, unsigned long *time, unsigned long *age) +{ + if (date) + *date = _date; + if (time) + *time = _time; + if (age) + *age = _last_time_fix == GPS_INVALID_FIX_TIME ? + GPS_INVALID_AGE : uptime() - _last_time_fix; +} + +void gps_f_get_position(float *latitude, float *longitude, unsigned long *fix_age) +{ + long lat, lon; + gps_get_position(&lat, &lon, fix_age); + *latitude = lat == GPS_INVALID_ANGLE ? GPS_INVALID_F_ANGLE : (lat / 100000.0); + *longitude = lat == GPS_INVALID_ANGLE ? GPS_INVALID_F_ANGLE : (lon / 100000.0); +} + +void gps_crack_datetime(int *year, byte *month, byte *day, + byte *hour, byte *minute, byte *second, byte *hundredths, unsigned long *age) +{ + unsigned long date, time; + gps_get_datetime(&date, &time, age); + if (year) + { + *year = date % 100; + *year += *year > 80 ? 1900 : 2000; + } + if (month) *month = (date / 100) % 100; + if (day) *day = date / 10000; + if (hour) *hour = time / 1000000; + if (minute) *minute = (time / 10000) % 100; + if (second) *second = (time / 100) % 100; + if (hundredths) *hundredths = time % 100; +} + +float gps_f_altitude() +{ + return _altitude == GPS_INVALID_ALTITUDE ? GPS_INVALID_F_ALTITUDE : _altitude / 100.0; +} + +float gps_f_course() +{ + return _course == GPS_INVALID_ANGLE ? GPS_INVALID_F_ANGLE : _course / 100.0; +} + +float gps_f_speed_knots() +{ + return _speed == GPS_INVALID_SPEED ? GPS_INVALID_F_SPEED : _speed / 100.0; +} + +float gps_f_speed_mph() +{ + float sk = gps_f_speed_knots(); + return sk == GPS_INVALID_F_SPEED ? GPS_INVALID_F_SPEED : GPS_MPH_PER_KNOT * gps_f_speed_knots(); +} + +float gps_f_speed_mps() +{ + float sk = gps_f_speed_knots(); + return sk == GPS_INVALID_F_SPEED ? GPS_INVALID_F_SPEED : GPS_MPS_PER_KNOT * gps_f_speed_knots(); +} + +float gps_f_speed_kmph() +{ + float sk = gps_f_speed_knots(); + return sk == GPS_INVALID_F_SPEED ? GPS_INVALID_F_SPEED : GPS_KMPH_PER_KNOT * gps_f_speed_knots(); +} + diff --git a/apps/rp_tinygps/tinygps.h b/apps/rp_tinygps/tinygps.h new file mode 100644 index 0000000000000000000000000000000000000000..93e863ce5a1e8f7cf83cd0163c38812612ef61f7 --- /dev/null +++ b/apps/rp_tinygps/tinygps.h @@ -0,0 +1,110 @@ +#ifndef tinygps_h +#define tinygps_h + +#include <stdlib.h> +#include <math.h> +#include <time.h> +#include <termios.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <sys/signal.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <stdint.h> +#include <string.h> +#include <stdbool.h> +#include <errno.h> +#include <signal.h> +#include <sys/mman.h> +#include <sys/sendfile.h> +#include <sys/stat.h> + + +//typedef char bool; +typedef unsigned char byte; +#define false 0 +#define true 1 + +#define PI 3.14159265 +#define TWO_PI 2*PI + +#define sq(x) ((x)*(x)) + +#define GPRMC_TERM "GPRMC" +#define GPGGA_TERM "GPGGA" + +#define GPS_INVALID_F_ANGLE 1000.0 +#define GPS_INVALID_F_ALTITUDE 1000000.0 +#define GPS_INVALID_F_SPEED -1.0 + + +#define GPS_VERSION 12 // software version of this library +#define GPS_MPH_PER_KNOT 1.15077945 +#define GPS_MPS_PER_KNOT 0.51444444 +#define GPS_KMPH_PER_KNOT 1.852 +#define GPS_MILES_PER_METER 0.00062137112 +#define GPS_KM_PER_METER 0.001 +// #define GPS_NO_STATS + + enum { + GPS_INVALID_AGE = 0xFFFFFFFF, + GPS_INVALID_ANGLE = 999999999, + GPS_INVALID_ALTITUDE = 999999999, + GPS_INVALID_DATE = 0, + GPS_INVALID_TIME = 0xFFFFFFFF, + GPS_INVALID_SPEED = 999999999, + GPS_INVALID_FIX_TIME = 0xFFFFFFFF, + GPS_INVALID_SATELLITES = 0xFF, + GPS_INVALID_HDOP = 0xFFFFFFFF + }; + + // process one character received from GPS + bool encode(char c); + + // lat/long in hundred thousandths of a degree and age of fix in milliseconds + void gps_get_position(long *latitude, long *longitude, unsigned long *fix_age); + + // date as ddmmyy, time as hhmmsscc, and age in milliseconds + void gps_get_datetime(unsigned long *date, unsigned long *time, unsigned long *age); + + void gps_f_get_position(float *latitude, float *longitude, unsigned long *fix_age); + void gps_crack_datetime(int *year, byte *month, byte *day, + byte *hour, byte *minute, byte *second, byte *hundredths, unsigned long *fix_age); + float gps_f_altitude(); + unsigned short gps_satellites(); + float gps_f_course(); + float gps_f_speed_knots(); + float gps_f_speed_mph(); + float gps_f_speed_mps(); + float gps_f_speed_kmph(); + + static int library_version() { return GPS_VERSION; } + + static float gps_distance_between (float lat1, float long1, float lat2, float long2); + static float gps_course_to (float lat1, float long1, float lat2, float long2); + static const char *gps_cardinal(float course); + +#ifndef GPS_NO_STATS + void gps_stats(unsigned long *chars, unsigned short *good_sentences, unsigned short *failed_cs); +#endif + + enum { + GPS_SENTENCE_GPGGA, + GPS_SENTENCE_GPRMC, + GPS_SENTENCE_OTHER + }; + + // internal utilities + int from_hex(char a); + unsigned long gps_parse_decimal(); + unsigned long gps_parse_degrees(); + bool gps_term_complete(); + bool gpsisdigit(char c); + long gpsatol(const char *str); + int gpsstrcmp(const char *str1, const char *str2); +// Cabeceras funciones +void signal_handler_IO (int status); + +#endif diff --git a/apps/rp_venusGPS/Makefile b/apps/rp_venusGPS/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7268416d2a155349485255054649dfa5f6d447d2 --- /dev/null +++ b/apps/rp_venusGPS/Makefile @@ -0,0 +1,14 @@ +CC=gcc +FLAGS=-Wall -O3 + +#### +PROG=gpsLogger +EXTRA=nmea_rp.c uart_rp.c gps_rp.c + +all: $(PROG) + +$(PROG): $(PROG).c $(EXTRA) + $(CC) $(FLAGS) -o $(PROG) $(PROG).c $(EXTRA) -lm + +clean: + rm -f $(PROG) diff --git a/apps/rp_venusGPS/gpsLogger.c b/apps/rp_venusGPS/gpsLogger.c new file mode 100644 index 0000000000000000000000000000000000000000..7241e0cf7dd42d28dfa00e0bdcf24df1234e1873 --- /dev/null +++ b/apps/rp_venusGPS/gpsLogger.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <stdlib.h> +#include "gps_rp.h" + +int main(void) { + // Open + gps_init(); + + loc_t data; + + while (1) { + gps_location(&data); + + printf("%lf %lf %d:%d:%d %d/%d/%d\n", data.latitude, data.longitude, data.D.hour, data.D.minute, data.D.second, data.D.day, data.D.month,data.D.year); + } + + return EXIT_SUCCESS; +} + diff --git a/apps/rp_venusGPS/gps_rp.c b/apps/rp_venusGPS/gps_rp.c new file mode 100644 index 0000000000000000000000000000000000000000..dfb8b16a95c6e71cde2b7fc4ab974069e774fd22 --- /dev/null +++ b/apps/rp_venusGPS/gps_rp.c @@ -0,0 +1,147 @@ +/* + * @brief This is a simple application for testing UART communication with a GPS + * connected to a RedPitaya + * + * @Author L. Horacio Arnaldi <lharnaldi@gmail.com> + * + * (c) LabDPR http://labdpr.cab.cnea.gov.ar + * + * This part of code is written in C programming language. + * Please visit http://en.wikipedia.org/wiki/C_(programming_language) + * for more details on the language used herein. + */ + +#include "gps_rp.h" +#include "nmea_rp.h" +#include "uart_rp.h" + +void gps_init(void) { + rp_UartInit(); + rp_UartConfig(); +} + +void gps_on(void) { +} + +// Compute the GPS location using decimal scale +void gps_location(loc_t *coord) { + uint8_t status = _EMPTY; + while(status != _COMPLETED) { + gpgga_t gpgga; + gprmc_t gprmc; + char buffer[256]; + + rp_UartReadln(buffer, 256); + switch (rp_NmeaGetMessageType(buffer)) { + case NMEA_GPGGA: + rp_NmeaParseGpgga(buffer, &gpgga); + + gps_convert_deg_to_dec(&(gpgga.latitude), gpgga.NS, &(gpgga.longitude), gpgga.EW); + + coord->latitude = gpgga.latitude; + coord->longitude = gpgga.longitude; + coord->height = gpgga.height; + + status |= NMEA_GPGGA; + break; + case NMEA_GPRMC: + rp_NmeaParseGprmc(buffer, &gprmc); + + gps_convert_deg_to_dec(&(gprmc.latitude), gprmc.NS, &(gprmc.longitude), gprmc.EW); + coord->latitude = gprmc.latitude; + coord->longitude = gprmc.longitude; + coord->height = gprmc.height; + coord->speed = gprmc.speed; + coord->course = gprmc.course; + coord->D.hour = gprmc.D.hour; + coord->D.minute = gprmc.D.minute; + coord->D.second = gprmc.D.second; + coord->D.day = gprmc.D.day; + coord->D.month = gprmc.D.month; + coord->D.year = gprmc.D.year; + + + status |= NMEA_GPRMC; + break; + } + } +} + +void gps_off(void) { + //Write off + rp_UartClose(); +} + +// Convert lat e lon to decimals (from deg) +void gps_convert_deg_to_dec(double *latitude, char ns, double *longitude, char we) +{ + double lat = (ns == 'N') ? *latitude : -1 * (*latitude); + double lon = (we == 'E') ? *longitude : -1 * (*longitude); + + *latitude = gps_deg_dec(lat); + *longitude = gps_deg_dec(lon); +} + +double gps_deg_dec(double deg_point) +{ + double ddeg; + double sec = modf(deg_point, &ddeg)*60; + int deg = (int)(ddeg/100); + int min = (int)(deg_point-(deg*100)); + + double absdlat = round(deg * 1000000.); + double absmlat = round(min * 1000000.); + double absslat = round(sec * 1000000.); + + return round(absdlat + (absmlat/60) + (absslat/3600)) /1000000; +} + +// GPS Parser ********************************************** + +// Example: $GPRMC,092741.00,A,5213.13757,N,00008.23605,E,0.272,,180617,,,A*7F +//char fmt[]="$GPRMC,dddtdd.ds,A,eeae.eeee,l,eeeae.eeee,o,jdk,c,dddy"; +// +//int state; +//unsigned int temp; +//long ltmp; +// +//// GPS variables +//volatile unsigned int Time, Csecs, Knots, Course, Date; +//volatile long Lat, Long; +//volatile boolean Fix; +// +//void ParseGPS (char c) { +// if (c == '$') { state = 0; temp = 0; ltmp = 0; } +// char mode = fmt[state++]; +// // If received character matches format string, return +// if (mode == c) return; +// char d = c - '0'; +// // Ignore extra digits of precision +// if (mode == ',') state--; +// // d=decimal digit; j=decimal digits before decimal point +// else if (mode == 'd') temp = temp*10 + d; +// else if (mode == 'j') { if (c != '.') { temp = temp*10 + d; state--; } } +// // e=long decimal digit +// else if (mode == 'e') ltmp = (ltmp<<3) + (ltmp<<1) + d; // ltmp = ltmp*10 + d; +// // a=angular measure +// else if (mode == 'a') ltmp = (ltmp<<2) + (ltmp<<1) + d; // ltmp = ltmp*6 + d; +// // t=Time - hhmm +// else if (mode == 't') { Time = temp*10 + d; temp = 0; } +// // s=Centisecs +// else if (mode == 's') { Csecs = temp*10 + d; temp = 0; } +// // l=Latitude - in minutes * 1e-4 +// else if (mode == 'l') { if (c == 'N') Lat = ltmp; else Lat = -ltmp; ltmp = 0; } +// // o=Longitude - in minutes * 1e-4 +// else if (mode == 'o') { if (c == 'E') Long = ltmp; else Long = -ltmp; ltmp = 0; } +// // k=Speed - in knots*100 +// else if (mode == 'k') { Knots = temp*10 + d; temp = 0; } +// // c=Course (Track) - in degrees*100. Allow for empty field. +// else if (mode == 'c') { +// if (c == ',') { Course = temp; temp = 0; state++; } +// else if (c == '.') state--; +// else { temp = temp*10 + d; state--; } +// } +// // y=Date - ddmm +// else if (mode == 'y') { Date = temp*10 + d ; Fix = 1; state = 0; } +// else state = 0; +//} diff --git a/apps/rp_venusGPS/gps_rp.h b/apps/rp_venusGPS/gps_rp.h new file mode 100644 index 0000000000000000000000000000000000000000..42e9deadc93a7d492d533f02896c28b78822ffd4 --- /dev/null +++ b/apps/rp_venusGPS/gps_rp.h @@ -0,0 +1,75 @@ +/** + * $Id: $ + * + * @brief GPS stuffs module. + * + * @Author L. Horacio Arnaldi <lharnaldi@gmail.com> + * + * (c) LabDPR http://labdpr.cab.cnea.gov.ar + * + * This part of code is written in C programming language. + * Please visit http://en.wikipedia.org/wiki/C_(programming_language) + * for more details on the language used herein. + */ + +#ifndef _GPS_RP_H_ +#define _GPS_RP_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +typedef struct{ + int year; + int month; + int day; + int hour; + int minute; + int second; +}DTIME; + + +typedef struct location { + //double gtime; + //double latitude; + //double longitude; + //double speed; + //double altitude; + //double course; + double latitude; // longitud + double longitude; // Latitud + int latitude_Degree; // grado + int latitude_Cent; // min + int latitude_Second; // segundos + int longitude_Degree; // grado + int longitude_Cent; // min + int longitude_Second; // segundos + float speed; // velocidad + float course; // rumbo + float height; // altitud + int satellite; + char NS; + char EW; + DTIME D; +} loc_t; + +// Initialize device +void gps_init(void); +// Activate device +void gps_on(void); +// Get the actual location +void gps_location(loc_t *); + + +// Turn off device (low-power consumption) +void gps_off(void); + +// ------------------------------------------------------------------------- +// Internal functions +// ------------------------------------------------------------------------- + +// convert deg to decimal deg latitude, (N/S), longitude, (W/E) +void gps_convert_deg_to_dec(double *, char, double *, char); +double gps_deg_dec(double); + +#endif diff --git a/apps/rp_venusGPS/nmea_rp.c b/apps/rp_venusGPS/nmea_rp.c new file mode 100644 index 0000000000000000000000000000000000000000..814f0436bbc980e668656eac10154e886d410635 --- /dev/null +++ b/apps/rp_venusGPS/nmea_rp.c @@ -0,0 +1,221 @@ +/* + * @brief This is a simple parser programm for NMEA messages + * + * @Author L. Horacio Arnaldi <lharnaldi@gmail.com> + * + * (c) LabDPR http://labdpr.cab.cnea.gov.ar + * + * This part of code is written in C programming language. + * Please visit http://en.wikipedia.org/wiki/C_(programming_language) + * for more details on the language used herein. + */ + +#include "nmea_rp.h" + +int rp_GetComma(char num, char* line){ + char *ptr = line; + int count = 0; + while ((count != num) && ((ptr = strstr(ptr, ",")) != NULL)) { + ptr += 1; + count++; + } + return ptr-line; +} + +int rp_NmeaParseGprmc(char *nmea, gprmc_t *GPS){ + uint8_t ch, status, tmp; + float lati_cent_tmp, lati_second_tmp; + float long_cent_tmp, long_second_tmp; + float speed_tmp=0; + char *buf = nmea; + ch = buf[5]; + status = buf[rp_GetComma(2, buf)]; + + GPS->NS = buf[rp_GetComma(4, buf)]; + GPS->EW = buf[rp_GetComma(6, buf)]; + + //GPS->latitude = Get_Double_Number(&buf[rp_GetComma(3, buf)]); + //GPS->longitude = Get_Double_Number(&buf[rp_GetComma(5, buf)]); + + GPS->latitude_Degree = (int)GPS->latitude / 100; // Latitud separada + lati_cent_tmp = (GPS->latitude - GPS->latitude_Degree * 100); + GPS->latitude_Cent = (int)lati_cent_tmp; + lati_second_tmp = (lati_cent_tmp - GPS->latitude_Cent) * 60; + GPS->latitude_Second = (int)lati_second_tmp; + + GPS->longitude_Degree = (int)GPS->longitude / 100; // Longitud separada + long_cent_tmp = (GPS->longitude - GPS->longitude_Degree * 100); + GPS->longitude_Cent = (int)long_cent_tmp; + long_second_tmp = (long_cent_tmp - GPS->longitude_Cent) * 60; + GPS->longitude_Second = (int)long_second_tmp; + + //speed_tmp = Get_Float_Number(&buf[rp_GetComma(7, buf)]); // Velocidad (unidad: milla náutica / hora) + GPS->speed = speed_tmp * 1.85; //1Millas náuticas =1.85Kilómetros + //GPS->direction = Get_Float_Number(&buf[rp_GetComma(8, buf)]); // ángulo + + GPS->D.hour = (buf[7] - '0') * 10 + (buf[8] - '0'); // Tiempo + GPS->D.minute = (buf[9] - '0') * 10 + (buf[10] - '0'); + GPS->D.second = (buf[11] - '0') * 10 + (buf[12] - '0'); + tmp = rp_GetComma(9, buf); + GPS->D.day = (buf[tmp + 0] - '0') * 10 + (buf[tmp + 1] - '0'); // fecha + GPS->D.month = (buf[tmp + 2] - '0') * 10 + (buf[tmp + 3] - '0'); + GPS->D.year = (buf[tmp + 4] - '0') * 10 + (buf[tmp + 5] - '0') + 2000; + + //UTC2BTC(&GPS->D); + + return 1; + //} + //} + + //return 0; + } + +void rp_NmeaParseGpgga(char *nmea, gpgga_t *loc){ + char *ptr = nmea; + + ptr = strchr(ptr, ',')+1; //skip time -> not valid now + //loc->gtime = atof(ptr); + + ptr = strchr(ptr, ',')+1; + loc->latitude = atof(ptr); + + ptr = strchr(ptr, ',')+1; + switch (ptr[0]) { + case 'N': + loc->NS = 'N'; + break; + case 'S': + loc->NS = 'S'; + break; + case ',': + loc->NS = '\0'; + break; + } + + ptr = strchr(ptr, ',')+1; + loc->longitude = atof(ptr); + + ptr = strchr(ptr, ',')+1; + switch (ptr[0]) { + case 'W': + loc->EW = 'W'; + break; + case 'E': + loc->EW = 'E'; + break; + case ',': + loc->EW = '\0'; + break; + } + + ptr = strchr(ptr, ',')+1; + loc->quality = (uint8_t)atoi(ptr); + + ptr = strchr(ptr, ',')+1; + loc->satellites = (uint8_t)atoi(ptr); + + ptr = strchr(ptr, ',')+1; + + ptr = strchr(ptr, ',')+1; + loc->height = atof(ptr); +} + +/* + void rp_NmeaParseGprmc(char *nmea, gprmc_t *loc){ + char *ptr = nmea; + +// GPS->D.hour = (buf[7] - '0') * 10 + (buf[8] - '0'); // Tiempo +// GPS->D.minute = (buf[9] - '0') * 10 + (buf[10] - '0'); +// GPS->D.second = (buf[11] - '0') * 10 + (buf[12] - '0'); +// tmp = rp_GetComma(9, buf); +// GPS->D.day = (buf[tmp + 0] - '0') * 10 + (buf[tmp + 1] - '0'); // fecha +// GPS->D.month = (buf[tmp + 2] - '0') * 10 + (buf[tmp + 3] - '0'); +// GPS->D.year = (buf[tmp + 4] - '0') * 10 + (buf[tmp + 5] - '0') + 2000; +ptr = strchr(ptr, ',')+1; //skip time +//loc->gtime = atof(ptr); +loc->D.hour = *(ptr-'0')*10 + *(ptr+1 - '0'); //(buf[7] - '0') * 10 + (buf[8] - '0'); // Tiempo +loc->D.minute = *(ptr+2 - '0')*10 + *(ptr+3 - '0'); //(buf[9] - '0') * 10 + (buf[10] - '0'); +loc->D.second = *(ptr+4 - '0')*10 + *(ptr+5 - '0'); //(buf[11] - '0') * 10 + (buf[12] - '0'); +ptr = strchr(ptr, ',')+1; //skip status + +ptr = strchr(ptr, ',')+1; +loc->latitude = atof(ptr); + +ptr = strchr(ptr, ',')+1; +switch (ptr[0]) { +case 'N': +loc->NS = 'N'; +break; +case 'S': +loc->NS = 'S'; +break; +case ',': +loc->NS = '\0'; +break; +} + +ptr = strchr(ptr, ',')+1; +loc->longitude = atof(ptr); + +ptr = strchr(ptr, ',')+1; +switch (ptr[0]) { +case 'W': +loc->EW = 'W'; +break; +case 'E': +loc->EW = 'E'; +break; +case ',': +loc->EW = '\0'; +break; +} + +ptr = strchr(ptr, ',')+1; +loc->speed = atof(ptr); + +ptr = strchr(ptr, ',')+1; +loc->course = atof(ptr); +}*/ + +/** + * Get the message type (GPGGA, GPRMC, etc..) + * + * This function filters out also wrong packages (invalid checksum) + * + * @param message The NMEA message + * @return The type of message if it is valid + */ +uint8_t rp_NmeaGetMessageType(const char *message){ + uint8_t checksum = 0; + if ((checksum = rp_NmeaValidChecksum(message)) != _EMPTY) { + return checksum; + } + + if (strstr(message, NMEA_GPGGA_STR) != NULL) { + return NMEA_GPGGA; + } + + if (strstr(message, NMEA_GPRMC_STR) != NULL) { + return NMEA_GPRMC; + } + + return NMEA_UNKNOWN; +} + +uint8_t rp_NmeaValidChecksum(const char *message) { + uint8_t checksum= (uint8_t)strtol(strchr(message, '*')+1, NULL, 16); + + char p; + uint8_t sum = 0; + ++message; + while ((p = *message++) != '*') { + sum ^= p; + } + + if (sum != checksum) { + return NMEA_CHECKSUM_ERR; + } + + return _EMPTY; +} + diff --git a/apps/rp_venusGPS/nmea_rp.h b/apps/rp_venusGPS/nmea_rp.h new file mode 100644 index 0000000000000000000000000000000000000000..5838b08e5e57762592b3955315df628c5e564fad --- /dev/null +++ b/apps/rp_venusGPS/nmea_rp.h @@ -0,0 +1,104 @@ +/** + * $Id: $ + * + * @brief GPS NMEA messages parser. + * + * @Author L. Horacio Arnaldi <lharnaldi@gmail.com> + * + * (c) LabDPR http://labdpr.cab.cnea.gov.ar + * + * This part of code is written in C programming language. + * Please visit http://en.wikipedia.org/wiki/C_(programming_language) + * for more details on the language used herein. + */ + +#ifndef _NMEA_RP_H_ +#define _NMEA_RP_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include <string.h> +#include <math.h> + +#define _EMPTY 0x00 +#define NMEA_GPRMC 0x01 +#define NMEA_GPRMC_STR "$GPRMC" +#define NMEA_GPGGA 0x02 +#define NMEA_GPGGA_STR "$GPGGA" +#define NMEA_UNKNOWN 0x00 +#define _COMPLETED 0x03 + +#define NMEA_CHECKSUM_ERR 0x80 +#define NMEA_MESSAGE_ERR 0xC0 + +typedef struct{ + int year; + int month; + int day; + int hour; + int minute; + int second; +}DATE_TIME; + +//typedef struct gdata{ +// double latitude; // longitud +// double longitude; // Latitud +// int latitude_Degree; // grado +// int latitude_Cent; // min +// int latitude_Second; // segundos +// int longitude_Degree; // grado +// int longitude_Cent; // min +// int longitude_Second; // segundos +// float speed; // velocidad +// float direction; // rumbo +// float height; // altitud +// int satellite; +// uint8_t NS; +// uint8_t EW; +// DATE_TIME D; +//}GPS_INFO; + +typedef struct gpgga { + double gtime; + double latitude; + double longitude; + uint8_t quality; + uint8_t satellites; + float height; // altitud + char NS; + char EW; +} gpgga_t; + +typedef struct gprmc { + //double gtime; + //double latitude; + //char lat; + //double longitude; + //char lon; + //double speed; + //double course; + double latitude; // longitud + double longitude; // Latitud + int latitude_Degree; // grado + int latitude_Cent; // min + int latitude_Second; // segundos + int longitude_Degree; // grado + int longitude_Cent; // min + int longitude_Second; // segundos + float speed; // velocidad + float course; // rumbo + float height; // altitud + int satellite; + char NS; + char EW; + DATE_TIME D; +} gprmc_t; + +uint8_t rp_NmeaGetMessageType(const char *); +uint8_t rp_NmeaValidChecksum(const char *); +void rp_NmeaParseGpgga(char *, gpgga_t *); +int rp_NmeaParseGprmc(char *, gprmc_t *); + +#endif + diff --git a/apps/rp_venusGPS/uart_rp.c b/apps/rp_venusGPS/uart_rp.c new file mode 100644 index 0000000000000000000000000000000000000000..51e04f610fdb5b75aa480ff3417944990f78667b --- /dev/null +++ b/apps/rp_venusGPS/uart_rp.c @@ -0,0 +1,92 @@ +/* + * @brief This is a simple application for testing UART + * communication with a GPS connected to a RedPitaya + * + * @Author L. Horacio Arnaldi <lharnaldi@gmail.com> + * + * (c) LabDPR http://labdpr.cab.cnea.gov.ar + * + * This part of code is written in C programming language. + * Please visit http://en.wikipedia.org/wiki/C_(programming_language) + * for more details on the language used herein. + */ + +#include "uart_rp.h" + +/* File descriptor definition */ +int uart_fd = -1; + +int rp_UartInit(void) +{ + uart_fd = open(PORTNAME, O_RDWR | O_NOCTTY | O_NDELAY); + + if(uart_fd == -1){ + fprintf(stderr, "Failed to open uart.\n"); + return -1; + } + return 0; +} + +void rp_UartConfig(void) +{ + struct termios options; + tcgetattr(uart_fd, &options); + /*Configure the UART + see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html */ + options.c_cflag = B9600 | CS8 | CLOCAL | CREAD; + options.c_iflag = IGNPAR; + options.c_oflag = 0; + options.c_lflag = 0; + /* Setting attributes */ + tcflush(uart_fd, TCIFLUSH); + tcsetattr(uart_fd, TCSANOW, &options); +} + +int rp_UartPrintln(const char *line, int len) +{ + if (uart_fd != -1) { + char *cpstr = (char *)malloc((len+1) * sizeof(char)); + strcpy(cpstr, line); + cpstr[len-1] = '\r'; + cpstr[len] = '\n'; + + int count = write(uart_fd, cpstr, len+1); + if (count < 0) { + fprintf(stderr, "UART TX error.\n"); + return -1; + } + free(cpstr); + } + return 0; +} + +/* Read a line from UART */ +int rp_UartReadln(char *buffer, int len) +{ + char c; + char *b = buffer; + int rx_length = -1; + + while(1) { + rx_length = read(uart_fd, (void*)(&c), 1); + + if (rx_length <= 0) { + //wait for messages + sleep(1); + } else { + if (c == '\n') { + *b++ = '\0'; + break; + } + *b++ = c; + } + } + return 0; +} + +void rp_UartClose(void) +{ + tcflush(uart_fd, TCIFLUSH); + close(uart_fd); +} + diff --git a/apps/rp_venusGPS/uart_rp.h b/apps/rp_venusGPS/uart_rp.h new file mode 100644 index 0000000000000000000000000000000000000000..b7098cfd0e8538c78fc8832b664a02b85d09ead5 --- /dev/null +++ b/apps/rp_venusGPS/uart_rp.h @@ -0,0 +1,40 @@ +/** + * $Id: $ + * + * @brief UART communication module for the STEMLab RedPitaya board (tested with + * the 14-bit version). + * + * @Author L. Horacio Arnaldi <lharnaldi@gmail.com> + * + * (c) LabDPR http://labdpr.cab.cnea.gov.ar + * + * This part of code is written in C programming language. + * Please visit http://en.wikipedia.org/wiki/C_(programming_language) + * for more details on the language used herein. + */ + +#ifndef _UART_RP_H_ +#define _UART_RP_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <termios.h> +#include <inttypes.h> +#include <string.h> + +#include <inttypes.h> + +//Default name for UART port in E2 expansion conector +#ifndef PORTNAME +#define PORTNAME "/dev/ttyPS1" +#endif + +int rp_UartInit(void); +void rp_UartConfig(void); +int rp_UartPrintln(const char *, int); +int rp_UartReadln(char *, int); +void rp_UartClose(void); + +#endif