summaryrefslogtreecommitdiffstats
path: root/bcm4751_gpsd.c
diff options
context:
space:
mode:
Diffstat (limited to 'bcm4751_gpsd.c')
-rw-r--r--bcm4751_gpsd.c294
1 files changed, 294 insertions, 0 deletions
diff --git a/bcm4751_gpsd.c b/bcm4751_gpsd.c
new file mode 100644
index 0000000..5072751
--- /dev/null
+++ b/bcm4751_gpsd.c
@@ -0,0 +1,294 @@
+/**
+ * This file is part of BCM4751 gpsd
+ *
+ * Copyright (C) 2011 Paul Kocialkowski <contact@oaulk.fr>
+ *
+ * BCM4751 gpsd is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * BCM4751 gpsd is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with BCM4751 gpsd. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <termios.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "meif.h"
+
+/*
+ * Utils
+ */
+
+void hex_dump(void *data, int size)
+{
+ /* dumps size bytes of *data to stdout. Looks like:
+ * [0000] 75 6E 6B 6E 6F 77 6E 20
+ * 30 FF 00 00 00 00 39 00 unknown 0.....9.
+ * (in a single line of course)
+ */
+
+ unsigned char *p = data;
+ unsigned char c;
+ int n;
+ char bytestr[4] = {0};
+ char addrstr[10] = {0};
+ char hexstr[ 16*3 + 5] = {0};
+ char charstr[16*1 + 5] = {0};
+ for(n=1;n<=size;n++) {
+ if (n%16 == 1) {
+ /* store address for this line */
+ snprintf(addrstr, sizeof(addrstr), "%.4x",
+ ((unsigned int)p-(unsigned int)data) );
+ }
+
+ c = *p;
+ if (isalnum(c) == 0) {
+ c = '.';
+ }
+
+ /* store hex str (for left side) */
+ snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
+ strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1);
+
+ /* store char str (for right side) */
+ snprintf(bytestr, sizeof(bytestr), "%c", c);
+ strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1);
+
+ if(n%16 == 0) {
+ /* line completed */
+ printf("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
+ hexstr[0] = 0;
+ charstr[0] = 0;
+ } else if(n%8 == 0) {
+ /* half line: add whitespaces */
+ strncat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1);
+ strncat(charstr, " ", sizeof(charstr)-strlen(charstr)-1);
+ }
+ p++; /* next byte */
+ }
+
+ if (strlen(hexstr) > 0) {
+ /* print rest of buffer if not empty */
+ printf("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
+ }
+}
+
+/*
+ * SEC
+ */
+
+int sec_gps_power(int power)
+{
+ char gpio_power_path[] = "/sys/class/sec/gps/GPS_PWR_EN/value";
+ char gpio_on_value[] = "1\n";
+ char gpio_off_value[] = "0\n";
+ int fd = -1;
+ int rc;
+
+ fd = open(gpio_power_path, O_RDWR);
+ if(fd < 0)
+ return -1;
+
+ if(power) {
+ rc = write(fd, gpio_on_value, strlen(gpio_on_value));
+ } else {
+ rc = write(fd, gpio_off_value, strlen(gpio_off_value));
+ }
+
+ if(rc <= 0) {
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ usleep(250000);
+
+ return 0;
+}
+
+int sec_gps_reset(int value)
+{
+ char gpio_reset_path[] = "/sys/class/sec/gps/GPS_nRST/value";
+ char gpio_on_value[] = "1\n";
+ char gpio_off_value[] = "0\n";
+ int fd = -1;
+ int rc;
+
+ fd = open(gpio_reset_path, O_RDWR);
+ if(fd < 0)
+ return -1;
+
+ if(value) {
+ rc = write(fd, gpio_on_value, strlen(gpio_on_value));
+ } else {
+ rc = write(fd, gpio_off_value, strlen(gpio_off_value));
+ }
+
+ if(rc <= 0) {
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ usleep(250000);
+
+ return 0;
+}
+
+/*
+ * BCM4751
+ */
+
+int bcm4751_serial_open(void)
+{
+ struct termios termios;
+ int fd = -1;
+
+ // TODO: add more checks
+
+ fd = open("/dev/s3c2410_serial1", O_RDWR|O_NOCTTY|O_NONBLOCK);
+ if(fd < 0)
+ return -1;
+
+ tcgetattr(fd, &termios);
+
+ // Flush
+ ioctl(fd, TCFLSH, 0x2);
+
+ cfmakeraw(&termios);
+ cfsetispeed(&termios, B115200);
+ cfsetospeed(&termios, B115200);
+
+ // This is the magic to contact the chip
+ termios.c_cflag = 0x800018b2;
+
+ tcsetattr(fd, TCSANOW, &termios);
+
+ // Flush
+ ioctl(fd, TCFLSH, 0x2);
+
+ return fd;
+}
+
+int bcm4751_serial_read(int fd, void *data, int length, struct timeval *timeout)
+{
+ fd_set fds;
+ int rc = -1;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ rc = select(fd + 1, &fds, NULL, NULL, timeout);
+ if(rc > 0 && length > 0) {
+ rc = read(fd, data, length);
+ }
+
+ return rc;
+}
+
+int bcm4751_serial_write(int fd, void *data, int length, struct timeval *timeout)
+{
+ fd_set fds;
+ int rc = -1;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ rc = select(fd + 1, NULL, &fds, NULL, timeout);
+ if(rc > 0) {
+ rc = write(fd, data, length);
+ }
+
+ return rc;
+}
+
+int bcm4751_autobaud(int fd)
+{
+ struct timeval timeout;
+ uint8_t autobaud[20] = { 0x80 };
+ int ready = 0;
+ int rc = -1;
+
+ // TODO: limit the number of attempts
+
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+
+ while(!ready) {
+ bcm4751_serial_write(fd, autobaud, sizeof(autobaud), NULL);
+
+ rc = bcm4751_serial_read(fd, NULL, 0, &timeout);
+ if(rc > 0)
+ ready = 1;
+ }
+
+ return 0;
+}
+
+void bcm4751_read_dump(int fd)
+{
+ void *data = NULL;
+ int length = 0x100;
+ int rc = -1;
+
+ data = malloc(length);
+
+ while(1) {
+ rc = bcm4751_serial_read(fd, data, length, NULL);
+ if(rc > 0) {
+ printf("Read %d bytes:\n", rc);
+ hex_dump(data, rc);
+ } else {
+ free(data);
+ return;
+ }
+ }
+}
+
+int main(void)
+{
+ int fd = -1;
+ int rc = -1;
+
+ printf("Turning the GPS on...\n");
+ rc = sec_gps_power(1);
+ if(rc < 0) {
+ printf("Failed to turn the GPS on!\n");
+ return 1;
+ }
+
+ printf("Opening the GPS serial...\n");
+ fd = bcm4751_serial_open();
+ if(fd < 0) {
+ printf("Failed to open the GPS serial!\n");
+ return 1;
+ }
+
+ printf("Sending autobaud...\n");
+ rc = bcm4751_autobaud(fd);
+ if(fd < 0) {
+ printf("Failed to send autobaud!\n");
+ return 1;
+ }
+
+ bcm4751_read_dump(fd);
+
+ return 0;
+}