static bool noHandleOption(int argc, char **argv, int *jptr) { MODES_NOTUSED(argc); MODES_NOTUSED(argv); MODES_NOTUSED(jptr); return false; }
// //========================================================================= // // We use a thread reading data in background, while the main thread // handles decoding and visualization of data to the user. // // The reading thread calls the RTLSDR API to read data asynchronously, and // uses a callback to populate the data buffer. // // A Mutex is used to avoid races with the decoding thread. // void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx) { MODES_NOTUSED(ctx); // Lock the data buffer variables before accessing them pthread_mutex_lock(&Modes.data_mutex); Modes.iDataIn &= (MODES_ASYNC_BUF_NUMBER-1); // Just incase!!! // Get the system time for this block ftime(&Modes.stSystemTimeRTL[Modes.iDataIn]); if (len > MODES_ASYNC_BUF_SIZE) {len = MODES_ASYNC_BUF_SIZE;} // Queue the new data Modes.pData[Modes.iDataIn] = (uint16_t *) buf; Modes.iDataIn = (MODES_ASYNC_BUF_NUMBER-1) & (Modes.iDataIn + 1); Modes.iDataReady = (MODES_ASYNC_BUF_NUMBER-1) & (Modes.iDataIn - Modes.iDataOut); if (Modes.iDataReady == 0) { // Ooooops. We've just received the MODES_ASYNC_BUF_NUMBER'th outstanding buffer // This means that RTLSDR is currently overwriting the MODES_ASYNC_BUF_NUMBER+1 // buffer, but we havent yet processed it, so we're going to lose it. There // isn't much we can do to recover the lost data, but we can correct things to // avoid any additional problems. Modes.iDataOut = (MODES_ASYNC_BUF_NUMBER-1) & (Modes.iDataOut+1); Modes.iDataReady = (MODES_ASYNC_BUF_NUMBER-1); Modes.iDataLost++; } // Signal to the other thread that new data is ready, and unlock pthread_cond_signal(&Modes.data_cond); pthread_mutex_unlock(&Modes.data_mutex); }
// //========================================================================= // // This function decodes a Beast binary format message // // The message is passed to the higher level layers, so it feeds // the selected screen output, the network output and so forth. // // If the message looks invalid it is silently discarded. // // The function always returns 0 (success) to the caller as there is no // case where we want broken messages here to close the client connection. // int decodeBinMessage(struct client *c, char *p) { int msgLen = 0; unsigned char msg[MODES_LONG_MSG_BYTES]; struct modesMessage mm; MODES_NOTUSED(c); memset(&mm, 0, sizeof(mm)); if ((*p == '1') && (Modes.mode_ac)) { // skip ModeA/C unless user enables --modes-ac msgLen = MODEAC_MSG_BYTES; } else if (*p == '2') { msgLen = MODES_SHORT_MSG_BYTES; } else if (*p == '3') { msgLen = MODES_LONG_MSG_BYTES; } if (msgLen) { // Mark messages received over the internet as remote so that we don't try to // pass them off as being received by this instance when forwarding them mm.remote = 1; p += 7; // Skip the timestamp mm.signalLevel = *p++; // Grab the signal level memcpy(msg, p, msgLen); // and the data if (msgLen == MODEAC_MSG_BYTES) { // ModeA or ModeC decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1])); } else { decodeModesMessage(&mm, msg); } useModesMessage(&mm); } return (0); }
/* We read data using a thread, so the main thread only handles decoding * without caring about data acquisition. */ void *readerThreadEntryPoint(void *arg) { MODES_NOTUSED(arg); rtlsdr_read_async(Modes.dev, rtlsdrCallback, NULL, MODES_ASYNC_BUF_NUMBER, MODES_DATA_LEN); Modes.exit --; return NULL; }
// //========================================================================= // // This function decodes a Beast binary format message // // The message is passed to the higher level layers, so it feeds // the selected screen output, the network output and so forth. // // If the message looks invalid it is silently discarded. // // The function always returns 0 (success) to the caller as there is no // case where we want broken messages here to close the client connection. // int decodeBinMessage(struct client *c, char *p) { int msgLen = 0; int j; char ch; char * ptr; unsigned char msg[MODES_LONG_MSG_BYTES]; struct modesMessage mm; MODES_NOTUSED(c); memset(&mm, 0, sizeof(mm)); ch = *p++; /// Get the message type if (0x1A == ch) {p++;} if ((ch == '1') && (Modes.mode_ac)) { // skip ModeA/C unless user enables --modes-ac msgLen = MODEAC_MSG_BYTES; } else if (ch == '2') { msgLen = MODES_SHORT_MSG_BYTES; } else if (ch == '3') { msgLen = MODES_LONG_MSG_BYTES; } if (msgLen) { // Mark messages received over the internet as remote so that we don't try to // pass them off as being received by this instance when forwarding them mm.remote = 1; ptr = (char*) &mm.timestampMsg; for (j = 0; j < 6; j++) { // Grab the timestamp (big endian format) ptr[5-j] = ch = *p++; if (0x1A == ch) {p++;} } mm.signalLevel = ch = *p++; // Grab the signal level if (0x1A == ch) {p++;} for (j = 0; j < msgLen; j++) { // and the data msg[j] = ch = *p++; if (0x1A == ch) {p++;} } if (msgLen == MODEAC_MSG_BYTES) { // ModeA or ModeC decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1])); } else { decodeModesMessage(&mm, msg); } useModesMessage(&mm); } return (0); }
// //========================================================================= // // We use a thread reading data in background, while the main thread // handles decoding and visualization of data to the user. // // The reading thread calls the RTLSDR API to read data asynchronously, and // uses a callback to populate the data buffer. // // A Mutex is used to avoid races with the decoding thread. // void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx) { MODES_NOTUSED(ctx); pthread_mutex_lock(&Modes.data_mutex); ftime(&Modes.stSystemTimeRTL); if (len > MODES_ASYNC_BUF_SIZE) len = MODES_ASYNC_BUF_SIZE; // Read the new data memcpy(Modes.data, buf, len); Modes.data_ready = 1; // Signal to the other thread that new data is ready pthread_cond_signal(&Modes.data_cond); pthread_mutex_unlock(&Modes.data_mutex); }
/* We use a thread reading data in background, while the main thread * handles decoding and visualization of data to the user. * * The reading thread calls the RTLSDR API to read data asynchronously, and * uses a callback to populate the data buffer. * A Mutex is used to avoid races with the decoding thread. */ void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx) { MODES_NOTUSED(ctx); pthread_mutex_lock(&Modes.data_mutex); if (len > MODES_DATA_LEN) len = MODES_DATA_LEN; /* Move the last part of the previous buffer, that was not processed, * on the start of the new buffer. */ memcpy(Modes.data, Modes.data+MODES_DATA_LEN, (MODES_FULL_LEN-1)*4); /* Read the new data. */ memcpy(Modes.data+(MODES_FULL_LEN-1)*4, buf, len); Modes.data_ready = 1; /* Signal to the other thread that new data is ready */ pthread_cond_signal(&Modes.data_cond); pthread_mutex_unlock(&Modes.data_mutex); }
// //========================================================================= // // We read data using a thread, so the main thread only handles decoding // without caring about data acquisition // void *readerThreadEntryPoint(void *arg) { MODES_NOTUSED(arg); if (Modes.filename == NULL) { rtlsdr_read_async(Modes.dev, rtlsdrCallback, NULL, MODES_ASYNC_BUF_NUMBER, MODES_ASYNC_BUF_SIZE); } else { readDataFromFile(); } // Signal to the other thread that new data is ready - dummy really so threads don't mutually lock pthread_cond_signal(&Modes.data_cond); pthread_mutex_unlock(&Modes.data_mutex); #ifndef _WIN32 pthread_exit(NULL); #else return NULL; #endif }
void *readerThreadEntryPoint(void *arg) { MODES_NOTUSED(arg); start_cpu_timing(&reader_thread_start); // we accumulate in rtlsdrCallback() or readDataFromFile() if (Modes.filename == NULL) { while (!Modes.exit) { rtlsdr_read_async(Modes.dev, rtlsdrCallback, NULL, MODES_RTL_BUFFERS, MODES_RTL_BUF_SIZE); if (!Modes.exit) { log_with_timestamp("Warning: lost the connection to the RTLSDR device."); rtlsdr_close(Modes.dev); Modes.dev = NULL; do { sleep(5); log_with_timestamp("Trying to reconnect to the RTLSDR device.."); } while (!Modes.exit && modesInitRTLSDR() < 0); } } if (Modes.dev != NULL) { rtlsdr_close(Modes.dev); Modes.dev = NULL; } } else { readDataFromFile(); } // Wake the main thread (if it's still waiting) pthread_mutex_lock(&Modes.data_mutex); Modes.exit = 1; // just in case pthread_cond_signal(&Modes.data_cond); pthread_mutex_unlock(&Modes.data_mutex); #ifndef _WIN32 pthread_exit(NULL); #else return NULL; #endif }
// // ============================= Utility functions ========================== // void sigintHandler(int dummy) { MODES_NOTUSED(dummy); signal(SIGINT, SIG_DFL); // reset signal handler - bit extra safety Modes.exit = 1; // Signal to threads that we are done }
// //========================================================================= // // This function decodes a string representing message in raw hex format // like: *8D4B969699155600E87406F5B69F; The string is null-terminated. // // The message is passed to the higher level layers, so it feeds // the selected screen output, the network output and so forth. // // If the message looks invalid it is silently discarded. // // The function always returns 0 (success) to the caller as there is no // case where we want broken messages here to close the client connection. // int decodeHexMessage(struct client *c, char *hex) { int l = strlen(hex), j; unsigned char msg[MODES_LONG_MSG_BYTES]; struct modesMessage mm; MODES_NOTUSED(c); memset(&mm, 0, sizeof(mm)); // Mark messages received over the internet as remote so that we don't try to // pass them off as being received by this instance when forwarding them mm.remote = 1; mm.signalLevel = 0xFF; // Remove spaces on the left and on the right while(l && isspace(hex[l-1])) { hex[l-1] = '\0'; l--; } while(isspace(*hex)) { hex++; l--; } // Turn the message into binary. // Accept *-AVR raw @-AVR/BEAST timeS+raw %-AVR timeS+raw (CRC good) <-BEAST timeS+sigL+raw // and some AVR records that we can understand if (hex[l-1] != ';') {return (0);} // not complete - abort switch(hex[0]) { case '<': { mm.signalLevel = (hexDigitVal(hex[13])<<4) | hexDigitVal(hex[14]); hex += 15; l -= 16; // Skip <, timestamp and siglevel, and ; break;} case '@': // No CRC check case '%': { // CRC is OK hex += 13; l -= 14; // Skip @,%, and timestamp, and ; break;} case '*': case ':': { hex++; l-=2; // Skip * and ; break;} default: { return (0); // We don't know what this is, so abort break;} } if ( (l != (MODEAC_MSG_BYTES * 2)) && (l != (MODES_SHORT_MSG_BYTES * 2)) && (l != (MODES_LONG_MSG_BYTES * 2)) ) {return (0);} // Too short or long message... broken if ( (0 == Modes.mode_ac) && (l == (MODEAC_MSG_BYTES * 2)) ) {return (0);} // Right length for ModeA/C, but not enabled for (j = 0; j < l; j += 2) { int high = hexDigitVal(hex[j]); int low = hexDigitVal(hex[j+1]); if (high == -1 || low == -1) return 0; msg[j/2] = (high << 4) | low; } if (l == (MODEAC_MSG_BYTES * 2)) { // ModeA or ModeC decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1])); } else { // Assume ModeS decodeModesMessage(&mm, msg); } useModesMessage(&mm); return (0); }
static void sigtermHandler(int dummy) { MODES_NOTUSED(dummy); signal(SIGTERM, SIG_DFL); // reset signal handler - bit extra safety Modes.exit = 1; // Signal to threads that we are done log_with_timestamp("Caught SIGTERM, shutting down..\n"); }
void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx) { struct mag_buf *outbuf; struct mag_buf *lastbuf; uint32_t slen; unsigned next_free_buffer; unsigned free_bufs; unsigned block_duration; static int was_odd = 0; // paranoia!! static int dropping = 0; MODES_NOTUSED(ctx); // Lock the data buffer variables before accessing them pthread_mutex_lock(&Modes.data_mutex); if (Modes.exit) { rtlsdr_cancel_async(Modes.dev); // ask our caller to exit } next_free_buffer = (Modes.first_free_buffer + 1) % MODES_MAG_BUFFERS; outbuf = &Modes.mag_buffers[Modes.first_free_buffer]; lastbuf = &Modes.mag_buffers[(Modes.first_free_buffer + MODES_MAG_BUFFERS - 1) % MODES_MAG_BUFFERS]; free_bufs = (Modes.first_filled_buffer - next_free_buffer + MODES_MAG_BUFFERS) % MODES_MAG_BUFFERS; // Paranoia! Unlikely, but let's go for belt and suspenders here if (len != MODES_RTL_BUF_SIZE) { fprintf(stderr, "weirdness: rtlsdr gave us a block with an unusual size (got %u bytes, expected %u bytes)\n", (unsigned)len, (unsigned)MODES_RTL_BUF_SIZE); if (len > MODES_RTL_BUF_SIZE) { // wat?! Discard the start. unsigned discard = (len - MODES_RTL_BUF_SIZE + 1) / 2; outbuf->dropped += discard; buf += discard*2; len -= discard*2; } } if (was_odd) { // Drop a sample so we are in sync with I/Q samples again (hopefully) ++buf; --len; ++outbuf->dropped; } was_odd = (len & 1); slen = len/2; if (free_bufs == 0 || (dropping && free_bufs < MODES_MAG_BUFFERS/2)) { // FIFO is full. Drop this block. dropping = 1; outbuf->dropped += slen; pthread_mutex_unlock(&Modes.data_mutex); return; } dropping = 0; pthread_mutex_unlock(&Modes.data_mutex); // Compute the sample timestamp and system timestamp for the start of the block outbuf->sampleTimestamp = lastbuf->sampleTimestamp + 12e6 * (lastbuf->length + outbuf->dropped) / Modes.sample_rate; block_duration = 1e9 * slen / Modes.sample_rate; // Get the approx system time for the start of this block clock_gettime(CLOCK_REALTIME, &outbuf->sysTimestamp); outbuf->sysTimestamp.tv_nsec -= block_duration; normalize_timespec(&outbuf->sysTimestamp); // Copy trailing data from last block (or reset if not valid) if (outbuf->dropped == 0 && lastbuf->length >= Modes.trailing_samples) { memcpy(outbuf->data, lastbuf->data + lastbuf->length - Modes.trailing_samples, Modes.trailing_samples * sizeof(uint16_t)); } else { memset(outbuf->data, 0, Modes.trailing_samples * sizeof(uint16_t)); } // Convert the new data outbuf->length = slen; convert_samples(buf, &outbuf->data[Modes.trailing_samples], slen, &outbuf->total_power); // Push the new data to the demodulation thread pthread_mutex_lock(&Modes.data_mutex); Modes.mag_buffers[next_free_buffer].dropped = 0; Modes.mag_buffers[next_free_buffer].length = 0; // just in case Modes.first_free_buffer = next_free_buffer; // accumulate CPU while holding the mutex, and restart measurement end_cpu_timing(&reader_thread_start, &Modes.reader_cpu_accumulator); start_cpu_timing(&reader_thread_start); pthread_cond_signal(&Modes.data_cond); pthread_mutex_unlock(&Modes.data_mutex); }