#pragma once // Includes code from Dire Wolf Copyright (C) 2011, 2012, 2013, 2014, 2015 John Langner, WB2OSZ // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // Dephi emulation functions string * Strings(TStringList * Q, int Index); void Clear(TStringList * Q); int Count(TStringList * List); string * newString(); string * copy(string * Source, int StartChar, int Count); TStringList * newTStringList(); void freeString(string * Msg); void initString(string * S); void initTStringList(TStringList* T); // Two delete() This is confusing!! // Not really - one acts on String, other TStringList void Delete(TStringList * Q, int Index); void mydelete(string * Source, int StartChar, int Count); void move(unsigned char * SourcePointer, unsigned char * DestinationPointer, int CopyCount); void fmove(float * SourcePointer, float * DestinationPointer, int CopyCount); void setlength(string * Msg, int Count); // Set string length string * stringAdd(string * Msg, unsigned char * Chars, int Count); // Extend string void Assign(TStringList * to, TStringList * from); // Duplicate from to to string * duplicateString(string * in); // This looks for a string in a stringlist. Returns inhex if found, otherwise -1 int my_indexof(TStringList * l, string * s); int Add(TStringList * Q, string * Entry); #define MAX_FILTER_SIZE 480 /* 401 is needed for profile A, 300 baud & 44100. Revisit someday. */ // Size comes out to 417 for 1200 bps with 48000 sample rate // v1.7 - Was 404. Bump up to 480. #define MAX_TOTAL_CHANS 16 #define MAX_ADEVS 3 #define AX25_MAX_ADDR_LEN 12 #include // for uint64_t #define AX25_MAX_REPEATERS 8 #define AX25_MIN_ADDRS 2 /* Destination & Source. */ #define AX25_MAX_ADDRS 10 /* Destination, Source, 8 digipeaters. */ #define AX25_DESTINATION 0 /* Address positions in frame. */ #define AX25_SOURCE 1 #define AX25_REPEATER_1 2 #define AX25_REPEATER_2 3 #define AX25_REPEATER_3 4 #define AX25_REPEATER_4 5 #define AX25_REPEATER_5 6 #define AX25_REPEATER_6 7 #define AX25_REPEATER_7 8 #define AX25_REPEATER_8 9 #define AX25_MAX_ADDR_LEN 12 /* In theory, you would expect the maximum length */ /* to be 6 letters, dash, 2 digits, and nul for a */ /* total of 10. However, object labels can be 10 */ /* characters so throw in a couple extra bytes */ /* to be safe. */ #define AX25_MIN_INFO_LEN 0 /* Previously 1 when considering only APRS. */ #define AX25_MAX_INFO_LEN 2048 /* Maximum size for APRS. */ /* AX.25 starts out with 256 as the default max */ /* length but the end stations can negotiate */ /* something different. */ /* version 0.8: Change from 256 to 2028 to */ /* handle the larger paclen for Linux AX25. */ /* These don't include the 2 bytes for the */ /* HDLC frame FCS. */ /* * Previously, for APRS only. * #define AX25_MIN_PACKET_LEN ( 2 * 7 + 2 + AX25_MIN_INFO_LEN) * #define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + AX25_MAX_INFO_LEN) */ /* The more general case. */ /* An AX.25 frame can have a control byte and no protocol. */ #define AX25_MIN_PACKET_LEN ( 2 * 7 + 1 ) #define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + 3 + AX25_MAX_INFO_LEN) /* * packet_t is a pointer to a packet object. * * The actual implementation is not visible outside ax25_pad.c. */ #define AX25_UI_FRAME 3 /* Control field value. */ #define AX25_PID_NO_LAYER_3 0xf0 /* protocol ID used for APRS */ #define AX25_PID_SEGMENTATION_FRAGMENT 0x08 #define AX25_PID_ESCAPE_CHARACTER 0xff struct packet_s { int magic1; /* for error checking. */ int seq; /* unique sequence number for debugging. */ double release_time; /* Time stamp in format returned by dtime_now(). */ /* When to release from the SATgate mode delay queue. */ #define MAGIC 0x41583235 struct packet_s *nextp; /* Pointer to next in queue. */ int num_addr; /* Number of addresses in frame. */ /* Range of AX25_MIN_ADDRS .. AX25_MAX_ADDRS for AX.25. */ /* It will be 0 if it doesn't look like AX.25. */ /* -1 is used temporarily at allocation to mean */ /* not determined yet. */ /* * The 7th octet of each address contains: * * Bits: H R R SSID 0 * * H for digipeaters set to 0 initially. * Changed to 1 when position has been used. * * for source & destination it is called * command/response. Normally both 1 for APRS. * They should be opposites for connected mode. * * R R Reserved. Normally set to 1 1. * * SSID Substation ID. Range of 0 - 15. * * 0 Usually 0 but 1 for last address. */ #define SSID_H_MASK 0x80 #define SSID_H_SHIFT 7 #define SSID_RR_MASK 0x60 #define SSID_RR_SHIFT 5 #define SSID_SSID_MASK 0x1e #define SSID_SSID_SHIFT 1 #define SSID_LAST_MASK 0x01 int frame_len; /* Frame length without CRC. */ int modulo; /* I & S frames have sequence numbers of either 3 bits (modulo 8) */ /* or 7 bits (modulo 128). This is conveyed by either 1 or 2 */ /* control bytes. Unfortunately, we can't determine this by looking */ /* at an isolated frame. We need to know about the context. If we */ /* are part of the conversation, we would know. But if we are */ /* just listening to others, this would be more difficult to determine. */ /* For U frames: set to 0 - not applicable */ /* For I & S frames: 8 or 128 if known. 0 if unknown. */ unsigned char frame_data[AX25_MAX_PACKET_LEN + 1]; /* Raw frame contents, without the CRC. */ int magic2; /* Will get stomped on if above overflows. */ }; typedef struct packet_s *packet_t; typedef enum cmdres_e { cr_00 = 2, cr_cmd = 1, cr_res = 0, cr_11 = 3 } cmdres_t; extern packet_t ax25_new(void); /* * APRS always has one control octet of 0x03 but the more * general AX.25 case is one or two control bytes depending on * whether "modulo 128 operation" is in effect. */ //#define DEBUGX 1 static inline int ax25_get_control_offset(packet_t this_p) { return (this_p->num_addr * 7); } static inline int ax25_get_num_control(packet_t this_p) { int c; c = this_p->frame_data[ax25_get_control_offset(this_p)]; if ((c & 0x01) == 0) { /* I xxxx xxx0 */ #if DEBUGX dw_printf("ax25_get_num_control, %02x is I frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1); #endif return ((this_p->modulo == 128) ? 2 : 1); } if ((c & 0x03) == 1) { /* S xxxx xx01 */ #if DEBUGX dw_printf("ax25_get_num_control, %02x is S frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1); #endif return ((this_p->modulo == 128) ? 2 : 1); } #if DEBUGX dw_printf("ax25_get_num_control, %02x is U frame, always returns 1.\n", c); #endif return (1); /* U xxxx xx11 */ } /* * APRS always has one protocol octet of 0xF0 meaning no level 3 * protocol but the more general case is 0, 1 or 2 protocol ID octets. */ static inline int ax25_get_pid_offset(packet_t this_p) { return (ax25_get_control_offset(this_p) + ax25_get_num_control(this_p)); } static int ax25_get_num_pid(packet_t this_p) { int c; int pid; c = this_p->frame_data[ax25_get_control_offset(this_p)]; if ((c & 0x01) == 0 || /* I xxxx xxx0 */ c == 0x03 || c == 0x13) { /* UI 000x 0011 */ pid = this_p->frame_data[ax25_get_pid_offset(this_p)]; #if DEBUGX dw_printf("ax25_get_num_pid, %02x is I or UI frame, pid = %02x, returns %d\n", c, pid, (pid == AX25_PID_ESCAPE_CHARACTER) ? 2 : 1); #endif if (pid == AX25_PID_ESCAPE_CHARACTER) { return (2); /* pid 1111 1111 means another follows. */ } return (1); } #if DEBUGX dw_printf("ax25_get_num_pid, %02x is neither I nor UI frame, returns 0\n", c); #endif return (0); } /* * AX.25 has info field for 5 frame types depending on the control field. * * xxxx xxx0 I * 000x 0011 UI (which includes APRS) * 101x 1111 XID * 111x 0011 TEST * 100x 0111 FRMR * * APRS always has an Information field with at least one octet for the Data Type Indicator. */ static inline int ax25_get_info_offset(packet_t this_p) { int offset = ax25_get_control_offset(this_p) + ax25_get_num_control(this_p) + ax25_get_num_pid(this_p); #if DEBUGX dw_printf("ax25_get_info_offset, returns %d\n", offset); #endif return (offset); } static inline int ax25_get_num_info(packet_t this_p) { int len; /* assuming AX.25 frame. */ len = this_p->frame_len - this_p->num_addr * 7 - ax25_get_num_control(this_p) - ax25_get_num_pid(this_p); if (len < 0) { len = 0; /* print error? */ } return (len); } typedef enum ax25_modulo_e { modulo_unknown = 0, modulo_8 = 8, modulo_128 = 128 } ax25_modulo_t; typedef enum ax25_frame_type_e { frame_type_I = 0, // Information frame_type_S_RR, // Receive Ready - System Ready To Receive frame_type_S_RNR, // Receive Not Ready - TNC Buffer Full frame_type_S_REJ, // Reject Frame - Out of Sequence or Duplicate frame_type_S_SREJ, // Selective Reject - Request single frame repeat frame_type_U_SABME, // Set Async Balanced Mode, Extended frame_type_U_SABM, // Set Async Balanced Mode frame_type_U_DISC, // Disconnect frame_type_U_DM, // Disconnect Mode frame_type_U_UA, // Unnumbered Acknowledge frame_type_U_FRMR, // Frame Reject frame_type_U_UI, // Unnumbered Information frame_type_U_XID, // Exchange Identification frame_type_U_TEST, // Test frame_type_U, // other Unnumbered, not used by AX.25. frame_not_AX25 // Could not get control byte from frame. // This must be last because value plus 1 is // for the size of an array. } ax25_frame_type_t; /* * Originally this was a single number. * Let's try something new in version 1.2. * Also collect AGC values from the mark and space filters. */ typedef struct alevel_s { int rec; int mark; int space; //float ms_ratio; // TODO: take out after temporary investigation. } alevel_t; #ifndef AXTEST // TODO: remove this? #define AX25MEMDEBUG 0 #endif #if AX25MEMDEBUG // to investigate a memory leak problem extern void ax25memdebug_set(void); extern int ax25memdebug_get(void); extern int ax25memdebug_seq(packet_t this_p); extern packet_t ax25_from_text_debug(char *monitor, int strict, char *src_file, int src_line); #define ax25_from_text(m,s) ax25_from_text_debug(m,s,__FILE__,__LINE__) extern packet_t ax25_from_frame_debug(unsigned char *data, int len, alevel_t alevel, char *src_file, int src_line); #define ax25_from_frame(d,l,a) ax25_from_frame_debug(d,l,a,__FILE__,__LINE__); extern packet_t ax25_dup_debug(packet_t copy_from, char *src_file, int src_line); #define ax25_dup(p) ax25_dup_debug(p,__FILE__,__LINE__); extern void ax25_delete_debug(packet_t pp, char *src_file, int src_line); #define ax25_delete(p) ax25_delete_debug(p,__FILE__,__LINE__); #else extern packet_t ax25_from_text(char *monitor, int strict); extern packet_t ax25_from_frame(unsigned char *data, int len, alevel_t alevel); extern packet_t ax25_dup(packet_t copy_from); extern void ax25_delete(packet_t pp); #endif extern int ax25_parse_addr(int position, char *in_addr, int strict, char *out_addr, int *out_ssid, int *out_heard); extern int ax25_check_addresses(packet_t pp); extern packet_t ax25_unwrap_third_party(packet_t from_pp); extern void ax25_set_addr(packet_t pp, int, char *); extern void ax25_insert_addr(packet_t this_p, int n, char *ad); extern void ax25_remove_addr(packet_t this_p, int n); extern int ax25_get_num_addr(packet_t pp); extern int ax25_get_num_repeaters(packet_t this_p); extern void ax25_get_addr_with_ssid(packet_t pp, int n, char *station); extern void ax25_get_addr_no_ssid(packet_t pp, int n, char *station); extern int ax25_get_ssid(packet_t pp, int n); extern void ax25_set_ssid(packet_t this_p, int n, int ssid); extern int ax25_get_h(packet_t pp, int n); extern void ax25_set_h(packet_t pp, int n); extern int ax25_get_heard(packet_t this_p); extern int ax25_get_first_not_repeated(packet_t pp); extern int ax25_get_rr(packet_t this_p, int n); extern int ax25_get_info(packet_t pp, unsigned char **paddr); extern void ax25_set_info(packet_t pp, unsigned char *info_ptr, int info_len); extern int ax25_cut_at_crlf(packet_t this_p); extern void ax25_set_nextp(packet_t this_p, packet_t next_p); extern int ax25_get_dti(packet_t this_p); extern packet_t ax25_get_nextp(packet_t this_p); extern void ax25_set_release_time(packet_t this_p, double release_time); extern double ax25_get_release_time(packet_t this_p); extern void ax25_set_modulo(packet_t this_p, int modulo); extern int ax25_get_modulo(packet_t this_p); extern void ax25_format_addrs(packet_t pp, char *); extern void ax25_format_via_path(packet_t this_p, char *result, size_t result_size); extern int ax25_pack(packet_t pp, unsigned char result[AX25_MAX_PACKET_LEN]); extern ax25_frame_type_t ax25_frame_type(packet_t this_p, cmdres_t *cr, char *desc, int *pf, int *nr, int *ns); extern void ax25_hex_dump(packet_t this_p); extern int ax25_is_aprs(packet_t pp); extern int ax25_is_null_frame(packet_t this_p); extern int ax25_get_control(packet_t this_p); extern int ax25_get_c2(packet_t this_p); extern int ax25_get_pid(packet_t this_p); extern int ax25_get_frame_len(packet_t this_p); extern unsigned char *ax25_get_frame_data_ptr(packet_t this_p); extern unsigned short ax25_dedupe_crc(packet_t pp); extern unsigned short ax25_m_m_crc(packet_t pp); extern void ax25_safe_print(char *, int, int ascii_only); #define AX25_ALEVEL_TO_TEXT_SIZE 40 // overkill but safe. extern int ax25_alevel_to_text(alevel_t alevel, char text[AX25_ALEVEL_TO_TEXT_SIZE]); int demod_init(struct audio_s *pa); int demod_get_sample(int a); void demod_process_sample(int chan, int subchan, int sam); void demod_print_agc(int chan, int subchan); alevel_t demod_get_audio_level(int chan, int subchan); void hdlc_rec_bit(int chan, int subchan, int slice, int raw, int is_scrambled, int descram_state); /* Provided elsewhere to process a complete frame. */ //void process_rec_frame (int chan, unsigned char *fbuf, int flen, int level); /* Is HLDC decoder is currently gathering bits into a frame? */ /* Similar to, but not exactly the same as, data carrier detect. */ /* We use this to influence the PLL inertia. */ int hdlc_rec_gathering(int chan, int subchan, int slice); /* Transmit needs to know when someone else is transmitting. */ void dcd_change(int chan, int subchan, int slice, int state); int hdlc_rec_data_detect_any(int chan); /* direwolf.h - Common stuff used many places. */ // TODO: include this file first before anything else in each .c file. #ifdef NDEBUG #undef NDEBUG // Because it would disable assert(). #endif #define __restrict__ #define dw_printf Debugprintf #define M_PI 3.1415926f #define no_init_all deprecated #ifndef DIREWOLF_H #define DIREWOLF_H 1 /* * Support Windows XP and later. * * We need this before "#include ". * * Don't know what other impact it might have on others. */ #ifdef WIN32 #define __WIN32__ 1 #endif #if __WIN32__ #ifdef _WIN32_WINNT #error Include "direwolf.h" before any windows system files. #endif #ifdef WINVER #error Include "direwolf.h" before any windows system files. #endif #define _WIN32_WINNT 0x0501 /* Minimum OS version is XP. */ #define WINVER 0x0501 /* Minimum OS version is XP. */ #include #include #endif /* * Maximum number of audio devices. * Three is probably adequate for standard version. * Larger reasonable numbers should also be fine. * * For example, if you wanted to use 4 audio devices at once, change this to 4. */ #define MAX_ADEVS 3 /* * Maximum number of radio channels. * Note that there could be gaps. * Suppose audio device 0 was in mono mode and audio device 1 was stereo. * The channels available would be: * * ADevice 0: channel 0 * ADevice 1: left = 2, right = 3 * * TODO1.2: Look for any places that have * for (ch=0; ch>1) #define ADEVFIRSTCHAN(n) ((n) * 2) /* * Maximum number of modems per channel. * I called them "subchannels" (in the code) because * it is short and unambiguous. * Nothing magic about the number. Could be larger * but CPU demands might be overwhelming. */ #define MAX_SUBCHANS 9 /* * Each one of these can have multiple slicers, at * different levels, to compensate for different * amplitudes of the AFSK tones. * Initially used same number as subchannels but * we could probably trim this down a little * without impacting performance. */ #define MAX_SLICERS 9 #if __WIN32__ #define SLEEP_SEC(n) Sleep((n)*1000) #define SLEEP_MS(n) Sleep(n) #else #define SLEEP_SEC(n) sleep(n) #define SLEEP_MS(n) usleep((n)*1000) #endif #if __WIN32__ #define PTW32_STATIC_LIB //#include "pthreads/pthread.h" // This enables definitions of localtime_r and gmtime_r in system time.h. //#define _POSIX_THREAD_SAFE_FUNCTIONS 1 #define _POSIX_C_SOURCE 1 #else #include #endif #ifdef __APPLE__ // https://groups.yahoo.com/neo/groups/direwolf_packet/conversations/messages/2072 // The original suggestion was to add this to only ptt.c. // I thought it would make sense to put it here, so it will apply to all files, // consistently, rather than only one file ptt.c. // The placement of this is critical. Putting it earlier was a problem. // https://github.com/wb2osz/direwolf/issues/113 // It needs to be after the include pthread.h because // pthread.h pulls in , which redefines __DARWIN_C_LEVEL back to ansi, // which breaks things. // Maybe it should just go in ptt.c as originally suggested. // #define __DARWIN_C_LEVEL __DARWIN_C_FULL // There is a more involved patch here: // https://groups.yahoo.com/neo/groups/direwolf_packet/conversations/messages/2458 #ifndef _DARWIN_C_SOURCE #define _DARWIN_C_SOURCE #endif // Defining _DARWIN_C_SOURCE ensures that the definition for the cfmakeraw function (or similar) // are pulled in through the include file . #ifdef __DARWIN_C_LEVEL #undef __DARWIN_C_LEVEL #endif #define __DARWIN_C_LEVEL __DARWIN_C_FULL #endif #define DW_METERS_TO_FEET(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 3.2808399) #define DW_FEET_TO_METERS(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.3048) #define DW_KM_TO_MILES(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.621371192) #define DW_MILES_TO_KM(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 1.609344) #define DW_KNOTS_TO_MPH(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 1.15077945) #define DW_KNOTS_TO_METERS_PER_SEC(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.51444444444) #define DW_MPH_TO_KNOTS(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.868976) #define DW_MPH_TO_METERS_PER_SEC(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.44704) #define DW_MBAR_TO_INHG(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.0295333727) #if __WIN32__ typedef CRITICAL_SECTION dw_mutex_t; #define dw_mutex_init(x) \ InitializeCriticalSection (x) /* This one waits for lock. */ #define dw_mutex_lock(x) \ EnterCriticalSection (x) /* Returns non-zero if lock was obtained. */ #define dw_mutex_try_lock(x) \ TryEnterCriticalSection (x) #define dw_mutex_unlock(x) \ LeaveCriticalSection (x) #else typedef pthread_mutex_t dw_mutex_t; #define dw_mutex_init(x) pthread_mutex_init (x, NULL) /* this one will wait. */ #define dw_mutex_lock(x) \ { \ int err; \ err = pthread_mutex_lock (x); \ if (err != 0) { \ text_color_set(DW_COLOR_ERROR); \ dw_printf ("INTERNAL ERROR %s %d pthread_mutex_lock returned %d", __FILE__, __LINE__, err); \ exit (1); \ } \ } /* This one returns true if lock successful, false if not. */ /* pthread_mutex_trylock returns 0 for success. */ #define dw_mutex_try_lock(x) \ ({ \ int err; \ err = pthread_mutex_trylock (x); \ if (err != 0 && err != EBUSY) { \ text_color_set(DW_COLOR_ERROR); \ dw_printf ("INTERNAL ERROR %s %d pthread_mutex_trylock returned %d", __FILE__, __LINE__, err); \ exit (1); \ } ; \ ! err; \ }) #define dw_mutex_unlock(x) \ { \ int err; \ err = pthread_mutex_unlock (x); \ if (err != 0) { \ text_color_set(DW_COLOR_ERROR); \ dw_printf ("INTERNAL ERROR %s %d pthread_mutex_unlock returned %d", __FILE__, __LINE__, err); \ exit (1); \ } \ } #endif // Formerly used write/read on Linux, for some forgotten reason, // but always using send/recv makes more sense. // Need option to prevent a SIGPIPE signal on Linux. (added for 1.5 beta 2) #if __WIN32__ || __APPLE__ #define SOCK_SEND(s,data,size) send(s,data,size,0) #else #define SOCK_SEND(s,data,size) send(s,data,size, MSG_NOSIGNAL) #endif #define SOCK_RECV(s,data,size) recv(s,data,size,0) /* Platform differences for string functions. */ #if __WIN32__ char *strsep(char **stringp, const char *delim); char *strtok_r(char *str, const char *delim, char **saveptr); #endif // Don't recall why I added this for everyone rather than only for Windows. char *strcasestr(const char *S, const char *FIND); #endif /* ifndef DIREWOLF_H */ /*------------------------------------------------------------------ * * Module: audio.h * * Purpose: Interface to audio device commonly called a "sound card" * for historical reasons. * *---------------------------------------------------------------*/ /* * PTT control. */ enum ptt_method_e { PTT_METHOD_NONE, /* VOX or no transmit. */ PTT_METHOD_SERIAL, /* Serial port RTS or DTR. */ PTT_METHOD_GPIO, /* General purpose I/O, Linux only. */ PTT_METHOD_LPT, /* Parallel printer port, Linux only. */ PTT_METHOD_HAMLIB, /* HAMLib, Linux only. */ PTT_METHOD_CM108 }; /* GPIO pin of CM108/CM119/etc. Linux only. */ typedef enum ptt_method_e ptt_method_t; enum ptt_line_e { PTT_LINE_NONE = 0, PTT_LINE_RTS = 1, PTT_LINE_DTR = 2 }; // Important: 0 for neither. typedef enum ptt_line_e ptt_line_t; enum audio_in_type_e { AUDIO_IN_TYPE_SOUNDCARD, AUDIO_IN_TYPE_SDR_UDP, AUDIO_IN_TYPE_STDIN }; /* For option to try fixing frames with bad CRC. */ typedef enum retry_e { RETRY_NONE = 0, RETRY_INVERT_SINGLE = 1, RETRY_INVERT_DOUBLE = 2, RETRY_INVERT_TRIPLE = 3, RETRY_INVERT_TWO_SEP = 4, RETRY_MAX = 5 } retry_t; // Type of communication medium associated with the channel. enum medium_e { MEDIUM_NONE = 0, // Channel is not valid for use. MEDIUM_RADIO, // Internal modem for radio. MEDIUM_IGATE, // Access IGate as ordinary channel. MEDIUM_NETTNC }; // Remote network TNC. (possible future) typedef enum sanity_e { SANITY_APRS, SANITY_AX25, SANITY_NONE } sanity_t; struct audio_s { /* Previously we could handle only a single audio device. */ /* In version 1.2, we generalize this to handle multiple devices. */ /* This means we can now have more than 2 radio channels. */ struct adev_param_s { /* Properties of the sound device. */ int defined; /* Was device defined? */ /* First one defaults to yes. */ char adevice_in[80]; /* Name of the audio input device (or file?). */ /* TODO: Can be "-" to read from stdin. */ char adevice_out[80]; /* Name of the audio output device (or file?). */ int num_channels; /* Should be 1 for mono or 2 for stereo. */ int samples_per_sec; /* Audio sampling rate. Typically 11025, 22050, or 44100. */ int bits_per_sample; /* 8 (unsigned char) or 16 (signed short). */ } adev[MAX_ADEVS]; /* Common to all channels. */ char tts_script[80]; /* Script for text to speech. */ int statistics_interval; /* Number of seconds between the audio */ /* statistics reports. This is set by */ /* the "-a" option. 0 to disable feature. */ int xmit_error_rate; /* For testing purposes, we can generate frames with an invalid CRC */ /* to simulate corruption while going over the air. */ /* This is the probability, in per cent, of randomly corrupting it. */ /* Normally this is 0. 25 would mean corrupt it 25% of the time. */ int recv_error_rate; /* Similar but the % probability of dropping a received frame. */ float recv_ber; /* Receive Bit Error Rate (BER). */ /* Probability of inverting a bit coming out of the modem. */ //int fx25_xmit_enable; /* Enable transmission of FX.25. */ /* See fx25_init.c for explanation of values. */ /* Initially this applies to all channels. */ /* This should probably be per channel. One step at a time. */ /* v1.7 - replaced by layer2_xmit==LAYER2_FX25 */ int fx25_auto_enable; /* Turn on FX.25 for current connected mode session */ /* under poor conditions. */ /* Set to 0 to disable feature. */ /* I put it here, rather than with the rest of the link layer */ /* parameters because it is really a part of the HDLC layer */ /* and is part of the KISS TNC functionality rather than our data link layer. */ /* Future: not used yet. */ char timestamp_format[40]; /* -T option */ /* Precede received & transmitted frames with timestamp. */ /* Command line option uses "strftime" format string. */ /* originally a "channel" was always connected to an internal modem. */ /* In version 1.6, this is generalized so that a channel (as seen by client application) */ /* can be connected to something else. Initially, this will allow application */ /* access to the IGate. Later we might have network TNCs or other internal functions. */ // Properties for all channels. enum medium_e chan_medium[MAX_TOTAL_CHANS]; // MEDIUM_NONE for invalid. // MEDIUM_RADIO for internal modem. (only possibility earlier) // MEDIUM_IGATE allows application access to IGate. // MEDIUM_NETTNC for external TNC via TCP. int igate_vchannel; /* Virtual channel mapped to APRS-IS. */ /* -1 for none. */ /* Redundant but it makes things quicker and simpler */ /* than always searching thru above. */ /* Properties for each radio channel, common to receive and transmit. */ /* Can be different for each radio channel. */ struct achan_param_s { // What else should be moved out of structure and enlarged when NETTNC is implemented. ??? char mycall[AX25_MAX_ADDR_LEN]; /* Call associated with this radio channel. */ /* Could all be the same or different. */ enum modem_t { MODEM_AFSK, MODEM_BASEBAND, MODEM_SCRAMBLE, MODEM_QPSK, MODEM_8PSK, MODEM_OFF, MODEM_16_QAM, MODEM_64_QAM, MODEM_AIS, MODEM_EAS } modem_type; /* Usual AFSK. */ /* Baseband signal. Not used yet. */ /* Scrambled http://www.amsat.org/amsat/articles/g3ruh/109/fig03.gif */ /* Might try MFJ-2400 / CCITT v.26 / Bell 201 someday. */ /* No modem. Might want this for DTMF only channel. */ enum layer2_t { LAYER2_AX25 = 0, LAYER2_FX25, LAYER2_IL2P } layer2_xmit; // IL2P - New for version 1.7. // New layer 2 with FEC. Much less overhead than FX.25 but no longer backward compatible. // Only applies to transmit. // Listening for FEC sync word should add negligible overhead so // we leave reception enabled all the time as we do with FX.25. // TODO: FX.25 should probably be put here rather than global for all channels. int fx25_strength; // Strength of FX.25 FEC. // 16, 23, 64 for specific number of parity symbols. // 1 for automatic selection based on frame size. int il2p_max_fec; // 1 for max FEC length, 0 for automatic based on size. int il2p_invert_polarity; // 1 means invert on transmit. Receive handles either automatically. enum v26_e { V26_UNSPECIFIED = 0, V26_A, V26_B } v26_alternative; // Original implementation used alternative A for 2400 bbps PSK. // Years later, we discover that MFJ-2400 used alternative B. // It's likely the others did too. it also works a little better. // Default to MFJ compatible and print warning if user did not // pick one explicitly. #define V26_DEFAULT V26_B enum dtmf_decode_t { DTMF_DECODE_OFF, DTMF_DECODE_ON } dtmf_decode; /* Originally the DTMF ("Touch Tone") decoder was always */ /* enabled because it took a negligible amount of CPU. */ /* There were complaints about the false positives when */ /* hearing other modulation schemes on HF SSB so now it */ /* is enabled only when needed. */ /* "On" will send special "t" packet to attached applications */ /* and process as APRStt. Someday we might want to separate */ /* these but for now, we have a single off/on. */ int decimate; /* Reduce AFSK sample rate by this factor to */ /* decrease computational requirements. */ int upsample; /* Upsample by this factor for G3RUH. */ int mark_freq; /* Two tones for AFSK modulation, in Hz. */ int space_freq; /* Standard tones are 1200 and 2200 for 1200 baud. */ int baud; /* Data bits per second. */ /* Standard rates are 1200 for VHF and 300 for HF. */ /* This should really be called bits per second. */ /* Next 3 come from config file or command line. */ char profiles[16]; /* zero or more of ABC etc, optional + */ int num_freq; /* Number of different frequency pairs for decoders. */ int offset; /* Spacing between filter frequencies. */ int num_slicers; /* Number of different threshold points to decide */ /* between mark or space. */ /* This is derived from above by demod_init. */ int num_subchan; /* Total number of modems for each channel. */ /* These are for dealing with imperfect frames. */ enum retry_e fix_bits; /* Level of effort to recover from */ /* a bad FCS on the frame. */ /* 0 = no effort */ /* 1 = try fixing a single bit */ /* 2... = more techniques... */ enum sanity_e sanity_test; /* Sanity test to apply when finding a good */ /* CRC after making a change. */ /* Must look like APRS, AX.25, or anything. */ int passall; /* Allow thru even with bad CRC. */ /* Additional properties for transmit. */ /* Originally we had control outputs only for PTT. */ /* In version 1.2, we generalize this to allow others such as DCD. */ /* In version 1.4 we add CON for connected to another station. */ /* Index following structure by one of these: */ #define OCTYPE_PTT 0 #define OCTYPE_DCD 1 #define OCTYPE_CON 2 #define NUM_OCTYPES 3 /* number of values above. i.e. last value +1. */ struct { ptt_method_t ptt_method; /* none, serial port, GPIO, LPT, HAMLIB, CM108. */ char ptt_device[128]; /* Serial device name for PTT. e.g. COM1 or /dev/ttyS0 */ /* Also used for HAMLIB. Could be host:port when model is 1. */ /* For years, 20 characters was plenty then we start getting extreme names like this: */ /* /dev/serial/by-id/usb-FTDI_Navigator__CAT___2nd_PTT__00000000-if00-port0 */ /* /dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller_D-if00-port0 */ /* Issue 104, changed to 100 bytes in version 1.5. */ /* This same field is also used for CM108/CM119 GPIO PTT which will */ /* have a name like /dev/hidraw1 for Linux or */ /* \\?\hid#vid_0d8c&pid_0008&mi_03#8&39d3555&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030} */ /* for Windows. Largest observed was 95 but add some extra to be safe. */ ptt_line_t ptt_line; /* Control line when using serial port. PTT_LINE_RTS, PTT_LINE_DTR. */ ptt_line_t ptt_line2; /* Optional second one: PTT_LINE_NONE when not used. */ int out_gpio_num; /* GPIO number. Originally this was only for PTT. */ /* It is now more general. */ /* octrl array is indexed by PTT, DCD, or CONnected indicator. */ /* For CM108/CM119, this should be in range of 1-8. */ #define MAX_GPIO_NAME_LEN 20 // 12 would cover any case I've seen so this should be safe char out_gpio_name[MAX_GPIO_NAME_LEN]; /* originally, gpio number NN was assumed to simply */ /* have the name gpioNN but this turned out not to be */ /* the case for CubieBoard where it was longer. */ /* This is filled in by ptt_init so we don't have to */ /* recalculate it each time we access it. */ /* This could probably be collapsed into ptt_device instead of being separate. */ int ptt_lpt_bit; /* Bit number for parallel printer port. */ /* Bit 0 = pin 2, ..., bit 7 = pin 9. */ int ptt_invert; /* Invert the output. */ int ptt_invert2; /* Invert the secondary output. */ #ifdef USE_HAMLIB int ptt_model; /* HAMLIB model. -1 for AUTO. 2 for rigctld. Others are radio model. */ int ptt_rate; /* Serial port speed when using hamlib CAT control for PTT. */ /* If zero, hamlib will come up with a default for pariticular rig. */ #endif } octrl[NUM_OCTYPES]; /* Each channel can also have associated input lines. */ /* So far, we just have one for transmit inhibit. */ #define ICTYPE_TXINH 0 #define NUM_ICTYPES 1 /* number of values above. i.e. last value +1. */ struct { ptt_method_t method; /* none, serial port, GPIO, LPT. */ int in_gpio_num; /* GPIO number */ char in_gpio_name[MAX_GPIO_NAME_LEN]; /* originally, gpio number NN was assumed to simply */ /* have the name gpioNN but this turned out not to be */ /* the case for CubieBoard where it was longer. */ /* This is filled in by ptt_init so we don't have to */ /* recalculate it each time we access it. */ int invert; /* 1 = active low */ } ictrl[NUM_ICTYPES]; /* Transmit timing. */ int dwait; /* First wait extra time for receiver squelch. */ /* Default 0 units of 10 mS each . */ int slottime; /* Slot time in 10 mS units for persistence algorithm. */ /* Typical value is 10 meaning 100 milliseconds. */ int persist; /* Sets probability for transmitting after each */ /* slot time delay. Transmit if a random number */ /* in range of 0 - 255 <= persist value. */ /* Otherwise wait another slot time and try again. */ /* Default value is 63 for 25% probability. */ int txdelay; /* After turning on the transmitter, */ /* send "flags" for txdelay * 10 mS. */ /* Default value is 30 meaning 300 milliseconds. */ int txtail; /* Amount of time to keep transmitting after we */ /* are done sending the data. This is to avoid */ /* dropping PTT too soon and chopping off the end */ /* of the frame. Again 10 mS units. */ /* At this point, I'm thinking of 10 (= 100 mS) as the default */ /* because we're not quite sure when the soundcard audio stops. */ int fulldup; /* Full Duplex. */ } achan[MAX_CHANS]; #ifdef USE_HAMLIB int rigs; /* Total number of configured rigs */ RIG *rig[MAX_RIGS]; /* HAMLib rig instances */ #endif }; #if __WIN32__ #define DEFAULT_ADEVICE "" /* Windows: Empty string = default audio device. */ #elif __APPLE__ #define DEFAULT_ADEVICE "" /* Mac OSX: Empty string = default audio device. */ #elif USE_ALSA #define DEFAULT_ADEVICE "default" /* Use default device for ALSA. */ #elif USE_SNDIO #define DEFAULT_ADEVICE "default" /* Use default device for sndio. */ #else #define DEFAULT_ADEVICE "/dev/dsp" /* First audio device for OSS. (FreeBSD) */ #endif /* * UDP audio receiving port. Couldn't find any standard or usage precedent. * Got the number from this example: http://gqrx.dk/doc/streaming-audio-over-udp * Any better suggestions? */ #define DEFAULT_UDP_AUDIO_PORT 7355 // Maximum size of the UDP buffer (for allowing IP routing, udp packets are often limited to 1472 bytes) #define SDR_UDP_BUF_MAXLEN 2000 #define DEFAULT_NUM_CHANNELS 1 #define DEFAULT_SAMPLES_PER_SEC 44100 /* Very early observations. Might no longer be valid. */ /* 22050 works a lot better than 11025. */ /* 44100 works a little better than 22050. */ /* If you have a reasonable machine, use the highest rate. */ #define MIN_SAMPLES_PER_SEC 8000 //#define MAX_SAMPLES_PER_SEC 48000 /* Originally 44100. Later increased because */ /* Software Defined Radio often uses 48000. */ #define MAX_SAMPLES_PER_SEC 192000 /* The cheap USB-audio adapters (e.g. CM108) can handle 44100 and 48000. */ /* The "soundcard" in my desktop PC can do 96kHz or even 192kHz. */ /* We will probably need to increase the sample rate to go much above 9600 baud. */ #define DEFAULT_BITS_PER_SAMPLE 16 #define DEFAULT_FIX_BITS RETRY_INVERT_SINGLE /* * Standard for AFSK on VHF FM. * Reversing mark and space makes no difference because * NRZI encoding only cares about change or lack of change * between the two tones. * * HF SSB uses 300 baud and 200 Hz shift. * 1600 & 1800 Hz is a popular tone pair, sometimes * called the KAM tones. */ #define DEFAULT_MARK_FREQ 1200 #define DEFAULT_SPACE_FREQ 2200 #define DEFAULT_BAUD 1200 /* Used for sanity checking in config file and command line options. */ /* 9600 baud is known to work. */ /* TODO: Is 19200 possible with a soundcard at 44100 samples/sec or do we need a higher sample rate? */ #define MIN_BAUD 100 //#define MAX_BAUD 10000 #define MAX_BAUD 40000 // Anyone want to try 38.4 k baud? /* * Typical transmit timings for VHF. */ #define DEFAULT_DWAIT 0 #define DEFAULT_SLOTTIME 10 #define DEFAULT_PERSIST 63 #define DEFAULT_TXDELAY 30 #define DEFAULT_TXTAIL 10 #define DEFAULT_FULLDUP 0 /* * Note that we have two versions of these in audio.c and audio_win.c. * Use one or the other depending on the platform. */ int audio_open(struct audio_s *pa); int audio_get(int a); /* a = audio device, 0 for first */ int audio_put(int a, int c); int audio_flush(int a); void audio_wait(int a); int audio_close(void); /* end audio.h */ void multi_modem_init(struct audio_s *pmodem); void multi_modem_process_sample(int c, int audio_sample); int multi_modem_get_dc_average(int chan); // Deprecated. Replace with ...packet void multi_modem_process_rec_packet(int chan, int subchan, int slice, packet_t pp, alevel_t alevel, retry_t retries, int is_fx25); void fsk_gen_filter(int samples_per_sec, int baud, int mark_freq, int space_freq, char profile, struct demodulator_state_s *D); /* fsk_demod_state.h */ /* * Demodulator state. * The name of the file is from we only had FSK. Now we have other techniques. * Different copy is required for each channel & subchannel being processed concurrently. */ // TODO1.2: change prefix from BP_ to DSP_ typedef enum bp_window_e { BP_WINDOW_TRUNCATED, BP_WINDOW_COSINE, BP_WINDOW_HAMMING, BP_WINDOW_BLACKMAN, BP_WINDOW_FLATTOP } bp_window_t; // Experimental low pass filter to detect DC bias or low frequency changes. // IIR behaves like an analog R-C filter. // Intuitively, it seems like FIR would be better because it is based on a finite history. // However, it would require MANY taps and a LOT of computation for a low frequency. // We can use a little trick here to keep a running average. // This would be equivalent to convolving with an array of all 1 values. // That would eliminate the need to multiply. // We can also eliminate the need to add them all up each time by keeping a running total. // Add a sample to the total when putting it in our array of recent samples. // Subtract it from the total when it gets pushed off the end. // We can also eliminate the need to shift them all down by using a circular buffer. #define CIC_LEN_MAX 4000 typedef struct cic_s { int len; // Number of elements used. // Might want to dynamically allocate. short in[CIC_LEN_MAX]; // Samples coming in. int sum; // Running sum. int inext; // Next position to fill. } cic_t; #define MAX_FILTER_SIZE 480 /* 401 is needed for profile A, 300 baud & 44100. Revisit someday. */ // Size comes out to 417 for 1200 bps with 48000 sample rate // v1.7 - Was 404. Bump up to 480. struct demodulator_state_s { /* * These are set once during initialization. */ enum modem_t modem_type; // MODEM_AFSK, MODEM_8PSK, etc. // enum v26_e v26_alt; // Which alternative when V.26. char profile; // 'A', 'B', etc. Upper case. // Only needed to see if we are using 'F' to take fast path. #define TICKS_PER_PLL_CYCLE ( 256.0 * 256.0 * 256.0 * 256.0 ) int pll_step_per_sample; // PLL is advanced by this much each audio sample. // Data is sampled when it overflows. /* * Window type for the various filters. */ bp_window_t lp_window; /* * Alternate Low pass filters. * First is arbitrary number for quick IIR. * Second is frequency as ratio to baud rate for FIR. */ int lpf_use_fir; /* 0 for IIR, 1 for FIR. */ float lpf_iir; /* Only if using IIR. */ float lpf_baud; /* Cutoff frequency as fraction of baud. */ /* Intuitively we'd expect this to be somewhere */ /* in the range of 0.5 to 1. */ /* In practice, it turned out a little larger */ /* for profiles B, C, D. */ float lp_filter_width_sym; /* Length in number of symbol times. */ #define lp_filter_len_bits lp_filter_width_sym // FIXME: temp hack int lp_filter_taps; /* Size of Low Pass filter, in audio samples. */ #define lp_filter_size lp_filter_taps // FIXME: temp hack /* * Automatic gain control. Fast attack and slow decay factors. */ float agc_fast_attack; float agc_slow_decay; /* * Use a longer term view for reporting signal levels. */ float quick_attack; float sluggish_decay; /* * Hysteresis before final demodulator 0 / 1 decision. */ float hysteresis; int num_slicers; /* >1 for multiple slicers. */ /* * Phase Locked Loop (PLL) inertia. * Larger number means less influence by signal transitions. * It is more resistant to change when locked on to a signal. */ float pll_locked_inertia; float pll_searching_inertia; /* * Optional band pass pre-filter before mark/space detector. */ int use_prefilter; /* True to enable it. */ float prefilter_baud; /* Cutoff frequencies, as fraction of */ /* baud rate, beyond tones used. */ /* Example, if we used 1600/1800 tones at */ /* 300 baud, and this was 0.5, the cutoff */ /* frequencies would be: */ /* lower = min(1600,1800) - 0.5 * 300 = 1450 */ /* upper = max(1600,1800) + 0.5 * 300 = 1950 */ float pre_filter_len_sym; // Length in number of symbol times. #define pre_filter_len_bits pre_filter_len_sym // temp until all references changed. bp_window_t pre_window; // Window type for filter shaping. int pre_filter_taps; // Calculated number of filter taps. #define pre_filter_size pre_filter_taps // temp until all references changed. float pre_filter[MAX_FILTER_SIZE]; float raw_cb[MAX_FILTER_SIZE]; // audio in, need better name. /* * The rest are continuously updated. */ unsigned int lo_phase; /* Local oscillator for PSK. */ /* * Use half of the AGC code to get a measure of input audio amplitude. * These use "quick" attack and "sluggish" decay while the * AGC uses "fast" attack and "slow" decay. */ float alevel_rec_peak; float alevel_rec_valley; float alevel_mark_peak; float alevel_space_peak; /* * Outputs from the mark and space amplitude detection, * used as inputs to the FIR lowpass filters. * Kernel for the lowpass filters. */ float lp_filter[MAX_FILTER_SIZE]; float m_peak, s_peak; float m_valley, s_valley; float m_amp_prev, s_amp_prev; /* * For the PLL and data bit timing. * starting in version 1.2 we can have multiple slicers for one demodulator. * Each slicer has its own PLL and HDLC decoder. */ /* * Version 1.3: Clean up subchan vs. slicer. * * Originally some number of CHANNELS (originally 2, later 6) * which can have multiple parallel demodulators called SUB-CHANNELS. * This was originally for staggered frequencies for HF SSB. * It can also be used for multiple demodulators with the same * frequency but other differing parameters. * Each subchannel has its own demodulator and HDLC decoder. * * In version 1.2 we added multiple SLICERS. * The data structure, here, has multiple slicers per * demodulator (subchannel). Due to fuzzy thinking or * expediency, the multiple slicers got mapped into subchannels. * This means we can't use both multiple decoders and * multiple slicers at the same time. * * Clean this up in 1.3 and keep the concepts separate. * This means adding a third variable many places * we are passing around the origin. * */ struct { signed int data_clock_pll; // PLL for data clock recovery. // It is incremented by pll_step_per_sample // for each audio sample. // Must be 32 bits!!! // So far, this is the case for every compiler used. signed int prev_d_c_pll; // Previous value of above, before // incrementing, to detect overflows. int pll_symbol_count; // Number symbols during time nudge_total is accumulated. int64_t pll_nudge_total; // Sum of DPLL nudge amounts. // Both of these are cleared at start of frame. // At end of frame, we can see if incoming // baud rate is a little off. int prev_demod_data; // Previous data bit detected. // Used to look for transitions. float prev_demod_out_f; /* This is used only for "9600" baud data. */ int lfsr; // Descrambler shift register. // This is for detecting phase lock to incoming signal. int good_flag; // Set if transition is near where expected, // i.e. at a good time. int bad_flag; // Set if transition is not where expected, // i.e. at a bad time. unsigned char good_hist; // History of good transitions for past octet. unsigned char bad_hist; // History of bad transitions for past octet. unsigned int score; // History of whether good triumphs over bad // for past 32 symbols. int data_detect; // True when locked on to signal. } slicer[MAX_SLICERS]; // Actual number in use is num_slicers. // Should be in range 1 .. MAX_SLICERS, /* * Version 1.6: * * This has become quite disorganized and messy with different combinations of * fields used for different demodulator types. Start to reorganize it into a common * part (with things like the DPLL for clock recovery), and separate sections * for each of the demodulator types. * Still a lot to do here. */ union { ////////////////////////////////////////////////////////////////////////////////// // // // AFSK only - new method in 1.7 // // // ////////////////////////////////////////////////////////////////////////////////// struct afsk_only_s { unsigned int m_osc_phase; // Phase for Mark local oscillator. unsigned int m_osc_delta; // How much to change for each audio sample. unsigned int s_osc_phase; // Phase for Space local oscillator. unsigned int s_osc_delta; // How much to change for each audio sample. unsigned int c_osc_phase; // Phase for Center frequency local oscillator. unsigned int c_osc_delta; // How much to change for each audio sample. // Need two mixers for profile "A". float m_I_raw[MAX_FILTER_SIZE]; float m_Q_raw[MAX_FILTER_SIZE]; float s_I_raw[MAX_FILTER_SIZE]; float s_Q_raw[MAX_FILTER_SIZE]; // Only need one mixer for profile "B". Reuse the same storage? //#define c_I_raw m_I_raw //#define c_Q_raw m_Q_raw float c_I_raw[MAX_FILTER_SIZE]; float c_Q_raw[MAX_FILTER_SIZE]; int use_rrc; // Use RRC rather than generic low pass. float rrc_width_sym; /* Width of RRC filter in number of symbols. */ float rrc_rolloff; /* Rolloff factor for RRC. Between 0 and 1. */ float prev_phase; // To see phase shift between samples for FM demod. float normalize_rpsam; // Normalize to -1 to +1 for expected tones. } afsk; ////////////////////////////////////////////////////////////////////////////////// // // // Baseband only, AKA G3RUH // // // ////////////////////////////////////////////////////////////////////////////////// // TODO: Continue experiments with root raised cosine filter. // Either switch to that or take out all the related stuff. struct bb_only_s { float rrc_width_sym; /* Width of RRC filter in number of symbols. */ float rrc_rolloff; /* Rolloff factor for RRC. Between 0 and 1. */ int rrc_filter_taps; // Number of elements used in the next two. // FIXME: TODO: reevaluate max size needed. float audio_in[MAX_FILTER_SIZE]; // Audio samples in. float lp_filter[MAX_FILTER_SIZE]; // Low pass filter. // New in 1.7 - Polyphase filter to reduce CPU requirements. float lp_polyphase_1[MAX_FILTER_SIZE]; float lp_polyphase_2[MAX_FILTER_SIZE]; float lp_polyphase_3[MAX_FILTER_SIZE]; float lp_polyphase_4[MAX_FILTER_SIZE]; float lp_1_iir_param; // very low pass filters to get DC offset. float lp_1_out; float lp_2_iir_param; float lp_2_out; float agc_1_fast_attack; // Signal envelope detection. float agc_1_slow_decay; float agc_1_peak; float agc_1_valley; float agc_2_fast_attack; float agc_2_slow_decay; float agc_2_peak; float agc_2_valley; float agc_3_fast_attack; float agc_3_slow_decay; float agc_3_peak; float agc_3_valley; // CIC low pass filters to detect DC bias or low frequency changes. // IIR behaves like an analog R-C filter. // Intuitively, it seems like FIR would be better because it is based on a finite history. // However, it would require MANY taps and a LOT of computation for a low frequency. // We can use a little trick here to keep a running average. // This would be equivalent to convolving with an array of all 1 values. // That would eliminate the need to multiply. // We can also eliminate the need to add them all up each time by keeping a running total. // Add a sample to the total when putting it in our array of recent samples. // Subtract it from the total when it gets pushed off the end. // We can also eliminate the need to shift them all down by using a circular buffer. // This only works with integers because float would have cumulated round off errors. cic_t cic_center1; cic_t cic_above; cic_t cic_below; } bb; ////////////////////////////////////////////////////////////////////////////////// // // // PSK only. // // // ////////////////////////////////////////////////////////////////////////////////// struct psk_only_s { enum v26_e v26_alt; // Which alternative when V.26. float sin_table256[256]; // Precomputed sin table for speed. // Optional band pass pre-filter before phase detector. // TODO? put back into common section? // TODO? Why was I thinking that? int use_prefilter; // True to enable it. float prefilter_baud; // Cutoff frequencies, as fraction of baud rate, beyond tones used. // In the case of PSK, we use only a single tone of 1800 Hz. // If we were using 2400 bps (= 1200 baud), this would be // the fraction of 1200 for the cutoff below and above 1800. float pre_filter_width_sym; /* Length in number of symbol times. */ int pre_filter_taps; /* Size of pre filter, in audio samples. */ bp_window_t pre_window; float audio_in[MAX_FILTER_SIZE]; float pre_filter[MAX_FILTER_SIZE]; // Use local oscillator or correlate with previous sample. int psk_use_lo; /* Use local oscillator rather than self correlation. */ unsigned int lo_step; /* How much to advance the local oscillator */ /* phase for each audio sample. */ unsigned int lo_phase; /* Local oscillator phase accumulator for PSK. */ // After mixing with LO before low pass filter. float I_raw[MAX_FILTER_SIZE]; // signal * LO cos. float Q_raw[MAX_FILTER_SIZE]; // signal * LO sin. // Number of delay line taps into previous symbol. // They are one symbol period and + or - 45 degrees of the carrier frequency. int boffs; /* symbol length based on sample rate and baud. */ int coffs; /* to get cos component of previous symbol. */ int soffs; /* to get sin component of previous symbol. */ float delay_line_width_sym; int delay_line_taps; // In audio samples. float delay_line[MAX_FILTER_SIZE]; // Low pass filter Second is frequency as ratio to baud rate for FIR. // TODO? put back into common section? // TODO? What are the tradeoffs? float lpf_baud; /* Cutoff frequency as fraction of baud. */ /* Intuitively we'd expect this to be somewhere */ /* in the range of 0.5 to 1. */ float lp_filter_width_sym; /* Length in number of symbol times. */ int lp_filter_taps; /* Size of Low Pass filter, in audio samples (i.e. filter taps). */ bp_window_t lp_window; float lp_filter[MAX_FILTER_SIZE]; } psk; } u; // end of union for different demodulator types. }; /*------------------------------------------------------------------- * * Name: pll_dcd_signal_transition2 * dcd_each_symbol2 * * Purpose: New DCD strategy for 1.6. * * Inputs: D Pointer to demodulator state. * * chan Radio channel: 0 to MAX_CHANS - 1 * * subchan Which of multiple demodulators: 0 to MAX_SUBCHANS - 1 * * slice Slicer number: 0 to MAX_SLICERS - 1. * * dpll_phase Signed 32 bit counter for DPLL phase. * Wraparound is where data is sampled. * Ideally transitions would occur close to 0. * * Output: D->slicer[slice].data_detect - true when PLL is locked to incoming signal. * * Description: From the beginning, DCD was based on finding several flag octets * in a row and dropping when eight bits with no transitions. * It was less than ideal but we limped along with it all these years. * This fell apart when FX.25 came along and a couple of the * correlation tags have eight "1" bits in a row. * * Our new strategy is to keep a running score of how well demodulator * output transitions match to where expected. * *--------------------------------------------------------------------*/ // These are good for 1200 bps AFSK. // Might want to override for other modems. #ifndef DCD_THRESH_ON #define DCD_THRESH_ON 30 // Hysteresis: Can miss 2 out of 32 for detecting lock. // 31 is best for TNC Test CD. 30 almost as good. // 30 better for 1200 regression test. #endif #ifndef DCD_THRESH_OFF #define DCD_THRESH_OFF 6 // Might want a little more fine tuning. #endif #ifndef DCD_GOOD_WIDTH #define DCD_GOOD_WIDTH 512 // No more than 1024!!! #endif inline static void pll_dcd_signal_transition2(struct demodulator_state_s *D, int slice, int dpll_phase) { if (dpll_phase > -DCD_GOOD_WIDTH * 1024 * 1024 && dpll_phase < DCD_GOOD_WIDTH * 1024 * 1024) { D->slicer[slice].good_flag = 1; } else { D->slicer[slice].bad_flag = 1; } } inline static void pll_dcd_each_symbol2(struct demodulator_state_s *D, int chan, int subchan, int slice) { D->slicer[slice].good_hist <<= 1; D->slicer[slice].good_hist |= D->slicer[slice].good_flag; D->slicer[slice].good_flag = 0; D->slicer[slice].bad_hist <<= 1; D->slicer[slice].bad_hist |= D->slicer[slice].bad_flag; D->slicer[slice].bad_flag = 0; D->slicer[slice].score <<= 1; // 2 is to detect 'flag' patterns with 2 transitions per octet. D->slicer[slice].score |= (signed)__builtin_popcount(D->slicer[slice].good_hist) - (signed)__builtin_popcount(D->slicer[slice].bad_hist) >= 2; int s = __builtin_popcount(D->slicer[slice].score); if (s >= DCD_THRESH_ON) { if (D->slicer[slice].data_detect == 0) { D->slicer[slice].data_detect = 1; dcd_change(chan, subchan, slice, D->slicer[slice].data_detect); } } else if (s <= DCD_THRESH_OFF) { if (D->slicer[slice].data_detect != 0) { D->slicer[slice].data_detect = 0; dcd_change(chan, subchan, slice, D->slicer[slice].data_detect); } } } /* Provided elsewhere to process a complete frame. */ //void process_rec_frame (int chan, unsigned char *fbuf, int flen, int level); /* Is HLDC decoder is currently gathering bits into a frame? */ /* Similar to, but not exactly the same as, data carrier detect. */ /* We use this to influence the PLL inertia. */ int hdlc_rec_gathering(int chan, int subchan, int slice); /* Transmit needs to know when someone else is transmitting. */ void dcd_change(int chan, int subchan, int slice, int state); int hdlc_rec_data_detect_any(int chan); #define FASTER13 1 // Don't pack 8 samples per byte. //typedef short slice_t; /* * Maximum size (in bytes) of an AX.25 frame including the 2 octet FCS. */ #define MAX_FRAME_LEN ((AX25_MAX_PACKET_LEN) + 2) /* * Maximum number of bits in AX.25 frame excluding the flags. * Adequate for extreme case of bit stuffing after every 5 bits * which could never happen. */ #define MAX_NUM_BITS (MAX_FRAME_LEN * 8 * 6 / 5) typedef struct rrbb_s { int magic1; struct rrbb_s* nextp; /* Next pointer to maintain a queue. */ int chan; /* Radio channel from which it was received. */ int subchan; /* Which modem when more than one per channel. */ int slice; /* Which slicer. */ alevel_t alevel; /* Received audio level at time of frame capture. */ unsigned int len; /* Current number of samples in array. */ int is_scrambled; /* Is data scrambled G3RUH / K9NG style? */ int descram_state; /* Descrambler state before first data bit of frame. */ int prev_descram; /* Previous descrambled bit. */ unsigned char fdata[MAX_NUM_BITS]; int magic2; } *rrbb_t; rrbb_t rrbb_new(int chan, int subchan, int slice, int is_scrambled, int descram_state, int prev_descram); void rrbb_clear(rrbb_t b, int is_scrambled, int descram_state, int prev_descram); static inline /*__attribute__((always_inline))*/ void rrbb_append_bit(rrbb_t b, const unsigned char val) { if (b->len >= MAX_NUM_BITS) { return; /* Silently discard if full. */ } b->fdata[b->len] = val; b->len++; } static inline /*__attribute__((always_inline))*/ unsigned char rrbb_get_bit(const rrbb_t b, const int ind) { return (b->fdata[ind]); } void rrbb_chop8(rrbb_t b); int rrbb_get_len(rrbb_t b); //void rrbb_flip_bit (rrbb_t b, unsigned int ind); void rrbb_delete(rrbb_t b); void rrbb_set_nextp(rrbb_t b, rrbb_t np); rrbb_t rrbb_get_nextp(rrbb_t b); int rrbb_get_chan(rrbb_t b); int rrbb_get_subchan(rrbb_t b); int rrbb_get_slice(rrbb_t b); void rrbb_set_audio_level(rrbb_t b, alevel_t alevel); alevel_t rrbb_get_audio_level(rrbb_t b); int rrbb_get_is_scrambled(rrbb_t b); int rrbb_get_descram_state(rrbb_t b); int rrbb_get_prev_descram(rrbb_t b); void hdlc_rec2_init(struct audio_s *audio_config_p); void hdlc_rec2_block(rrbb_t block); int hdlc_rec2_try_to_fix_later(rrbb_t block, int chan, int subchan, int slice, alevel_t alevel); /* Provided by the top level application to process a complete frame. */ void app_process_rec_packet(int chan, int subchan, int slice, packet_t pp, alevel_t level, int is_fx25, retry_t retries, char *spectrum); int gen_tone_init(struct audio_s *pp, int amp, int gen_packets); //int gen_tone_open (int nchan, int sample_rate, int bit_rate, int f1, int f2, int amp, char *fname); //int gen_tone_open_fd (int nchan, int sample_rate, int bit_rate, int f1, int f2, int amp, int fd) ; //int gen_tone_close (void); void tone_gen_put_bit(int chan, int dat, int scramble); void gen_tone_put_sample(int chan, int a, int sam); enum dw_color_e { DW_COLOR_INFO, /* black */ DW_COLOR_ERROR, /* red */ DW_COLOR_REC, /* green */ DW_COLOR_DECODED, /* blue */ DW_COLOR_XMIT, /* magenta */ DW_COLOR_DEBUG /* dark_green */ }; typedef enum dw_color_e dw_color_t; void text_color_init(int enable_color); void text_color_set(dw_color_t c); void text_color_term(void); /* Degree symbol. */ #if __WIN32__ //#define CH_DEGREE "\xc2\xb0" /* UTF-8. */ #define CH_DEGREE " " #else /* Maybe we could change this based on LANG environment variable. */ //#define CH_DEGREE "\xc2\xb0" /* UTF-8. */ #define CH_DEGREE " " #endif /* demod_9600.h */ void demod_9600_init(enum modem_t modem_type, int original_sample_rate, int upsample, int baud, struct demodulator_state_s *D); void demod_9600_process_sample(int chan, int sam, int upsample, struct demodulator_state_s *D); /* Undo data scrambling for 9600 baud. */ static inline int descramble(int in, int *state) { int out; out = (in ^ (*state >> 16) ^ (*state >> 11)) & 1; *state = (*state << 1) | (in & 1); return (out); }