├── config.h.in ├── runboth.sh ├── .gitignore ├── daemons ├── init.d │ └── startAIS └── network │ └── if-up.d │ └── startAIS ├── LICENSE.md ├── src ├── lib │ ├── winmmaudio │ │ ├── winmm_input.h │ │ └── winmm_input.c │ ├── callbacks.h │ ├── alsaaudio │ │ ├── alsaaudio.h │ │ └── alsaaudio.c │ ├── pulseaudio │ │ ├── pulseaudio.h │ │ └── pulseaudio.c │ ├── hmalloc.h │ ├── receiver.h │ ├── hmalloc.c │ ├── protodec.h │ ├── filter.h │ ├── filter.c │ ├── receiver.c │ ├── filter-i386.h │ └── protodec.c ├── sounddecoder.h ├── main.h ├── sounddecoder.c └── main.c ├── .project ├── rtlsdr ├── rtl-sdr_export.h └── rtl-sdr.h ├── CMakeLists.txt ├── README.md ├── .cproject └── .settings └── org.eclipse.cdt.codan.core.prefs /config.h.in: -------------------------------------------------------------------------------- 1 | #cmakedefine PROJECT_NAME "${PROJECT_NAME}" 2 | #cmakedefine HAVE_ALSA 3 | #cmakedefine HAVE_PULSEAUDIO 4 | -------------------------------------------------------------------------------- /runboth.sh: -------------------------------------------------------------------------------- 1 | ./aiswatcher -p 7004 -h boatbeaconapp.com -t 1 -P 63 -d -G 1000 -f /tmp/aisdata 2 | ./aiswatcher -p 7004 -h boatbeaconapp.com -D 1 -F 162025000 -t 1 -P 63 -d -G 1000 -f /tmp/aisdata 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.out 3 | aisdecoder 4 | testfiles/*.bin 5 | misc 6 | frames.js 7 | .*.swp 8 | Binaries/*build/libaisdecoder.1.0.0.dylib 9 | build/libaisdecoder.1.dylib 10 | build/libaisdecoder.dylib 11 | build/libaisdecoder.a 12 | build/CMakeFiles/* 13 | build 14 | -------------------------------------------------------------------------------- /daemons/init.d/startAIS: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # chkconfig: 345 99 10 3 | # description: auto start AIS receiver 4 | # 5 | case "$1" in 6 | 'start') 7 | su - root -c "cd /root/Development/aiswatcher/build ; sh runboth.sh > /var/log/ais.log 2> /var/log/ais_error.log &";; 8 | 'stop') 9 | echo "put something to shutdown or kill the process here";; 10 | esac 11 | -------------------------------------------------------------------------------- /daemons/network/if-up.d/startAIS: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Try to bring nmbd up when an interface comes up, if smbd is already running. 3 | # Don't bother to do anything for lo. 4 | set -e 5 | 6 | # Don't bother to restart sshd when lo is configured. 7 | if [ "$IFACE" != eth0 ]; then 8 | exit 0 9 | fi 10 | if [ "$PHASE" != post-up ]; then 11 | exit 0 12 | fi 13 | 14 | # start the service 15 | /etc/init.d/startAIS start 16 | 17 | exit 0 18 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 2 | Pocket Mariner Ltd and Astra Paging Ltd / AISHub (info@aishub.net) 3 | * 4 | * AISDecoder is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * AISDecoder uses parts of GNUAIS project (http://gnuais.sourceforge.net/) 10 | -------------------------------------------------------------------------------- /src/lib/winmmaudio/winmm_input.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //#ifdef EXTENSIBLE 6 | #define WAVE_BUFFERS 4 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | int winmm_init(unsigned int devId, 13 | LPHWAVEIN device, 14 | int channels, 15 | int bytesCount, 16 | HANDLE *eventHandler); 17 | 18 | int winmm_getRecorded(LPHWAVEIN device, char *out); 19 | void winmm_cleanup(LPHWAVEIN device, HANDLE *eventHandler); 20 | 21 | #ifdef __cplusplus 22 | } 23 | #endif 24 | -------------------------------------------------------------------------------- /src/lib/callbacks.h: -------------------------------------------------------------------------------- 1 | #ifndef CALLBACKS_H 2 | #define CALLBACKS_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | typedef void (*receiver_on_level_changed)(float level, int channel, unsigned char high); 9 | typedef void (*decoder_on_nmea_sentence_received)(const char *sentence, 10 | unsigned int length, 11 | unsigned char sentences, 12 | unsigned char sentencenum); 13 | 14 | extern receiver_on_level_changed on_sound_level_changed; 15 | extern decoder_on_nmea_sentence_received on_nmea_sentence_received; 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | #endif // CALLBACKS_H 21 | -------------------------------------------------------------------------------- /src/sounddecoder.h: -------------------------------------------------------------------------------- 1 | #ifndef SOUNDDECODER_H 2 | #define SOUNDDECODER_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | typedef enum { 9 | SOUND_CHANNELS_MONO, 10 | SOUND_CHANNELS_STEREO, 11 | SOUND_CHANNELS_LEFT, 12 | SOUND_CHANNELS_RIGHT 13 | } Sound_Channels; 14 | 15 | typedef enum { 16 | #ifdef HAVE_ALSA 17 | DRIVER_ALSA, 18 | #endif 19 | #ifdef HAVE_PULSEAUDIO 20 | DRIVER_PULSE, 21 | #endif 22 | #ifdef WIN32 23 | DRIVER_WINMM, 24 | #endif 25 | DRIVER_FILE 26 | } Sound_Driver; 27 | 28 | extern char errorSoundDecoder[]; 29 | 30 | 31 | int initSoundDecoder(const Sound_Channels _channels, const Sound_Driver _driver, const char *file); 32 | 33 | void runSoundDecoder(int *stop); 34 | void freeSoundDecoder(); 35 | 36 | #ifdef __cplusplus 37 | } 38 | #endif 39 | #endif // SOUNDDECODER_H 40 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | aisdecoder-1.0.0 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.aptana.projects.webnature 23 | org.eclipse.cdt.core.cnature 24 | org.eclipse.cdt.core.ccnature 25 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 26 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/lib/alsaaudio/alsaaudio.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * input.h 4 | * 5 | * (c) Ruben Undheim 2008 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #ifndef INC_INPUT_H 23 | #define INC_INPUT_H 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | int input_initialize(snd_pcm_t * handle, short **, int *, int channels_num, char *error_msg); 34 | int alsa_read(snd_pcm_t * handle, short *buffer, int count); 35 | void input_cleanup(snd_pcm_t *handle); 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | #endif 41 | -------------------------------------------------------------------------------- /src/lib/pulseaudio/pulseaudio.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * pulseaudio.h 4 | * 5 | * (c) Ruben Undheim 2012 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #ifndef INC_PULSEAUDIO_H 23 | #define INC_PULSEAUDIO_H 24 | 25 | #include 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | pa_simple *pulseaudio_initialize(unsigned char channels_number, const char *appname); 31 | 32 | void pulseaudio_cleanup(pa_simple *s); 33 | 34 | int pulseaudio_read(pa_simple *s, short *buffer, int count, unsigned char channels_number); 35 | 36 | #ifdef __cplusplus 37 | } 38 | #endif 39 | #endif /* INC_PULSEAUDIO_H */ 40 | -------------------------------------------------------------------------------- /src/lib/hmalloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Heikki Hannikainen, OH7LZB 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | * 18 | */ 19 | 20 | #ifndef HMALLOC_H 21 | #define HMALLOC_H 22 | 23 | #include 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* 29 | * Replacements for malloc, realloc and free, which never fail, 30 | * and might keep statistics on memory allocation... 31 | */ 32 | 33 | extern void *hmalloc(size_t size); 34 | extern void *hrealloc(void *ptr, size_t size); 35 | extern void hfree(void *ptr); 36 | 37 | extern char *hstrdup(const char *s); 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | #endif 42 | 43 | -------------------------------------------------------------------------------- /rtlsdr/rtl-sdr_export.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver 3 | * Copyright (C) 2012 by Hoernchen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef RTLSDR_EXPORT_H 20 | #define RTLSDR_EXPORT_H 21 | 22 | #if defined __GNUC__ 23 | # if __GNUC__ >= 4 24 | # define __SDR_EXPORT __attribute__((visibility("default"))) 25 | # define __SDR_IMPORT __attribute__((visibility("default"))) 26 | # else 27 | # define __SDR_EXPORT 28 | # define __SDR_IMPORT 29 | # endif 30 | #elif _MSC_VER 31 | # define __SDR_EXPORT __declspec(dllexport) 32 | # define __SDR_IMPORT __declspec(dllimport) 33 | #else 34 | # define __SDR_EXPORT 35 | # define __SDR_IMPORT 36 | #endif 37 | 38 | #ifndef rtlsdr_STATIC 39 | # ifdef rtlsdr_EXPORTS 40 | # define RTLSDR_API __SDR_EXPORT 41 | # else 42 | # define RTLSDR_API __SDR_IMPORT 43 | # endif 44 | #else 45 | #define RTLSDR_API 46 | #endif 47 | #endif /* RTLSDR_EXPORT_H */ 48 | -------------------------------------------------------------------------------- /src/lib/receiver.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * receiver.h 4 | * 5 | * (c) Ruben Undheim 2008 6 | * (c) Heikki Hannikainen 2008 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 | */ 22 | 23 | 24 | #ifndef INC_RECEIVER_H 25 | #define INC_RECEIVER_H 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "protodec.h" 36 | #include "callbacks.h" 37 | 38 | struct receiver { 39 | struct filter *filter; 40 | char name; 41 | int lastbit; 42 | int num_ch; 43 | int ch_ofs; 44 | unsigned int pll; 45 | unsigned int pllinc; 46 | struct demod_state_t *decoder; 47 | int prev; 48 | time_t last_levellog; 49 | }; 50 | 51 | extern struct receiver *init_receiver(char name, int num_ch, int ch_ofs); 52 | extern void free_receiver(struct receiver *rx); 53 | 54 | extern void receiver_run(struct receiver *rx, short *buf, int len); 55 | 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | #endif 60 | -------------------------------------------------------------------------------- /src/lib/pulseaudio/pulseaudio.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * pulseaudio.c 4 | * 5 | * (c) Ruben Undheim 2012 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | 23 | #include 24 | #include 25 | #include 26 | #include "pulseaudio.h" 27 | 28 | pa_simple *pulseaudio_initialize(unsigned char channels_number, const char *appname) { 29 | 30 | pa_simple *s; 31 | pa_sample_spec ss; 32 | 33 | ss.format = PA_SAMPLE_S16NE; 34 | ss.channels = channels_number; 35 | ss.rate = 48000; 36 | 37 | s = pa_simple_new(NULL, 38 | (appname != NULL) ? appname : "AIS Demodulator", 39 | PA_STREAM_RECORD, NULL, "AIS data", &ss, NULL, NULL, NULL); 40 | 41 | return s; 42 | } 43 | 44 | 45 | void pulseaudio_cleanup(pa_simple *s){ 46 | pa_simple_free(s); 47 | } 48 | 49 | int pulseaudio_read(pa_simple *s, short *buffer, int count, unsigned char channels_number){ 50 | int number_read = pa_simple_read(s, buffer, (size_t)(count * sizeof(short) * channels_number), NULL); 51 | return (number_read < 0) ? -1 : count; 52 | } 53 | -------------------------------------------------------------------------------- /src/lib/hmalloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * (c) Heikki Hannikainen, OH7LZB 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | * 18 | */ 19 | 20 | /* 21 | * Replacements for malloc, realloc and free, which never fail, 22 | * and might keep statistics on memory allocation... 23 | * 24 | * GPL'ed, by Heikki Hannikainen 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "hmalloc.h" 32 | 33 | #ifdef DMALLOC 34 | #include 35 | #endif 36 | 37 | int mem_panic = 0; 38 | 39 | void *hmalloc(size_t size) { 40 | void *p; 41 | if (!(p = malloc(size))) { 42 | if (mem_panic) exit(1); 43 | mem_panic = 1; 44 | exit(1); 45 | } 46 | 47 | return p; 48 | } 49 | 50 | void *hrealloc(void *ptr, size_t size) { 51 | void *p; 52 | 53 | if (!(p = realloc(ptr, size))) { 54 | if (mem_panic) exit(1); 55 | mem_panic = 1; 56 | exit(1); 57 | } 58 | 59 | return p; 60 | } 61 | 62 | void hfree(void *ptr) { 63 | if (ptr) free(ptr); 64 | } 65 | 66 | char *hstrdup(const char *s) { 67 | char *p; 68 | 69 | p = (char*)hmalloc(strlen(s)+1); 70 | strcpy(p, s); 71 | 72 | return p; 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/lib/protodec.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * protodec.h 4 | * 5 | * (c) Ruben Undheim 2008 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | 23 | #ifndef INC_PROTODEC_H 24 | #define INC_PROTODEC_H 25 | 26 | #define ST_SKURR 1 27 | #define ST_PREAMBLE 2 28 | #define ST_STARTSIGN 3 29 | #define ST_DATA 4 30 | #define ST_STOPSIGN 5 31 | 32 | #define DEMOD_BUFFER_LEN 450 33 | #define MAX_AIS_PACKET_TYPE 27 34 | #define NMEABUFFER_LEN 100 35 | 36 | struct demod_state_t { 37 | char chanid; 38 | int state; 39 | unsigned int offset; 40 | int nskurr, npreamble, nstartsign, ndata, nstopsign; 41 | 42 | int antallenner; 43 | unsigned char *buffer; 44 | unsigned char *rbuffer; 45 | char *tbuffer; 46 | int bufferpos; 47 | char last; 48 | int antallpreamble; 49 | int bitstuff; 50 | int receivedframes; 51 | int lostframes; 52 | int lostframes2; 53 | unsigned char seqnr; 54 | 55 | struct serial_state_t *serial; 56 | 57 | char *nmea; 58 | }; 59 | 60 | void protodec_initialize(struct demod_state_t *d, struct serial_state_t *serial, char chanid); 61 | void protodec_reset(struct demod_state_t *d); 62 | void protodec_getdata(int bufferlengde, struct demod_state_t *d); 63 | void protodec_decode(char *in, int count, struct demod_state_t *d); 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /src/main.h: -------------------------------------------------------------------------------- 1 | #ifndef __MAIN_H 2 | #define __MAIN_H 3 | 4 | 5 | // ============================= Include files ========================== 6 | 7 | 8 | #include "stdio.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "rtl-sdr.h" 24 | 25 | #define MODES_DEFAULT_PPM 52 26 | #define MODES_DEFAULT_RATE 48000 27 | #define MODES_DEFAULT_FREQ 161975000 //2nd ais frequency 162025000 28 | #define MODES_DEFAULT_WIDTH 1000 29 | #define MODES_DEFAULT_HEIGHT 700 30 | #define MODES_ASYNC_BUF_NUMBER 16 31 | #define MODES_ASYNC_BUF_SIZE (16*16384) // 256k 32 | #define MODES_ASYNC_BUF_SAMPLES (MODES_ASYNC_BUF_SIZE / 2) // Each sample is 2 bytes 33 | #define MODES_AUTO_GAIN -100 // Use automatic gain 34 | #define MODES_MAX_GAIN 999999 // Use max available gain 35 | #define MODES_MSG_SQUELCH_LEVEL 0x02FF // Average signal strength limit 36 | #define MODES_MSG_ENCODER_ERRS 3 // Maximum number of encoding errors 37 | 38 | // Program global state 39 | struct { // Internal state 40 | 41 | //rtl_fm -f 161975000 -g 40 -p 95 -s 48k -r 48k /tmp/aisdata 42 | // RTLSDR 43 | int dev_index; 44 | int gain; 45 | int enable_agc; 46 | int freq; 47 | int ppm_error; 48 | 49 | // Configuration 50 | char *filename; // Input form file, --ifile option 51 | 52 | } Modes; 53 | 54 | 55 | void run_rtl_fm(char **my_args); 56 | int openTcpSocket(const char *host, const char *portname); 57 | void modesInitConfig(); 58 | int verbose_device_search(char *s); 59 | void modesInitRTLSDR(void); 60 | int openSerialOut(); 61 | #endif 62 | -------------------------------------------------------------------------------- /src/lib/filter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * filter.h -- FIR filter 3 | * 4 | * Copyright (C) 2001, 2002, 2003, 2004 5 | * Tomi Manninen (oh2bns@sral.fi) 6 | * 7 | * This file is part of gMFSK. 8 | * 9 | * gMFSK is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * gMFSK is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with gMFSK; if not, write to the Free Software 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 | * 23 | */ 24 | 25 | #ifndef _FILTER_H 26 | #define _FILTER_H 27 | 28 | #define BufferLen 1024 29 | 30 | /* ---------------------------------------------------------------------- */ 31 | 32 | #ifdef __OPTIMIZE__ 33 | 34 | #ifdef __i386__ 35 | #include "filter-i386.h" 36 | #endif /* __i386__ */ 37 | 38 | 39 | #ifndef __HAVE_ARCH_MAC 40 | static __inline__ float filter_mac(const float *a, const float *b, int size) 41 | { 42 | float sum = 0; 43 | int i; 44 | 45 | for (i = 0; i < size; i++) 46 | sum += a[i] * b[i]; 47 | 48 | return sum; 49 | } 50 | #endif /* __HAVE_ARCH_MAC */ 51 | 52 | #endif /* __OPTIMIZE__ */ 53 | 54 | 55 | /* ---------------------------------------------------------------------- */ 56 | 57 | struct filter { 58 | int length; 59 | float *taps; 60 | float buffer[BufferLen]; 61 | int pointer; 62 | }; 63 | 64 | extern struct filter *filter_init(int len, float *taps); 65 | extern void filter_free(struct filter *f); 66 | 67 | extern void filter_run(struct filter *f, float in, float *out); 68 | extern short filter_run_buf(struct filter *f, short *in, float *out, int step, int len); 69 | 70 | /* ---------------------------------------------------------------------- */ 71 | 72 | #endif /* _FILTER_H */ 73 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(aiswatcher) 2 | cmake_minimum_required(VERSION 2.8) 3 | INCLUDE(CheckIncludeFiles) 4 | 5 | set(STATIC_LIB "${PROJECT_NAME}_static_lib") 6 | set(DYNAMIC_LIB "${PROJECT_NAME}_dynamic_lib") 7 | 8 | macro(get_WIN32_WINNT version) 9 | if (WIN32 AND CMAKE_SYSTEM_VERSION) 10 | set(ver ${CMAKE_SYSTEM_VERSION}) 11 | string(REPLACE "." "" ver ${ver}) 12 | string(REGEX REPLACE "([0-9])" "0\\1" ver ${ver}) 13 | set(${version} "0x${ver}") 14 | endif() 15 | endmacro() 16 | 17 | 18 | 19 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) 20 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) 21 | 22 | if("${CMAKE_BUILD_TYPE}" STREQUAL "") 23 | set(CMAKE_BUILD_TYPE "Debug") 24 | endif() 25 | 26 | if(NOT $ENV{CMAKE_BUILD_TYPE} STREQUAL "") 27 | set(CMAKE_BUILD_TYPE $ENV{CMAKE_BUILD_TYPE}) 28 | endif() 29 | 30 | string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE) 31 | MESSAGE(STATUS "Build configuration: ${CMAKE_BUILD_TYPE}") 32 | 33 | set(CMAKE_C_FLAGS_DEBUG "-g -Wall") 34 | set(CMAKE_C_FLAGS_RELEASE "-O3 -Wall") 35 | 36 | if(${CMAKE_BUILD_TYPE} STREQUAL "RELEASE") 37 | set(CMAKE_EXE_LINKER_FLAGS "-s") 38 | endif() 39 | 40 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/lib) 41 | 42 | aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST) 43 | set(SRC_LIST_LIB "${CMAKE_CURRENT_SOURCE_DIR}/src/sounddecoder.c") 44 | aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src/lib SRC_LIST_LIB) 45 | 46 | 47 | add_library(${DYNAMIC_LIB} SHARED ${SRC_LIST_LIB}) 48 | set_target_properties(${DYNAMIC_LIB} PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) 49 | 50 | add_library(${STATIC_LIB} STATIC ${SRC_LIST_LIB}) 51 | set_target_properties(${STATIC_LIB} PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) 52 | 53 | 54 | set(MYLIB_VERSION_MAJOR 1) 55 | set(MYLIB_VERSION_MINOR 0) 56 | set(MYLIB_VERSION_PATCH 0) 57 | set(MYLIB_VERSION_STRING ${MYLIB_VERSION_MAJOR}.${MYLIB_VERSION_MINOR}.${MYLIB_VERSION_PATCH}) 58 | set_target_properties(${DYNAMIC_LIB} 59 | PROPERTIES 60 | VERSION ${MYLIB_VERSION_STRING} 61 | SOVERSION ${MYLIB_VERSION_MAJOR}) 62 | 63 | 64 | add_executable(${PROJECT_NAME} ${SRC_LIST}) 65 | target_link_libraries(${PROJECT_NAME} ${STATIC_LIB}) 66 | 67 | 68 | target_link_libraries(${PROJECT_NAME} ${L_ALSA} ${L_PULSE}) 69 | 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | aiswatcher 2 | ========== 3 | Displays live ship positions on a google map from ships' AIS vhf radio broadcasts. 4 | 5 | AisWatcher builds and runs on most linux platfroms including BeagleBone, Raspberry Pi and Mac together with a RTL2832U (RTL SDR usb stick). 6 | 7 | See http://www.rtl-sdr.com/buy-rtl-sdr-dvb-t-dongles/ for the radio usb stick. 8 | 9 | AisWatcher decodes the radio data and converts it to AIS ascii data strings. You can dump the strings to the console and also forward them to the BoatBeaconApp.com server to display on a live map view and in the free Boat Watch apps, available for iPhone, iPad, Mac and Android. 10 | 11 | This code is based on a rework of aisdecoder from aishub.net (http://forum.aishub.net/ais-decoder/ais-decoder-beta-release/) 12 | to include rtl-sdr (http://sdr.osmocom.org/trac/wiki/rtl-sdr) to run as a single command and diplay ships live on a google map. 13 | 14 | Pre-requisites 15 | ============== 16 | 17 | Clone and build the rtl-sdr library. see http://sdr.osmocom.org/trac/wiki/rtl-sdr 18 | 19 | Make sure rtl_fm runs and it is in your path. (e.g. $PATH). 20 | 21 | Build instructions 22 | ================== 23 | 24 | git clone https://github.com/pocketmariner/aiswatcher.git 25 | 26 | cd aiswatcher 27 |

mkdir build 28 |

cd build 29 |

cmake ../ -DCMAKE_BUILD_TYPE=RELEASE 30 |

make 31 | 32 | To run:- 33 | 34 | ./aiswatcher -h boatbeaconapp.com -p 7028 -t 1 -d -l -f /tmp/aisdata -P 54 -D 0 35 | 36 | You can then view the live ships on this web page:- 37 | 38 | http://boatbeaconapp.com/station/7028 39 | 40 | Please email us at "support at pocketmariner.com" if you would like your own port and dedicated web page to view 41 | data from your setup. 42 | 43 | AisWatcher defaults to using the lower AIS radio frequency - 161.975MHz. Pass "-F 162025000" to use the alternative AIS band. 44 | Fine tune gain parameter (-G ) and most important set the ppm offset error ( -P ). You can use the gqrx app to find out what the ppm needs to be set to by tuning in to a known VHF radio station by adjusting the ppm value on gqrx. 45 | 46 | http://gqrx.dk/ 47 | 48 | ./aiswatcher -H to see all the options. 49 | 50 | We have also successfully developed a dual band AIS receiver for BeagleBone using gnu-radio. 51 | http://pocketmariner.com/ais-ship-tracking/cover-your-area/pocket-mariner-ais-dual-channel-receiver-for-99/ 52 | -------------------------------------------------------------------------------- /src/sounddecoder.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sounddecoder.cpp 3 | * 4 | * This file is part of AISDecoder. 5 | * 6 | * Copyright (C) 2013 7 | * Astra Paging Ltd / AISHub (info@aishub.net) 8 | * 9 | * AISDecoder is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * AISDecoder uses parts of GNUAIS project (http://gnuais.sourceforge.net/) 15 | * 16 | */ 17 | 18 | #include 19 | #include 20 | #include "config.h" 21 | 22 | #include "receiver.h" 23 | #include "hmalloc.h" 24 | 25 | #define MAX_FILENAME_SIZE 512 26 | #define ERROR_MESSAGE_LENGTH 1024 27 | #include "sounddecoder.h" 28 | 29 | char errorSoundDecoder[ERROR_MESSAGE_LENGTH]; 30 | static FILE *fp=NULL; 31 | static struct receiver *rx_a=NULL; 32 | static struct receiver *rx_b=NULL; 33 | 34 | static short *buffer=NULL; 35 | static int buffer_l=0; 36 | static int buffer_read=0; 37 | static int channels=0; 38 | static Sound_Channels sound_channels; 39 | static Sound_Driver driver; 40 | 41 | 42 | static void readBuffers(); 43 | 44 | 45 | int initSoundDecoder( const Sound_Channels _channels, const Sound_Driver _driver, const char *file) { 46 | 47 | sound_channels = _channels; 48 | driver = _driver; 49 | channels = sound_channels == SOUND_CHANNELS_MONO ? 1 : 2; 50 | errorSoundDecoder[0]=0; 51 | char soundFile[MAX_FILENAME_SIZE+1]; 52 | switch (driver) { 53 | case DRIVER_FILE: 54 | fprintf(stderr, "opening pipe\n"); 55 | strncpy(soundFile, file, MAX_FILENAME_SIZE); 56 | soundFile[MAX_FILENAME_SIZE]=0; 57 | fp = fopen(soundFile, "rb"); 58 | if (fp) { 59 | fprintf(stderr, "opened pipe\n"); 60 | buffer_l = 1024; 61 | int extra = buffer_l % 5; 62 | buffer_l -= extra; 63 | buffer = (short *) hmalloc(buffer_l * sizeof(short) * channels); 64 | } else { 65 | fprintf(stderr, "Can't open raw file for read\n"); 66 | strcpy(errorSoundDecoder, "Can't open raw file for read"); 67 | return 0; 68 | } 69 | break; 70 | 71 | } 72 | 73 | if (sound_channels == SOUND_CHANNELS_MONO) { 74 | rx_a = init_receiver('A', 1, 0); 75 | } else { 76 | rx_a = init_receiver('A', 2, 0); 77 | rx_b = init_receiver('B', 2, 1); 78 | } 79 | return 1; 80 | } 81 | 82 | void runSoundDecoder(int *stop) { 83 | 84 | while (!*stop) { 85 | switch (driver) { 86 | case DRIVER_FILE: 87 | 88 | buffer_read = fread(buffer, channels * sizeof(short), buffer_l, fp); 89 | //fprintf(stderr, "read %d",buffer_read); 90 | 91 | 92 | if (buffer_read <= 0) 93 | { 94 | 95 | *stop = 1; 96 | } 97 | break; 98 | 99 | 100 | } 101 | readBuffers(); 102 | } 103 | 104 | } 105 | 106 | static void readBuffers() { 107 | if (buffer_read <= 0) return; 108 | if (rx_a != NULL && sound_channels != SOUND_CHANNELS_RIGHT) 109 | receiver_run(rx_a, buffer, buffer_read); 110 | 111 | if (rx_b != NULL && 112 | (sound_channels == SOUND_CHANNELS_STEREO || sound_channels == SOUND_CHANNELS_RIGHT) 113 | ) receiver_run(rx_b, buffer, buffer_read); 114 | } 115 | 116 | void freeSoundDecoder() { 117 | 118 | if (fp != NULL) { 119 | fclose(fp); 120 | fp=NULL; 121 | } 122 | 123 | if (rx_a != NULL) { 124 | free_receiver(rx_a); 125 | rx_a=NULL; 126 | } 127 | 128 | if (rx_b != NULL) { 129 | free_receiver(rx_b); 130 | rx_b=NULL; 131 | } 132 | 133 | if (buffer != NULL) { 134 | hfree(buffer); 135 | buffer = NULL; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/lib/filter.c: -------------------------------------------------------------------------------- 1 | /* 2 | * filter.c -- FIR filter 3 | * 4 | * Copyright (C) 2001, 2002, 2003 5 | * Tomi Manninen (oh2bns@sral.fi) 6 | * 7 | * This file is part of gMFSK. 8 | * 9 | * gMFSK is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * gMFSK is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with gMFSK; if not, write to the Free Software 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 | * 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | #include "hmalloc.h" 29 | #include "filter.h" 30 | 31 | #undef DEBUG 32 | 33 | #ifdef DEBUG 34 | #include 35 | #endif 36 | 37 | /* ---------------------------------------------------------------------- */ 38 | 39 | /* 40 | * This gets used when not optimising 41 | */ 42 | #ifndef __OPTIMIZE__ 43 | float filter_mac(const float *a, const float *b, int size) 44 | { 45 | float sum = 0; 46 | int i; 47 | 48 | for (i = 0; i < size; i++) 49 | sum += a[i] * b[i]; 50 | 51 | return sum; 52 | } 53 | #endif 54 | 55 | /* ---------------------------------------------------------------------- */ 56 | 57 | struct filter *filter_init(int len, float *taps) 58 | { 59 | struct filter *f; 60 | 61 | f = (struct filter *) hmalloc(sizeof(struct filter)); 62 | memset(f, 0, sizeof(struct filter)); 63 | 64 | f->taps = (float *) hmalloc(len * sizeof(float)); 65 | memcpy(f->taps, taps, len * sizeof(float)); 66 | 67 | f->length = len; 68 | f->pointer = f->length; 69 | 70 | return f; 71 | } 72 | 73 | void filter_free(struct filter *f) 74 | { 75 | if (f) { 76 | hfree(f->taps); 77 | hfree(f); 78 | } 79 | } 80 | 81 | /* ---------------------------------------------------------------------- */ 82 | 83 | void filter_run(struct filter *f, float in, float *out) 84 | { 85 | float *ptr = f->buffer + f->pointer++; 86 | 87 | *ptr = in; 88 | 89 | // TODO: optimize: pass filter length as constant to enable 90 | // using optimized __mac_c and fix the number of rounds there! 91 | #ifndef __HAVE_ARCH_MAC 92 | *out = filter_mac(ptr - f->length, f->taps, f->length); 93 | #else 94 | *out = mac(ptr - f->length, f->taps, f->length); 95 | #endif 96 | //*out = filter_mac(ptr - f->length, f->taps, 53); 97 | 98 | if (f->pointer == BufferLen) { 99 | memcpy(f->buffer, 100 | f->buffer + BufferLen - f->length, 101 | f->length * sizeof(float)); 102 | f->pointer = f->length; 103 | } 104 | } 105 | 106 | short filter_run_buf(struct filter *f, short *in, float *out, int step, int len) 107 | { 108 | int id = 0; 109 | int od = 0; 110 | short maxval = 0; 111 | int pointer = f->pointer; 112 | float *buffer = f->buffer; 113 | 114 | while (od < len) { 115 | buffer[pointer] = in[id]; 116 | 117 | // look for peak volume 118 | if (in[id] > maxval) 119 | maxval = in[id]; 120 | 121 | #ifndef __HAVE_ARCH_MAC 122 | out[od] = filter_mac(&buffer[pointer - f->length], f->taps, f->length); 123 | #else 124 | out[od] = mac(&buffer[pointer - f->length], f->taps, f->length); 125 | #endif 126 | pointer++; 127 | 128 | /* the buffer is much smaller than the incoming chunks */ 129 | if (pointer == BufferLen) { 130 | memcpy(buffer, 131 | buffer + BufferLen - f->length, 132 | f->length * sizeof(float)); 133 | pointer = f->length; 134 | } 135 | 136 | id += step; 137 | od++; 138 | } 139 | 140 | f->pointer = pointer; 141 | 142 | return maxval; 143 | } 144 | 145 | /* ---------------------------------------------------------------------- */ 146 | -------------------------------------------------------------------------------- /src/lib/alsaaudio/alsaaudio.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * input.c 4 | * 5 | * (c) Ruben Undheim 2008 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | 23 | #include 24 | 25 | #include "config.h" 26 | #include "alsaaudio.h" 27 | #include "hmalloc.h" 28 | 29 | #ifdef DMALLOC 30 | #include 31 | #endif 32 | 33 | int input_initialize(snd_pcm_t * handle, short **buffer, int *buffer_l, int channels_num, char *error_msg) 34 | { 35 | int err; 36 | int dir; 37 | 38 | snd_pcm_hw_params_t *hwparams = NULL; 39 | 40 | snd_pcm_hw_params_alloca(&hwparams); 41 | 42 | if ((err = snd_pcm_hw_params_any(handle, hwparams)) < 0) { 43 | sprintf(error_msg, "Error initializing hwparams"); 44 | return -1; 45 | } 46 | 47 | if ((err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { 48 | sprintf(error_msg, "Error setting acecss mode (SND_PCM_ACCESS_RW_INTERLEAVED): %s", snd_strerror(err)); 49 | return -1; 50 | } 51 | if ((err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0) { 52 | sprintf(error_msg, "Error setting format (SND_PCM_FORMAT_S16_LE): %s", snd_strerror(err)); 53 | return -1; 54 | } 55 | 56 | if ((err = snd_pcm_hw_params_set_channels(handle, hwparams, channels_num)) < 0) { 57 | sprintf(error_msg, "Error setting channels %d: %s", channels_num, snd_strerror(err)); 58 | return -1; 59 | } 60 | 61 | unsigned int rate = 48000; 62 | if ((err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, 0)) < 0) { 63 | sprintf(error_msg, "Error setting sample rate (%d): %s", rate, snd_strerror(err)); 64 | return -1; 65 | } 66 | 67 | snd_pcm_uframes_t size = 4096; /* number of frames */ 68 | 69 | dir = 0; 70 | if ((err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &size, &dir)) < 0) { 71 | sprintf(error_msg, "Error setting buffer size (%lu): %s", size, snd_strerror(err)); 72 | return -1; 73 | } 74 | 75 | if ((err = snd_pcm_hw_params(handle, hwparams)) < 0) { 76 | sprintf(error_msg, "Error writing hwparams: %s", snd_strerror(err)); 77 | return -1; 78 | } 79 | 80 | snd_pcm_hw_params_get_period_size(hwparams, &size, &dir); 81 | //int extra = (int) size % 5; 82 | //*buffer_l = (int) size - extra; 83 | *buffer_l = (int) size; 84 | int buffer_len_in_bytes = *buffer_l * sizeof(short) * channels_num; 85 | 86 | // hlog(LOG_DEBUG, LOGPREFIX "Using sound buffer size: %d frames of %d channels: %d bytes", 87 | // *buffer_l, channels, buffer_len_in_bytes); 88 | 89 | *buffer = (short *) hmalloc(buffer_len_in_bytes); 90 | bzero(*buffer, buffer_len_in_bytes); 91 | 92 | return 0; 93 | } 94 | 95 | 96 | int alsa_read(snd_pcm_t * handle, short *buffer, int count) 97 | { 98 | int err; 99 | 100 | err = snd_pcm_readi(handle, buffer, count); 101 | 102 | if (err == -EPIPE) { 103 | // hlog(LOG_ERR, LOGPREFIX "Overrun"); 104 | snd_pcm_prepare(handle); 105 | } else if (err < 0) { 106 | // hlog(LOG_ERR, LOGPREFIX "Read error"); 107 | } else if (err != count) { 108 | // hlog(LOG_INFO, LOGPREFIX "Short read, read %d frames", err); 109 | } else { 110 | /*hlog(LOG_DEBUG, LOGPREFIX "Read %d samples", err); */ 111 | } 112 | 113 | return err; 114 | } 115 | 116 | void input_cleanup(snd_pcm_t *handle) 117 | { 118 | snd_pcm_close(handle); 119 | } 120 | -------------------------------------------------------------------------------- /src/lib/winmmaudio/winmm_input.c: -------------------------------------------------------------------------------- 1 | #include "winmm_input.h" 2 | #include 3 | #include 4 | 5 | #ifdef EXTENSIBLE 6 | #define _KSDATAFORMAT_SUBTYPE_PCM (GUID) {0x00000001,0x0000,0x0010,{0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71}} 7 | #endif 8 | 9 | static WAVEHDR wave_chunk[WAVE_BUFFERS]; 10 | static LPWAVEHDR current; 11 | static unsigned int buffer_size=0; 12 | 13 | static void CALLBACK waveInProc( // wave in I/O completion procedure 14 | HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 15 | ) { 16 | switch (uMsg) { 17 | case WIM_DATA: 18 | current = (LPWAVEHDR)dwParam1; 19 | SetEvent((HANDLE)dwInstance); 20 | break; 21 | } 22 | } 23 | 24 | int winmm_init(unsigned int devId, 25 | LPHWAVEIN device, 26 | int channels, 27 | int bytesCount, 28 | HANDLE *eventHandler 29 | ) { 30 | 31 | *eventHandler=CreateEvent(NULL, FALSE, FALSE, NULL); 32 | if (*eventHandler == NULL) return 0; 33 | 34 | #ifndef EXTENSIBLE 35 | WAVEFORMATEX Format; 36 | Format.cbSize = 0; 37 | Format.wFormatTag = WAVE_FORMAT_PCM; 38 | Format.nChannels = channels; 39 | Format.wBitsPerSample = 16; 40 | Format.nSamplesPerSec = 48000L; 41 | Format.nBlockAlign = Format.nChannels * Format.wBitsPerSample / 8; 42 | Format.nAvgBytesPerSec = Format.nSamplesPerSec * Format.nBlockAlign; 43 | LPWAVEFORMATEX pFmt=&Format; 44 | #else 45 | WAVEFORMATEXTENSIBLE fmt; 46 | fmt.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); 47 | fmt.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; 48 | fmt.Format.nChannels = channels; 49 | fmt.Format.wBitsPerSample = 16; 50 | fmt.Format.nSamplesPerSec = 48000L; 51 | fmt.Format.nBlockAlign = fmt.Format.nChannels * fmt.Format.wBitsPerSample / 8; 52 | fmt.Format.nAvgBytesPerSec = fmt.Format.nSamplesPerSec * fmt.Format.nBlockAlign; 53 | fmt.SubFormat=_KSDATAFORMAT_SUBTYPE_PCM; 54 | fmt.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; 55 | fmt.Samples.wReserved=0; 56 | fmt.Samples.wValidBitsPerSample=16; 57 | LPWAVEFORMATEX pFmt=&fmt.Format; 58 | #endif 59 | 60 | MMRESULT err = waveInOpen(device, devId, pFmt, (DWORD)waveInProc, (DWORD)*eventHandler, CALLBACK_FUNCTION); 61 | if (err == MMSYSERR_NOERROR) { 62 | buffer_size=sizeof(WAVEHDR); 63 | size_t i; 64 | for (i=0; inBlockAlign; 69 | ZeroMemory(wave_chunk[i].lpData, wave_chunk[i].dwBufferLength); 70 | if (waveInPrepareHeader(*device, &wave_chunk[i], buffer_size) == MMSYSERR_NOERROR) { 71 | waveInAddBuffer(*device, &wave_chunk[i], buffer_size); 72 | } else return 0; 73 | } 74 | return 1; 75 | } 76 | return 0; 77 | } 78 | 79 | int winmm_getRecorded(LPHWAVEIN device, char *out) { 80 | int number=current->dwBytesRecorded/current->dwUser; 81 | if (number > 0) { 82 | memcpy(out, current->lpData, current->dwBytesRecorded); 83 | } 84 | waveInUnprepareHeader(*device, current, buffer_size); 85 | current->dwBytesRecorded=0; 86 | current->dwFlags=0; 87 | waveInPrepareHeader(*device, current, buffer_size); 88 | waveInAddBuffer(*device, current, buffer_size); 89 | current=NULL; 90 | return number; 91 | } 92 | 93 | void winmm_cleanup(LPHWAVEIN device, HANDLE *eventHandler) { 94 | if (device != NULL) { 95 | waveInStop(*device); 96 | size_t i; 97 | for (i=0; i 27 | #include 28 | 29 | #include "receiver.h" 30 | #include "hmalloc.h" 31 | #include "filter.h" 32 | 33 | static int sound_levellog=1; 34 | 35 | receiver_on_level_changed on_sound_level_changed=NULL; 36 | 37 | static float coeffs[]={ 38 | 2.5959e-55, 2.9479e-49, 1.4741e-43, 3.2462e-38, 3.1480e-33, 39 | 1.3443e-28, 2.5280e-24, 2.0934e-20, 7.6339e-17, 1.2259e-13, 40 | 8.6690e-11, 2.6996e-08, 3.7020e-06, 2.2355e-04, 5.9448e-03, 41 | 6.9616e-02, 3.5899e-01, 8.1522e-01, 8.1522e-01, 3.5899e-01, 42 | 6.9616e-02, 5.9448e-03, 2.2355e-04, 3.7020e-06, 2.6996e-08, 43 | 8.6690e-11, 1.2259e-13, 7.6339e-17, 2.0934e-20, 2.5280e-24, 44 | 1.3443e-28, 3.1480e-33, 3.2462e-38, 1.4741e-43, 2.9479e-49, 45 | 2.5959e-55 46 | }; 47 | #define COEFFS_L 36 48 | 49 | 50 | struct receiver *init_receiver(char name, int num_ch, int ch_ofs) 51 | { 52 | struct receiver *rx; 53 | 54 | rx = (struct receiver *) hmalloc(sizeof(struct receiver)); 55 | memset(rx, 0, sizeof(struct receiver)); 56 | 57 | rx->filter = filter_init(COEFFS_L, coeffs); 58 | 59 | rx->decoder = hmalloc(sizeof(struct demod_state_t)); 60 | protodec_initialize(rx->decoder, NULL, name); 61 | 62 | rx->name = name; 63 | rx->lastbit = 0; 64 | rx->num_ch = num_ch; 65 | rx->ch_ofs = ch_ofs; 66 | rx->pll = 0; 67 | rx->pllinc = 0x10000 / 5; 68 | rx->prev = 0; 69 | rx->last_levellog = 0; 70 | 71 | return rx; 72 | } 73 | 74 | void free_receiver(struct receiver *rx) 75 | { 76 | if (rx) { 77 | filter_free(rx->filter); 78 | hfree(rx); 79 | } 80 | } 81 | 82 | #define INC 16 83 | #define FILTERED_LEN 8192 84 | 85 | void receiver_run(struct receiver *rx, short *buf, int len) 86 | { 87 | float out; 88 | int curr, bit; 89 | char b; 90 | short maxval = 0; 91 | int level_distance; 92 | float level; 93 | int rx_num_ch = rx->num_ch; 94 | float filtered[FILTERED_LEN]; 95 | int i; 96 | 97 | /* len is number of samples available in buffer for each 98 | * channels - something like 1024, regardless of number of channels */ 99 | 100 | buf += rx->ch_ofs; 101 | 102 | if (len > FILTERED_LEN) 103 | abort(); 104 | 105 | maxval = filter_run_buf(rx->filter, buf, filtered, rx_num_ch, len); 106 | 107 | for (i = 0; i < len; i++) { 108 | out = filtered[i]; 109 | curr = (out > 0); 110 | 111 | if ((curr ^ rx->prev) == 1) { 112 | if (rx->pll < (0x10000 / 2)) { 113 | rx->pll += rx->pllinc / INC; 114 | } else { 115 | rx->pll -= rx->pllinc / INC; 116 | } 117 | } 118 | rx->prev = curr; 119 | 120 | rx->pll += rx->pllinc; 121 | 122 | if (rx->pll > 0xffff) { 123 | /* slice */ 124 | bit = (out > 0); 125 | /* nrzi decode */ 126 | b = !(bit ^ rx->lastbit); 127 | /* feed to the decoder */ 128 | protodec_decode(&b, 1, rx->decoder); 129 | 130 | rx->lastbit = bit; 131 | rx->pll &= 0xffff; 132 | } 133 | } 134 | 135 | /* calculate level, and log it */ 136 | level = (float)maxval / (float)32768 * (float)100; 137 | level_distance = time(NULL) - rx->last_levellog; 138 | 139 | if (level > 95.0 && (level_distance >= 30 || level_distance >= sound_levellog)) { 140 | if (on_sound_level_changed != NULL) on_sound_level_changed(level, rx->ch_ofs, 1); 141 | time(&rx->last_levellog); 142 | } else if (sound_levellog != 0 && level_distance >= sound_levellog) { 143 | if (on_sound_level_changed != NULL) on_sound_level_changed(level, rx->ch_ofs, 0); 144 | time(&rx->last_levellog); 145 | } 146 | } 147 | 148 | -------------------------------------------------------------------------------- /.cproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | make 56 | 57 | all 58 | true 59 | false 60 | true 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/lib/filter-i386.h: -------------------------------------------------------------------------------- 1 | /* 2 | * filter-i386.h -- optimized filter routines 3 | * 4 | * Copyright (C) 1996 5 | * Thomas Sailer (sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu) 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 | */ 21 | 22 | /* ---------------------------------------------------------------------- */ 23 | 24 | #ifndef _FILTER_I386_H 25 | #define _FILTER_I386_H 26 | 27 | /* ---------------------------------------------------------------------- */ 28 | 29 | #define __HAVE_ARCH_MAC 30 | #define mac(a,b,size) \ 31 | (__builtin_constant_p(size) ? __mac_c((a),(b),(size)) : __mac_g((a),(b),(size))) 32 | 33 | #include 34 | 35 | extern inline float __mac_g(const float *a, const float *b, 36 | unsigned int size) 37 | { 38 | float sum = 0; 39 | unsigned int i; 40 | 41 | for (i = 0; i < size; i++) 42 | sum += (*a++) * (*b++); 43 | return sum; 44 | } 45 | 46 | extern inline float __mac_c(const float *a, const float *b, 47 | unsigned int size) 48 | { 49 | float f; 50 | 51 | /* 52 | * inspired from Phil Karn, KA9Q's home page 53 | */ 54 | switch (size) { 55 | case 53: 56 | asm volatile ("flds (%1);\n\t" 57 | "fmuls (%2);\n\t" 58 | "flds 4(%1);\n\t" 59 | "fmuls 4(%2);\n\t" 60 | "flds 8(%1);\n\t" 61 | "fmuls 8(%2);\n\t" 62 | "fxch %%st(2);\n\t" 63 | "faddp;\n\t" 64 | "flds 12(%1);\n\t" 65 | "fmuls 12(%2);\n\t" 66 | "fxch %%st(2);\n\t" 67 | "faddp;\n\t" 68 | "flds 16(%1);\n\t" 69 | "fmuls 16(%2);\n\t" 70 | "fxch %%st(2);\n\t" 71 | "faddp;\n\t" 72 | "flds 20(%1);\n\t" 73 | "fmuls 20(%2);\n\t" 74 | "fxch %%st(2);\n\t" 75 | "faddp;\n\t" 76 | "flds 24(%1);\n\t" 77 | "fmuls 24(%2);\n\t" 78 | "fxch %%st(2);\n\t" 79 | "faddp;\n\t" 80 | "flds 28(%1);\n\t" 81 | "fmuls 28(%2);\n\t" 82 | "fxch %%st(2);\n\t" 83 | "faddp;\n\t" 84 | "flds 32(%1);\n\t" 85 | "fmuls 32(%2);\n\t" 86 | "fxch %%st(2);\n\t" 87 | "faddp;\n\t" 88 | "flds 36(%1);\n\t" 89 | "fmuls 36(%2);\n\t" 90 | "fxch %%st(2);\n\t" 91 | "faddp;\n\t" 92 | "flds 40(%1);\n\t" 93 | "fmuls 40(%2);\n\t" 94 | "fxch %%st(2);\n\t" 95 | "faddp;\n\t" 96 | "flds 44(%1);\n\t" 97 | "fmuls 44(%2);\n\t" 98 | "fxch %%st(2);\n\t" 99 | "faddp;\n\t" 100 | "flds 48(%1);\n\t" 101 | "fmuls 48(%2);\n\t" 102 | "fxch %%st(2);\n\t" 103 | "faddp;\n\t" 104 | "flds 52(%1);\n\t" 105 | "fmuls 52(%2);\n\t" 106 | "fxch %%st(2);\n\t" 107 | "faddp;\n\t" 108 | "flds 56(%1);\n\t" 109 | "fmuls 56(%2);\n\t" 110 | "fxch %%st(2);\n\t" 111 | "faddp;\n\t" 112 | "flds 60(%1);\n\t" 113 | "fmuls 60(%2);\n\t" 114 | "fxch %%st(2);\n\t" 115 | "faddp;\n\t" 116 | "flds 64(%1);\n\t" 117 | "fmuls 64(%2);\n\t" 118 | "fxch %%st(2);\n\t" 119 | "faddp;\n\t" 120 | "flds 68(%1);\n\t" 121 | "fmuls 68(%2);\n\t" 122 | "fxch %%st(2);\n\t" 123 | "faddp;\n\t" 124 | "flds 72(%1);\n\t" 125 | "fmuls 72(%2);\n\t" 126 | "fxch %%st(2);\n\t" 127 | "faddp;\n\t" 128 | "flds 76(%1);\n\t" 129 | "fmuls 76(%2);\n\t" 130 | "fxch %%st(2);\n\t" 131 | "faddp;\n\t" 132 | "flds 80(%1);\n\t" 133 | "fmuls 80(%2);\n\t" 134 | "fxch %%st(2);\n\t" 135 | "faddp;\n\t" 136 | "flds 84(%1);\n\t" 137 | "fmuls 84(%2);\n\t" 138 | "fxch %%st(2);\n\t" 139 | "faddp;\n\t" 140 | "flds 88(%1);\n\t" 141 | "fmuls 88(%2);\n\t" 142 | "fxch %%st(2);\n\t" 143 | "faddp;\n\t" 144 | "flds 92(%1);\n\t" 145 | "fmuls 92(%2);\n\t" 146 | "fxch %%st(2);\n\t" 147 | "faddp;\n\t" 148 | "flds 96(%1);\n\t" 149 | "fmuls 96(%2);\n\t" 150 | "fxch %%st(2);\n\t" 151 | "faddp;\n\t" 152 | "flds 100(%1);\n\t" 153 | "fmuls 100(%2);\n\t" 154 | "fxch %%st(2);\n\t" 155 | "faddp;\n\t" 156 | "flds 104(%1);\n\t" 157 | "fmuls 104(%2);\n\t" 158 | "fxch %%st(2);\n\t" 159 | "faddp;\n\t" 160 | "flds 108(%1);\n\t" 161 | "fmuls 108(%2);\n\t" 162 | "fxch %%st(2);\n\t" 163 | "faddp;\n\t" 164 | "flds 112(%1);\n\t" 165 | "fmuls 112(%2);\n\t" 166 | "fxch %%st(2);\n\t" 167 | "faddp;\n\t" 168 | "flds 116(%1);\n\t" 169 | "fmuls 116(%2);\n\t" 170 | "fxch %%st(2);\n\t" 171 | "faddp;\n\t" 172 | "flds 120(%1);\n\t" 173 | "fmuls 120(%2);\n\t" 174 | "fxch %%st(2);\n\t" 175 | "faddp;\n\t" 176 | "flds 124(%1);\n\t" 177 | "fmuls 124(%2);\n\t" 178 | "fxch %%st(2);\n\t" 179 | "faddp;\n\t" 180 | "flds 128(%1);\n\t" 181 | "fmuls 128(%2);\n\t" 182 | "fxch %%st(2);\n\t" 183 | "faddp;\n\t" 184 | "flds 132(%1);\n\t" 185 | "fmuls 132(%2);\n\t" 186 | "fxch %%st(2);\n\t" 187 | "faddp;\n\t" 188 | "flds 136(%1);\n\t" 189 | "fmuls 136(%2);\n\t" 190 | "fxch %%st(2);\n\t" 191 | "faddp;\n\t" 192 | "flds 140(%1);\n\t" 193 | "fmuls 140(%2);\n\t" 194 | "fxch %%st(2);\n\t" 195 | "faddp;\n\t" 196 | "flds 144(%1);\n\t" 197 | "fmuls 144(%2);\n\t" 198 | "fxch %%st(2);\n\t" 199 | "faddp;\n\t" 200 | "flds 148(%1);\n\t" 201 | "fmuls 148(%2);\n\t" 202 | "fxch %%st(2);\n\t" 203 | "faddp;\n\t" 204 | "flds 152(%1);\n\t" 205 | "fmuls 152(%2);\n\t" 206 | "fxch %%st(2);\n\t" 207 | "faddp;\n\t" 208 | "flds 156(%1);\n\t" 209 | "fmuls 156(%2);\n\t" 210 | "fxch %%st(2);\n\t" 211 | "faddp;\n\t" 212 | "flds 160(%1);\n\t" 213 | "fmuls 160(%2);\n\t" 214 | "fxch %%st(2);\n\t" 215 | "faddp;\n\t" 216 | "flds 164(%1);\n\t" 217 | "fmuls 164(%2);\n\t" 218 | "fxch %%st(2);\n\t" 219 | "faddp;\n\t" 220 | "flds 168(%1);\n\t" 221 | "fmuls 168(%2);\n\t" 222 | "fxch %%st(2);\n\t" 223 | "faddp;\n\t" 224 | "flds 172(%1);\n\t" 225 | "fmuls 172(%2);\n\t" 226 | "fxch %%st(2);\n\t" 227 | "faddp;\n\t" 228 | "flds 176(%1);\n\t" 229 | "fmuls 176(%2);\n\t" 230 | "fxch %%st(2);\n\t" 231 | "faddp;\n\t" 232 | "flds 180(%1);\n\t" 233 | "fmuls 180(%2);\n\t" 234 | "fxch %%st(2);\n\t" 235 | "faddp;\n\t" 236 | "flds 184(%1);\n\t" 237 | "fmuls 184(%2);\n\t" 238 | "fxch %%st(2);\n\t" 239 | "faddp;\n\t" 240 | "flds 188(%1);\n\t" 241 | "fmuls 188(%2);\n\t" 242 | "fxch %%st(2);\n\t" 243 | "faddp;\n\t" 244 | "flds 192(%1);\n\t" 245 | "fmuls 192(%2);\n\t" 246 | "fxch %%st(2);\n\t" 247 | "faddp;\n\t" 248 | "flds 196(%1);\n\t" 249 | "fmuls 196(%2);\n\t" 250 | "fxch %%st(2);\n\t" 251 | "faddp;\n\t" 252 | "flds 200(%1);\n\t" 253 | "fmuls 200(%2);\n\t" 254 | "fxch %%st(2);\n\t" 255 | "faddp;\n\t" 256 | "flds 204(%1);\n\t" 257 | "fmuls 204(%2);\n\t" 258 | "fxch %%st(2);\n\t" 259 | "faddp;\n\t" 260 | "flds 208(%1);\n\t" 261 | "fmuls 208(%2);\n\t" 262 | "fxch %%st(2);\n\t" 263 | "faddp;\n\t" 264 | "faddp;\n\t":"=t" (f):"r"(a), "r"(b):"memory"); 265 | return f; 266 | 267 | default: 268 | fprintf(stderr, 269 | "Warning: optimize __mac_c(..., ..., %d)\n", size); 270 | return __mac_g(a, b, size); 271 | } 272 | } 273 | 274 | /* ---------------------------------------------------------------------- */ 275 | #endif /* _FILTER_I386_H */ 276 | -------------------------------------------------------------------------------- /src/lib/protodec.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * protodec.c 4 | * 5 | * (c) Ruben Undheim 2008 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #include 23 | #include 24 | #include /* String function definitions */ 25 | #include "callbacks.h" 26 | #include "config.h" 27 | 28 | #include "protodec.h" 29 | #include "hmalloc.h" 30 | 31 | decoder_on_nmea_sentence_received on_nmea_sentence_received=NULL; 32 | 33 | #ifdef DMALLOC 34 | #include 35 | #endif 36 | 37 | void protodec_initialize(struct demod_state_t *d, struct serial_state_t *serial, char chanid) 38 | { 39 | memset(d, 0, sizeof(struct demod_state_t)); 40 | 41 | d->chanid = chanid; 42 | d->serial = serial; 43 | 44 | d->receivedframes = 0; 45 | d->lostframes = 0; 46 | d->lostframes2 = 0; 47 | 48 | protodec_reset(d); 49 | 50 | d->seqnr = 0; 51 | 52 | d->buffer = hmalloc(DEMOD_BUFFER_LEN); 53 | d->rbuffer = hmalloc(DEMOD_BUFFER_LEN); 54 | d->nmea = hmalloc(NMEABUFFER_LEN); 55 | } 56 | 57 | void protodec_deinit(struct demod_state_t *d) 58 | { 59 | hfree(d->buffer); 60 | hfree(d->rbuffer); 61 | hfree(d->nmea); 62 | } 63 | 64 | void protodec_reset(struct demod_state_t *d) 65 | { 66 | d->state = ST_SKURR; 67 | d->nskurr = 0; 68 | d->ndata = 0; 69 | d->npreamble = 0; 70 | d->nstartsign = 0; 71 | d->nstopsign = 0; 72 | d->antallpreamble = 0; 73 | d->antallenner = 0; 74 | d->last = 0; 75 | d->bitstuff = 0; 76 | d->bufferpos = 0; 77 | } 78 | 79 | /* 80 | * Calculates CRC-checksum 81 | */ 82 | 83 | unsigned short protodec_sdlc_crc(const unsigned char *data, unsigned len) 84 | { 85 | unsigned short c, crc = 0xffff; 86 | 87 | while (len--) 88 | for (c = 0x100 + *data++; c > 1; c >>= 1) 89 | if ((crc ^ c) & 1) 90 | crc = (crc >> 1) ^ 0x8408; 91 | else 92 | crc >>= 1; 93 | return ~crc; 94 | 95 | } 96 | 97 | int protodec_calculate_crc(int length_bits, struct demod_state_t *d) 98 | { 99 | int length_bytes; 100 | unsigned char *buf; 101 | int buflen; 102 | int i, j, x; 103 | unsigned char tmp; 104 | 105 | if (length_bits <= 0) { 106 | return 0; 107 | } 108 | 109 | length_bytes = length_bits / 8; 110 | buflen = length_bytes + 2; 111 | 112 | /* what is this? */ 113 | buf = (unsigned char *) hmalloc(sizeof(*buf) * buflen); 114 | for (j = 0; j < buflen; j++) { 115 | tmp = 0; 116 | for (i = 0; i < 8; i++) 117 | tmp |= (((d->buffer[i + 8 * j]) << (i))); 118 | buf[j] = tmp; 119 | } 120 | 121 | /* ok, here's the actual CRC calculation */ 122 | unsigned short crc = protodec_sdlc_crc(buf, buflen); 123 | //DBG(printf("CRC: %04x\n",crc)); 124 | 125 | /* what is this? */ 126 | memset(d->rbuffer, 0, DEMOD_BUFFER_LEN); 127 | for (j = 0; j < length_bytes; j++) { 128 | for (i = 0; i < 8; i++) { 129 | x = j * 8 + i; 130 | if (x >= DEMOD_BUFFER_LEN) { 131 | hfree(buf); 132 | return 0; 133 | } else { 134 | d->rbuffer[x] = (buf[j] >> (7 - i)) & 1; 135 | } 136 | } 137 | } 138 | 139 | hfree(buf); 140 | 141 | return (crc == 0x0f47); 142 | } 143 | 144 | unsigned long protodec_henten(int from, int size, unsigned char *frame) 145 | { 146 | int i = 0; 147 | unsigned long tmp = 0; 148 | 149 | for (i = 0; i < size; i++) 150 | tmp |= (frame[from + i]) << (size - 1 - i); 151 | 152 | return tmp; 153 | } 154 | 155 | 156 | void protodec_generate_nmea(struct demod_state_t *d, int bufferlen, int fillbits, time_t received_t) 157 | { 158 | int senlen; 159 | int pos; 160 | int k, offset; 161 | int m; 162 | unsigned char sentences, sentencenum, nmeachk, letter; 163 | 164 | //6bits to nmea-ascii. One sentence len max 82char 165 | //inc. head + tail.This makes inside datamax 62char multipart, 62 single 166 | senlen = 56; //this is normally not needed.For testing only. May be fixed number 167 | if (bufferlen <= (senlen * 6)) { 168 | sentences = 1; 169 | } else { 170 | sentences = bufferlen / (senlen * 6); 171 | //sentences , if overflow put one more 172 | if (bufferlen % (senlen * 6) != 0) 173 | sentences++; 174 | }; 175 | 176 | sentencenum = 0; 177 | pos = 0; 178 | offset = (sentences>1) ? 15 : 14; 179 | do { 180 | k = offset; //leave room for nmea header 181 | while (k < senlen + offset && bufferlen > pos) { 182 | letter = (unsigned char)protodec_henten(pos, 6, d->rbuffer); 183 | // 6bit-to-ascii conversion by IEC 184 | letter += (letter < 40) ? 48 : 56; 185 | d->nmea[k] = letter; 186 | pos += 6; 187 | k++; 188 | } 189 | sentencenum++; 190 | 191 | memcpy(&d->nmea[0], "!AIVDM,0,0,", 11); 192 | d->nmea[7] += sentences; 193 | d->nmea[9] += sentencenum; 194 | 195 | memcpy(&d->nmea[k], ",0*00\0", 6); 196 | 197 | if (sentences > 1) { 198 | d->nmea[11] = '0' + d->seqnr; 199 | d->nmea[12] = ','; 200 | d->nmea[13] = d->chanid; 201 | d->nmea[14] = ','; 202 | if (sentencenum == sentences) d->nmea[k + 1] = '0' + fillbits; 203 | } else { 204 | d->nmea[11] = ','; 205 | d->nmea[12] = d->chanid; 206 | d->nmea[13] = ','; 207 | } 208 | 209 | m = 1; 210 | nmeachk = d->nmea[m++]; 211 | while (d->nmea[m] != '*') nmeachk ^= d->nmea[m++]; 212 | 213 | sprintf(&d->nmea[k + 3], "%02X\r\n", nmeachk); 214 | if (on_nmea_sentence_received != NULL) 215 | on_nmea_sentence_received(d->nmea, k+7, sentences, sentencenum); 216 | } while (sentencenum < sentences); 217 | } 218 | 219 | void protodec_getdata(int bufferlen, struct demod_state_t *d) 220 | { 221 | unsigned char type = protodec_henten(0, 6, d->rbuffer); 222 | if (type < 1 || type > MAX_AIS_PACKET_TYPE /* 9 */) 223 | return; 224 | // unsigned long mmsi = protodec_henten(8, 30, d->rbuffer); 225 | int fillbits = 0; 226 | int k; 227 | time_t received_t; 228 | time(&received_t); 229 | 230 | if (bufferlen % 6 > 0) { 231 | fillbits = 6 - (bufferlen % 6); 232 | for (k = bufferlen; k < bufferlen + fillbits; k++) 233 | d->rbuffer[k] = 0; 234 | 235 | bufferlen = bufferlen + fillbits; 236 | } 237 | 238 | protodec_generate_nmea(d, bufferlen, fillbits, received_t); 239 | 240 | d->seqnr++; 241 | if (d->seqnr > 9) 242 | d->seqnr = 0; 243 | 244 | if (type < 1 || type > MAX_AIS_PACKET_TYPE) 245 | return; // unsupported packet type 246 | } 247 | 248 | void protodec_decode(char *in, int count, struct demod_state_t *d) 249 | { 250 | int i = 0; 251 | int bufferlength, correct; 252 | 253 | while (i < count) { 254 | switch (d->state) { 255 | case ST_DATA: 256 | if (d->bitstuff) { 257 | if (in[i] == 1) { 258 | d->state = ST_STOPSIGN; 259 | d->ndata = 0; 260 | d->bitstuff = 0; 261 | } else { 262 | d->ndata++; 263 | d->last = in[i]; 264 | d->bitstuff = 0; 265 | } 266 | } else { 267 | if (in[i] == d->last && in[i] == 1) { 268 | d->antallenner++; 269 | if (d->antallenner == 4) { 270 | d->bitstuff = 1; 271 | d->antallenner = 0; 272 | } 273 | 274 | } else 275 | d->antallenner = 0; 276 | 277 | d->buffer[d->bufferpos] = in[i]; 278 | d->bufferpos++; 279 | d->ndata++; 280 | 281 | if (d->bufferpos >= 449) { 282 | protodec_reset(d); 283 | } 284 | } 285 | break; 286 | 287 | case ST_SKURR: 288 | if (in[i] != d->last) 289 | d->antallpreamble++; 290 | else 291 | d->antallpreamble = 0; 292 | d->last = in[i]; 293 | if (d->antallpreamble > 14 && in[i] == 0) { 294 | d->state = ST_PREAMBLE; 295 | d->nskurr = 0; 296 | d->antallpreamble = 0; 297 | } 298 | d->nskurr++; 299 | break; 300 | 301 | case ST_PREAMBLE: 302 | if (in[i] != d->last && d->nstartsign == 0) { 303 | d->antallpreamble++; 304 | } else { 305 | if (in[i] == 1) { 306 | if (d->nstartsign == 0) { 307 | d->nstartsign = 3; 308 | d->last = in[i]; 309 | } else if (d->nstartsign == 5) { 310 | d->nstartsign++; 311 | d->npreamble = 0; 312 | d->antallpreamble = 0; 313 | d->state = ST_STARTSIGN; 314 | } else { 315 | d->nstartsign++; 316 | } 317 | 318 | } else { 319 | if (d->nstartsign == 0) { 320 | d->nstartsign = 1; 321 | } else { 322 | protodec_reset(d); 323 | } 324 | } 325 | } 326 | d->npreamble++; 327 | break; 328 | 329 | case ST_STARTSIGN: 330 | if (d->nstartsign >= 7) { 331 | if (in[i] == 0) { 332 | d->state = ST_DATA; 333 | d->nstartsign = 0; 334 | d->antallenner = 0; 335 | memset(d->buffer, 0, DEMOD_BUFFER_LEN); 336 | d->bufferpos = 0; 337 | } else { 338 | protodec_reset(d); 339 | } 340 | 341 | } else if (in[i] == 0) { 342 | protodec_reset(d); 343 | } 344 | d->nstartsign++; 345 | break; 346 | 347 | case ST_STOPSIGN: 348 | bufferlength = d->bufferpos - 6 - 16; 349 | if (in[i] == 0 && bufferlength > 0) { 350 | correct = protodec_calculate_crc(bufferlength, d); 351 | if (correct) { 352 | d->receivedframes++; 353 | protodec_getdata(bufferlength, d); 354 | } else { 355 | d->lostframes++; 356 | } 357 | } else { 358 | d->lostframes2++; 359 | } 360 | protodec_reset(d); 361 | break; 362 | 363 | 364 | } 365 | d->last = in[i]; 366 | i++; 367 | } 368 | } 369 | 370 | -------------------------------------------------------------------------------- /.settings/org.eclipse.cdt.codan.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.cdt.codan.checkers.errnoreturn=Warning 3 | org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} 4 | org.eclipse.cdt.codan.checkers.errreturnvalue=Error 5 | org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 6 | org.eclipse.cdt.codan.checkers.noreturn=Error 7 | org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} 8 | org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error 9 | org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 10 | org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error 11 | org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 12 | org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning 13 | org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 14 | org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error 15 | org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 16 | org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning 17 | org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} 18 | org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning 19 | org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} 20 | org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error 21 | org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 22 | org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning 23 | org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true} 24 | org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error 25 | org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 26 | org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error 27 | org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 28 | org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error 29 | org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 30 | org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error 31 | org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 32 | org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error 33 | org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 34 | org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error 35 | org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 36 | org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error 37 | org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 38 | org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info 39 | org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} 40 | org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning 41 | org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 42 | org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error 43 | org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 44 | org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error 45 | org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 46 | org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error 47 | org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 48 | org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning 49 | org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 50 | org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning 51 | org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 52 | org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning 53 | org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()} 54 | org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning 55 | org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false} 56 | org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning 57 | org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false} 58 | org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error 59 | org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 60 | org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning 61 | org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} 62 | org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning 63 | org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} 64 | org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning 65 | org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")} 66 | org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error 67 | org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 68 | -------------------------------------------------------------------------------- /rtlsdr/rtl-sdr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver 3 | * Copyright (C) 2012 by Steve Markgraf 4 | * Copyright (C) 2012 by Dimitri Stolnikov 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef __RTL_SDR_H 21 | #define __RTL_SDR_H 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | //#include 28 | #include "rtl-sdr_export.h" 29 | 30 | typedef struct rtlsdr_dev rtlsdr_dev_t; 31 | 32 | RTLSDR_API uint32_t rtlsdr_get_device_count(void); 33 | 34 | RTLSDR_API const char* rtlsdr_get_device_name(uint32_t index); 35 | 36 | /*! 37 | * Get USB device strings. 38 | * 39 | * NOTE: The string arguments must provide space for up to 256 bytes. 40 | * 41 | * \param index the device index 42 | * \param manufact manufacturer name, may be NULL 43 | * \param product product name, may be NULL 44 | * \param serial serial number, may be NULL 45 | * \return 0 on success 46 | */ 47 | RTLSDR_API int rtlsdr_get_device_usb_strings(uint32_t index, 48 | char *manufact, 49 | char *product, 50 | char *serial); 51 | 52 | /*! 53 | * Get device index by USB serial string descriptor. 54 | * 55 | * \param serial serial string of the device 56 | * \return device index of first device where the name matched 57 | * \return -1 if name is NULL 58 | * \return -2 if no devices were found at all 59 | * \return -3 if devices were found, but none with matching name 60 | */ 61 | RTLSDR_API int rtlsdr_get_index_by_serial(const char *serial); 62 | 63 | RTLSDR_API int rtlsdr_open(rtlsdr_dev_t **dev, uint32_t index); 64 | 65 | RTLSDR_API int rtlsdr_close(rtlsdr_dev_t *dev); 66 | 67 | /* configuration functions */ 68 | 69 | /*! 70 | * Set crystal oscillator frequencies used for the RTL2832 and the tuner IC. 71 | * 72 | * Usually both ICs use the same clock. Changing the clock may make sense if 73 | * you are applying an external clock to the tuner or to compensate the 74 | * frequency (and samplerate) error caused by the original (cheap) crystal. 75 | * 76 | * NOTE: Call this function only if you fully understand the implications. 77 | * 78 | * \param dev the device handle given by rtlsdr_open() 79 | * \param rtl_freq frequency value used to clock the RTL2832 in Hz 80 | * \param tuner_freq frequency value used to clock the tuner IC in Hz 81 | * \return 0 on success 82 | */ 83 | RTLSDR_API int rtlsdr_set_xtal_freq(rtlsdr_dev_t *dev, uint32_t rtl_freq, 84 | uint32_t tuner_freq); 85 | 86 | /*! 87 | * Get crystal oscillator frequencies used for the RTL2832 and the tuner IC. 88 | * 89 | * Usually both ICs use the same clock. 90 | * 91 | * \param dev the device handle given by rtlsdr_open() 92 | * \param rtl_freq frequency value used to clock the RTL2832 in Hz 93 | * \param tuner_freq frequency value used to clock the tuner IC in Hz 94 | * \return 0 on success 95 | */ 96 | RTLSDR_API int rtlsdr_get_xtal_freq(rtlsdr_dev_t *dev, uint32_t *rtl_freq, 97 | uint32_t *tuner_freq); 98 | 99 | /*! 100 | * Get USB device strings. 101 | * 102 | * NOTE: The string arguments must provide space for up to 256 bytes. 103 | * 104 | * \param dev the device handle given by rtlsdr_open() 105 | * \param manufact manufacturer name, may be NULL 106 | * \param product product name, may be NULL 107 | * \param serial serial number, may be NULL 108 | * \return 0 on success 109 | */ 110 | RTLSDR_API int rtlsdr_get_usb_strings(rtlsdr_dev_t *dev, char *manufact, 111 | char *product, char *serial); 112 | 113 | /*! 114 | * Write the device EEPROM 115 | * 116 | * \param dev the device handle given by rtlsdr_open() 117 | * \param data buffer of data to be written 118 | * \param offset address where the data should be written 119 | * \param len length of the data 120 | * \return 0 on success 121 | * \return -1 if device handle is invalid 122 | * \return -2 if EEPROM size is exceeded 123 | * \return -3 if no EEPROM was found 124 | */ 125 | 126 | RTLSDR_API int rtlsdr_write_eeprom(rtlsdr_dev_t *dev, uint8_t *data, 127 | uint8_t offset, uint16_t len); 128 | 129 | /*! 130 | * Read the device EEPROM 131 | * 132 | * \param dev the device handle given by rtlsdr_open() 133 | * \param data buffer where the data should be written 134 | * \param offset address where the data should be read from 135 | * \param len length of the data 136 | * \return 0 on success 137 | * \return -1 if device handle is invalid 138 | * \return -2 if EEPROM size is exceeded 139 | * \return -3 if no EEPROM was found 140 | */ 141 | 142 | RTLSDR_API int rtlsdr_read_eeprom(rtlsdr_dev_t *dev, uint8_t *data, 143 | uint8_t offset, uint16_t len); 144 | 145 | RTLSDR_API int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq); 146 | 147 | /*! 148 | * Get actual frequency the device is tuned to. 149 | * 150 | * \param dev the device handle given by rtlsdr_open() 151 | * \return 0 on error, frequency in Hz otherwise 152 | */ 153 | RTLSDR_API uint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev); 154 | 155 | /*! 156 | * Set the frequency correction value for the device. 157 | * 158 | * \param dev the device handle given by rtlsdr_open() 159 | * \param ppm correction value in parts per million (ppm) 160 | * \return 0 on success 161 | */ 162 | RTLSDR_API int rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm); 163 | 164 | /*! 165 | * Get actual frequency correction value of the device. 166 | * 167 | * \param dev the device handle given by rtlsdr_open() 168 | * \return correction value in parts per million (ppm) 169 | */ 170 | RTLSDR_API int rtlsdr_get_freq_correction(rtlsdr_dev_t *dev); 171 | 172 | enum rtlsdr_tuner { 173 | RTLSDR_TUNER_UNKNOWN = 0, 174 | RTLSDR_TUNER_E4000, 175 | RTLSDR_TUNER_FC0012, 176 | RTLSDR_TUNER_FC0013, 177 | RTLSDR_TUNER_FC2580, 178 | RTLSDR_TUNER_R820T 179 | }; 180 | 181 | /*! 182 | * Get the tuner type. 183 | * 184 | * \param dev the device handle given by rtlsdr_open() 185 | * \return RTLSDR_TUNER_UNKNOWN on error, tuner type otherwise 186 | */ 187 | RTLSDR_API enum rtlsdr_tuner rtlsdr_get_tuner_type(rtlsdr_dev_t *dev); 188 | 189 | /*! 190 | * Get a list of gains supported by the tuner. 191 | * 192 | * NOTE: The gains argument must be preallocated by the caller. If NULL is 193 | * being given instead, the number of available gain values will be returned. 194 | * 195 | * \param dev the device handle given by rtlsdr_open() 196 | * \param gains array of gain values. In tenths of a dB, 115 means 11.5 dB. 197 | * \return <= 0 on error, number of available (returned) gain values otherwise 198 | */ 199 | RTLSDR_API int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains); 200 | 201 | /*! 202 | * Set the gain for the device. 203 | * Manual gain mode must be enabled for this to work. 204 | * 205 | * Valid gain values (in tenths of a dB) for the E4000 tuner: 206 | * -10, 15, 40, 65, 90, 115, 140, 165, 190, 207 | * 215, 240, 290, 340, 420, 430, 450, 470, 490 208 | * 209 | * Valid gain values may be queried with \ref rtlsdr_get_tuner_gains function. 210 | * 211 | * \param dev the device handle given by rtlsdr_open() 212 | * \param gain in tenths of a dB, 115 means 11.5 dB. 213 | * \return 0 on success 214 | */ 215 | RTLSDR_API int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain); 216 | 217 | /*! 218 | * Get actual gain the device is configured to. 219 | * 220 | * \param dev the device handle given by rtlsdr_open() 221 | * \return 0 on error, gain in tenths of a dB, 115 means 11.5 dB. 222 | */ 223 | RTLSDR_API int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev); 224 | 225 | /*! 226 | * Set the intermediate frequency gain for the device. 227 | * 228 | * \param dev the device handle given by rtlsdr_open() 229 | * \param stage intermediate frequency gain stage number (1 to 6 for E4000) 230 | * \param gain in tenths of a dB, -30 means -3.0 dB. 231 | * \return 0 on success 232 | */ 233 | RTLSDR_API int rtlsdr_set_tuner_if_gain(rtlsdr_dev_t *dev, int stage, int gain); 234 | 235 | /*! 236 | * Set the gain mode (automatic/manual) for the device. 237 | * Manual gain mode must be enabled for the gain setter function to work. 238 | * 239 | * \param dev the device handle given by rtlsdr_open() 240 | * \param manual gain mode, 1 means manual gain mode shall be enabled. 241 | * \return 0 on success 242 | */ 243 | RTLSDR_API int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int manual); 244 | 245 | /* this will select the baseband filters according to the requested sample rate */ 246 | RTLSDR_API int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t rate); 247 | 248 | /*! 249 | * Get actual sample rate the device is configured to. 250 | * 251 | * \param dev the device handle given by rtlsdr_open() 252 | * \return 0 on error, sample rate in Hz otherwise 253 | */ 254 | RTLSDR_API uint32_t rtlsdr_get_sample_rate(rtlsdr_dev_t *dev); 255 | 256 | /*! 257 | * Enable test mode that returns an 8 bit counter instead of the samples. 258 | * The counter is generated inside the RTL2832. 259 | * 260 | * \param dev the device handle given by rtlsdr_open() 261 | * \param test mode, 1 means enabled, 0 disabled 262 | * \return 0 on success 263 | */ 264 | RTLSDR_API int rtlsdr_set_testmode(rtlsdr_dev_t *dev, int on); 265 | 266 | /*! 267 | * Enable or disable the internal digital AGC of the RTL2832. 268 | * 269 | * \param dev the device handle given by rtlsdr_open() 270 | * \param digital AGC mode, 1 means enabled, 0 disabled 271 | * \return 0 on success 272 | */ 273 | RTLSDR_API int rtlsdr_set_agc_mode(rtlsdr_dev_t *dev, int on); 274 | 275 | /*! 276 | * Enable or disable the direct sampling mode. When enabled, the IF mode 277 | * of the RTL2832 is activated, and rtlsdr_set_center_freq() will control 278 | * the IF-frequency of the DDC, which can be used to tune from 0 to 28.8 MHz 279 | * (xtal frequency of the RTL2832). 280 | * 281 | * \param dev the device handle given by rtlsdr_open() 282 | * \param on 0 means disabled, 1 I-ADC input enabled, 2 Q-ADC input enabled 283 | * \return 0 on success 284 | */ 285 | RTLSDR_API int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on); 286 | 287 | /*! 288 | * Get state of the direct sampling mode 289 | * 290 | * \param dev the device handle given by rtlsdr_open() 291 | * \return -1 on error, 0 means disabled, 1 I-ADC input enabled 292 | * 2 Q-ADC input enabled 293 | */ 294 | RTLSDR_API int rtlsdr_get_direct_sampling(rtlsdr_dev_t *dev); 295 | 296 | /*! 297 | * Enable or disable offset tuning for zero-IF tuners, which allows to avoid 298 | * problems caused by the DC offset of the ADCs and 1/f noise. 299 | * 300 | * \param dev the device handle given by rtlsdr_open() 301 | * \param on 0 means disabled, 1 enabled 302 | * \return 0 on success 303 | */ 304 | RTLSDR_API int rtlsdr_set_offset_tuning(rtlsdr_dev_t *dev, int on); 305 | 306 | /*! 307 | * Get state of the offset tuning mode 308 | * 309 | * \param dev the device handle given by rtlsdr_open() 310 | * \return -1 on error, 0 means disabled, 1 enabled 311 | */ 312 | RTLSDR_API int rtlsdr_get_offset_tuning(rtlsdr_dev_t *dev); 313 | 314 | /* streaming functions */ 315 | 316 | RTLSDR_API int rtlsdr_reset_buffer(rtlsdr_dev_t *dev); 317 | 318 | RTLSDR_API int rtlsdr_read_sync(rtlsdr_dev_t *dev, void *buf, int len, int *n_read); 319 | 320 | typedef void(*rtlsdr_read_async_cb_t)(unsigned char *buf, uint32_t len, void *ctx); 321 | 322 | /*! 323 | * Read samples from the device asynchronously. This function will block until 324 | * it is being canceled using rtlsdr_cancel_async() 325 | * 326 | * NOTE: This function is deprecated and is subject for removal. 327 | * 328 | * \param dev the device handle given by rtlsdr_open() 329 | * \param cb callback function to return received samples 330 | * \param ctx user specific context to pass via the callback function 331 | * \return 0 on success 332 | */ 333 | RTLSDR_API int rtlsdr_wait_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx); 334 | 335 | /*! 336 | * Read samples from the device asynchronously. This function will block until 337 | * it is being canceled using rtlsdr_cancel_async() 338 | * 339 | * \param dev the device handle given by rtlsdr_open() 340 | * \param cb callback function to return received samples 341 | * \param ctx user specific context to pass via the callback function 342 | * \param buf_num optional buffer count, buf_num * buf_len = overall buffer size 343 | * set to 0 for default buffer count (32) 344 | * \param buf_len optional buffer length, must be multiple of 512, 345 | * set to 0 for default buffer length (16 * 32 * 512) 346 | * \return 0 on success 347 | */ 348 | RTLSDR_API int rtlsdr_read_async(rtlsdr_dev_t *dev, 349 | rtlsdr_read_async_cb_t cb, 350 | void *ctx, 351 | uint32_t buf_num, 352 | uint32_t buf_len); 353 | 354 | /*! 355 | * Cancel all pending asynchronous operations on the device. 356 | * 357 | * \param dev the device handle given by rtlsdr_open() 358 | * \return 0 on success 359 | */ 360 | RTLSDR_API int rtlsdr_cancel_async(rtlsdr_dev_t *dev); 361 | 362 | #ifdef __cplusplus 363 | } 364 | #endif 365 | 366 | #endif /* __RTL_SDR_H */ 367 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * main.cpp -- AIS Decoder 3 | * 4 | * Copyright (C) 2014 Pocket Mariner Ltd (support@pocketmariner.com ) and 5 | * Astra Paging Ltd / AISHub (info@aishub.net) 6 | * 7 | * AISDecoder is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * AISDecoder uses parts of GNUAIS project (http://gnuais.sourceforge.net/) 13 | * 14 | */ 15 | #include "main.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "config.h" 32 | #include "sounddecoder.h" 33 | #include "callbacks.h" 34 | 35 | #define HELP_AUDIO_DRIVERS "file" 36 | 37 | #define HELP_AUDIO_DEVICE "" 38 | 39 | #define HELP_MSG \ 40 | "Usage: " PROJECT_NAME " -h hostname -p port [-t protocol] [-f /path/file.raw] [-l] [-d] [-D] [-G] [-C] [-F]\n\n"\ 41 | "-h\tDestination host or IP address\n"\ 42 | "-p\tDestination port\n"\ 43 | "-t\tProtocol 0=UDP 1=TCP (UDP default)\n"\ 44 | "-f\tFull path to 48kHz raw audio file (default /tmp/aisdata)\n"\ 45 | "-l\tLog sound levels to console (stderr)\n"\ 46 | "-d\tLog NMEA sentences to console (stderr)\n"\ 47 | "-n\tOutput to serial/NMEA device name e.g. /dev/ttyO0 (BeagleBone Black J1)\n"\ 48 | "-D Select RTL device (default: 0)\n"\ 49 | "-G db Set gain (default: max gain. Use -10 for auto-gain)\n"\ 50 | "-C Enable the Automatic Gain Control (default: off)\n"\ 51 | "-F hz Set frequency (default: 161.97 Mhz)\n"\ 52 | "-H\tDisplay this help\n" 53 | 54 | #define MAX_BUFFER_LENGTH 2048 55 | static char buffer[MAX_BUFFER_LENGTH]; 56 | static unsigned int buffer_count=0; 57 | 58 | static int sock; 59 | static struct addrinfo* addr=NULL; 60 | static struct sockaddr_in serv_addr; 61 | static int protocol=0; //1 = TCP, 0 for UDP 62 | 63 | static int initSocket(const char *host, const char *portname); 64 | static int show_levels=0; 65 | static int debug_nmea=0; 66 | static int serial_nmea=0; 67 | static char* serial_device=NULL; 68 | static int ttyfd=-1; //file descriptor for console outpu 69 | static int share_nmea_via_ip=0; 70 | 71 | char *host=NULL,*port=NULL; 72 | 73 | void sound_level_changed(float level, int channel, unsigned char high) { 74 | if (high != 0) 75 | fprintf(stderr, "RX Level on ch %d too high: %.0f %%\n", channel, level); 76 | else 77 | fprintf(stderr, "RX Level on ch %d: %.0f %%\n", channel, level); 78 | } 79 | 80 | void nmea_sentence_received(const char *sentence, 81 | unsigned int length, 82 | unsigned char sentences, 83 | unsigned char sentencenum) { 84 | if (sentences == 1) { 85 | 86 | //if (debug_nmea) fprintf(stderr, "length %d", strlen(sentence)); 87 | if (debug_nmea) fprintf(stderr, "%s", sentence); 88 | if (serial_nmea && ttyfd > 0) write(ttyfd, sentence,strlen(sentence)); 89 | 90 | if (share_nmea_via_ip && protocol ==0) 91 | { 92 | if (sendto(sock, sentence, length, 0, addr->ai_addr, addr->ai_addrlen) == -1) abort(); 93 | } 94 | else if (share_nmea_via_ip && protocol==1) 95 | { 96 | //fprintf(stderr, "write to remote socket address 1\n"); 97 | if (write(sock, sentence, strlen(sentence)) < 0 ) 98 | { 99 | //it might have timed out - close it and re-open it. 100 | 101 | //fprintf(stderr, "Failed to write to remote socket address!\n"); 102 | 103 | if (!openTcpSocket(host, port) ) 104 | { 105 | fprintf(stderr, "Failed to to re-open remote socket address!\n"); 106 | // abort(); 107 | } 108 | else 109 | { 110 | write(sock, sentence, strlen(sentence)); 111 | } 112 | 113 | } 114 | 115 | } 116 | 117 | 118 | } else { 119 | if ((buffer_count + length) < MAX_BUFFER_LENGTH) { 120 | memcpy(&buffer[buffer_count], sentence, length); 121 | buffer_count += length; 122 | } else { 123 | buffer_count=0; 124 | } 125 | 126 | if (sentences == sentencenum && buffer_count > 0) { 127 | if (debug_nmea) fprintf(stderr, "%s", buffer); 128 | if (serial_nmea && ttyfd > 0) write(ttyfd, buffer,strlen(buffer)); 129 | 130 | if (share_nmea_via_ip && protocol ==0) 131 | { 132 | if (sendto(sock, buffer, buffer_count, 0, addr->ai_addr, addr->ai_addrlen) == -1) abort(); 133 | } 134 | else if (share_nmea_via_ip && protocol==1) 135 | { 136 | //fprintf(stderr, "write to remote socket address 2\n"); 137 | if (write(sock, sentence, strlen(sentence)) < 0 ) 138 | { 139 | //it might have timed out - close it and re-open it. 140 | 141 | //fprintf(stderr, "Failed to write to remote socket address!\n"); 142 | 143 | if (!openTcpSocket(host, port) ) 144 | { 145 | fprintf(stderr, "Failed to to re-open remote socket address!\n"); 146 | //abort(); 147 | } 148 | else 149 | { 150 | write(sock, sentence, strlen(sentence)); 151 | } 152 | 153 | } 154 | 155 | } 156 | 157 | buffer_count=0; 158 | }; 159 | } 160 | } 161 | 162 | #define CMD_PARAMS "h:p:t:ln:dHf:c:D:G:C:F:P:" 163 | 164 | 165 | int main(int argc, char *argv[]) { 166 | Sound_Channels channels = SOUND_CHANNELS_MONO; 167 | char *file_name=NULL; 168 | const char *params=CMD_PARAMS; 169 | char* devfilename=NULL; 170 | int hfnd=0, pfnd=0; 171 | 172 | Modes.dev_index=0; 173 | Modes.gain=40; 174 | Modes.enable_agc=0; 175 | Modes.freq=161975000; 176 | Modes.ppm_error=0; 177 | 178 | int opt; 179 | // We expect write failures to occur but we want to handle them where 180 | // the error occurs rather than in a SIGPIPE handler. 181 | signal(SIGPIPE, SIG_IGN); 182 | 183 | protocol=0; 184 | channels = SOUND_CHANNELS_MONO; 185 | file_name="/tmp/aisdata"; 186 | while ((opt = getopt(argc, argv, params)) != -1) { 187 | switch (opt) { 188 | //rtl-sdr options 189 | case 'D': 190 | Modes.dev_index = atoi(optarg); 191 | break; 192 | case 'G': 193 | Modes.gain = (int) (atof(optarg)); 194 | break; 195 | case 'C': 196 | Modes.enable_agc++; 197 | break; 198 | case 'F': 199 | Modes.freq = (int) strtoll(optarg,NULL,10); 200 | break; 201 | case 'P': 202 | Modes.ppm_error = atoi(optarg); 203 | break; 204 | //aisdecoder options 205 | case 'h': 206 | host = optarg; 207 | hfnd = 1; 208 | break; 209 | case 'p': 210 | port = optarg; 211 | pfnd = 1; 212 | break; 213 | case 't': 214 | protocol = atoi(optarg); 215 | break; 216 | case 'l': 217 | show_levels = 1; 218 | break; 219 | case 'f': 220 | file_name = optarg; 221 | break; 222 | case 'd': 223 | debug_nmea = 1; 224 | break; 225 | case 'n': 226 | serial_nmea = 1; 227 | serial_device = optarg; 228 | break; 229 | case 'H': 230 | fprintf(stderr, HELP_MSG); 231 | return EXIT_SUCCESS; 232 | break; 233 | default: 234 | fprintf(stderr, "%c\n",(char)opt); 235 | fprintf(stderr, HELP_MSG); 236 | return EXIT_SUCCESS; 237 | break; 238 | } 239 | } 240 | 241 | if (argc < 2) { 242 | fprintf(stderr, HELP_MSG); 243 | return EXIT_FAILURE; 244 | } 245 | 246 | if (!hfnd) { 247 | fprintf(stderr, "Host is not set\n"); 248 | //return EXIT_FAILURE; 249 | } 250 | 251 | if (!pfnd) { 252 | fprintf(stderr, "Port is not set\n"); 253 | //return EXIT_FAILURE; 254 | } 255 | 256 | if (hfnd && pfnd) share_nmea_via_ip =1; 257 | //Make filename device unique 258 | devfilename= malloc(strlen(file_name) + 4); 259 | sprintf(devfilename,"%s_%d",file_name,Modes.dev_index); 260 | 261 | Modes.filename=devfilename; 262 | file_name=devfilename; 263 | 264 | 265 | if (share_nmea_via_ip && !initSocket(host, port)) { 266 | fprintf(stderr, "Failed to configure networking\n"); 267 | return EXIT_FAILURE; 268 | } 269 | 270 | 271 | 272 | //aisdecoder startup 273 | if (show_levels) on_sound_level_changed=sound_level_changed; 274 | on_nmea_sentence_received=nmea_sentence_received; 275 | Sound_Driver driver = DRIVER_FILE; 276 | 277 | int OK=0; 278 | 279 | int status = mkfifo (file_name, 0666); //create the fifo for communicating between rts-sdr and the decoder 280 | if (status < 0 && errno != EEXIST) { 281 | fprintf(stderr, "Can't create fifo\n"); 282 | return EXIT_FAILURE; 283 | } 284 | // rtl-sdr Initialization 285 | 286 | char *my_args[9]; 287 | 288 | 289 | my_args[0] = "rtl_fm"; 290 | /* 291 | my_args[1] = "-h"; 292 | my_args[2] = NULL; 293 | */ 294 | my_args[1] = malloc(strlen("-f 161975000")); 295 | my_args[2] = malloc(20); 296 | my_args[3] = malloc(20); 297 | my_args[6] = malloc(10); 298 | 299 | sprintf(my_args[1],"-f %d",Modes.freq);// "-f 161975000" or 162025000; 300 | sprintf(my_args[2],"-g %d",Modes.gain);//"-g 40"; 301 | sprintf(my_args[3],"-p %d",Modes.ppm_error);//"-p 95"; 302 | my_args[4] = "-s 48k"; 303 | my_args[5] = "-r 48k"; 304 | sprintf(my_args[6],"-d %d",Modes.dev_index); 305 | my_args[7] = Modes.filename; 306 | 307 | my_args[8] = NULL; 308 | 309 | 310 | pid_t pID = fork(); 311 | 312 | if (pID < 0) // failed to fork 313 | { 314 | fprintf(stderr, "failed to fork\n"); 315 | exit(1); 316 | // Throw exception 317 | } 318 | 319 | 320 | 321 | //We need to bring in the rtl_fm code here to interact with rtl_sdr to demod and give 322 | //write audio sample out to our fifo file 323 | // fprintf(stderr, "Giving rtl_fm time to start\n"); 324 | if (pID == 0) // child 325 | { 326 | // Code only executed by child process 327 | 328 | run_rtl_fm(my_args); 329 | } 330 | else if (pID) // child 331 | { 332 | if (serial_nmea) openSerialOut(); 333 | OK=initSoundDecoder(channels, driver, file_name); 334 | 335 | int stop=0; 336 | 337 | if (OK) { 338 | runSoundDecoder(&stop); 339 | } else { 340 | fprintf(stderr, "%s\n", errorSoundDecoder); 341 | } 342 | freeSoundDecoder(); 343 | freeaddrinfo(addr); 344 | if (devfilename != NULL) free(devfilename); 345 | } 346 | 347 | return 0; 348 | } 349 | 350 | void run_rtl_fm(char **my_args) 351 | { 352 | //rtl_fm -f 161975000 -g 40 -p 95 -s 48k -r 48k /tmp/aisdata 353 | fprintf(stderr, "forked\n"); 354 | int succ = execvp( "rtl_fm", my_args); 355 | if (succ) fprintf(stderr, "Failed to run rtl_fm: %d\n",succ); 356 | free(my_args[1]); 357 | free(my_args[2]); 358 | free(my_args[3]); 359 | free(my_args[6]); 360 | 361 | } 362 | 363 | int initSocket(const char *host, const char *portname) { 364 | struct addrinfo hints; 365 | memset(&hints, 0, sizeof(hints)); 366 | 367 | char* testMessage = "aisdecoder connection\r\n";//"!AIVDM,1,1,,A,B3Pai_family, addr->ai_socktype, addr->ai_protocol); 389 | if (sock==-1) { 390 | fprintf(stderr, "%s",strerror(errno)); 391 | 392 | return 0; 393 | } 394 | if (protocol ==1 ) 395 | { 396 | struct hostent *server; 397 | server = gethostbyname(host); 398 | if (server == NULL) 399 | { 400 | fprintf(stderr,"ERROR, no such host %s",host); 401 | exit(0); 402 | } 403 | bzero((char *) &serv_addr, sizeof(serv_addr)); 404 | serv_addr.sin_family = AF_INET; 405 | bcopy((char *)server->h_addr, 406 | (char *)&serv_addr.sin_addr.s_addr, 407 | server->h_length); 408 | int portno=atoi(portname); 409 | serv_addr.sin_port = htons(portno); 410 | 411 | if (connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0) 412 | { 413 | fprintf(stderr, "Failed to connect to remote socket address!\n"); 414 | return 0; 415 | } 416 | 417 | if (write(sock, testMessage, strlen(testMessage)) < 0 ) 418 | { 419 | fprintf(stderr, "Failed to write to remote socket address!\n"); 420 | return 0; 421 | } 422 | } 423 | return 1; 424 | } 425 | 426 | int openTcpSocket(const char *host, const char *portname) { 427 | 428 | 429 | if (protocol!=1) return -1; 430 | if (! initSocket(host, portname)) return -1; 431 | return 1; 432 | 433 | } 434 | 435 | int openSerialOut() 436 | { 437 | //On BeagleBone Black /dev/ttyO0 is enabled by default and attached to the console 438 | //you can write to it 439 | //echo Hello > /dev/ttyO0 440 | //You can set its speed to the NMEA 38400 441 | //stty -F /dev/ttyO0 38400 - set console to 38400 442 | //stty -a -F /dev/ttyO0 443 | //You can connect and listen to the console on your mac using 444 | //screen /dev/tty.usbserial 38400 445 | //exit using ctrl-a d 446 | char* testMessage = "aisdecoder nmea connection\r\n";//"!AIVDM,1,1,,A,B3P