This is highly experimental.
Last active
August 29, 2015 14:05
-
-
Save bewest/6d05f80c932cc282ecfd to your computer and use it in GitHub Desktop.
medtronic symbol table
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CC=gcc | |
CFLAGS=-lm -pthread | |
rtl_mmpump: rtl_mmpump.c | |
# xxx: gcc ./rtl_mmpump.c -pthread -lm $(pkg-config --libs --cflags libusb-1.0 librtlsdr) | |
$(CC) -o $@ $< $(CFLAGS) $(shell pkg-config --libs --cflags libusb-1.0 librtlsdr) | |
all: rtl_mmpump |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver | |
* Copyright (C) 2012 by Steve Markgraf <[email protected]> | |
* Copyright (C) 2012 by Hoernchen <[email protected]> | |
* Copyright (C) 2012 by Kyle Keen <[email protected]> | |
* Copyright (C) 2012 by Youssef Touil <[email protected]> | |
* Copyright (C) 2012 by Ian Gilmour <[email protected]> | |
* | |
* 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 <http://www.gnu.org/licenses/>. | |
*/ | |
/* | |
This program is intended to sniff data from our Medtronic/Minimed-enabled | |
devices. Must be used ONLY for educational purposes and the author | |
won't be responsible for any damage caused by or with this software. | |
4b6b decoding errors are marked in yellow (don't expect the data and the | |
CRC to be OK in those cases) and happen quite a lot. I think it may be an | |
issue with the buffering or the gain control. I haven't tested it with | |
USA devices but it should work only tuning at 916.5 MHz. | |
Feel free to play with it ;-). | |
[email protected] | |
*/ | |
#include <errno.h> | |
#include <signal.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <math.h> | |
#ifndef _WIN32 | |
#include <unistd.h> | |
#else | |
#include <Windows.h> | |
#include <fcntl.h> | |
#include <io.h> | |
#include "getopt/getopt.h" | |
#endif | |
#include <pthread.h> | |
#include <libusb.h> | |
#include "rtl-sdr.h" | |
#ifdef _WIN32 | |
BOOL WINAPI sighandler(int signum); | |
#else | |
static void sighandler(int signum); | |
#endif | |
void usage(void); | |
char crc8 (char *message, int nBytes); | |
unsigned short crc16 (char *ptr, unsigned int len); | |
void hexDump (char *desc, char *addr, char *errors, int len); | |
void decodeMsg (char *msg, char *msgErr, int msgLen); | |
inline int decode4b6b (uint16_t symbolIn, uint16_t *symbolOut, int *error); | |
inline int getSymbol (uint16_t *buf, int maximum_i, int *i, | |
double bitSize, uint16_t *Symbol); | |
inline int preamble(uint16_t *buf, int i); | |
void filter_signal (uint16_t *buf, int len); | |
void getBits (uint16_t *buf, int len); | |
void getBits2 (uint16_t *buf, int len); | |
void lookForMsg(uint16_t *buf, int len); | |
int magnitute(uint8_t *buf, int len); | |
static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx); | |
static void *demod_thread_fn(void *arg); | |
#ifdef _WIN32 | |
#define sleep Sleep | |
#define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5)) | |
#endif | |
#define MMPUMP_RATE 2000000 | |
#define MMPUMP_FREQ_EUROPE 868350000 | |
#define MMPUMP_FREQ_USA 916500000 | |
#define DEFAULT_ASYNC_BUF_NUMBER 12 | |
#define DEFAULT_BUF_LENGTH (16 * 16384) | |
#define AUTO_GAIN -100 | |
#define FILTER_LEN 80 | |
#define MESSAGEGO 253 | |
#define OVERWRITE 254 | |
#define BADSAMPLE 255 | |
static pthread_t demod_thread; | |
static pthread_mutex_t data_ready; /* locked when no data available */ | |
static volatile int do_exit = 0; | |
static rtlsdr_dev_t *dev = NULL; | |
static uint16_t buffer2[264000]; | |
static uint16_t buffer3[264000]; | |
static int buffer3len; | |
static char recMsg [256]; | |
static char recErr [256]; | |
static int recMsgLen ; | |
static int recTotalErr ; | |
static int lastPreambleIdx; | |
static int msgNotFinished; | |
static int actualMsgId; | |
static unsigned short crc_tab[256]; | |
/* todo, bundle these up in a struct */ | |
uint8_t *buffer; /* also abused for uint16_t */ | |
int verbose_output = 0; | |
int maxval; | |
int short_output = 0; | |
double quality = 1.0; | |
int allowed_errors = 5; | |
FILE *file; | |
int adsb_frame[14]; | |
#define preamble_len 48 | |
#define long_frame 112 | |
#define short_frame 56 | |
void usage(void) | |
{ | |
fprintf(stderr, | |
"\nrtl_mmpump, a simple Medtronic-Minimed device sniffer\n\n" | |
"Use:\trtl_mmpump [-U] [-g gain] [-d device] [filename]\n" | |
"\t[-d device_index (default: 0)]\n" | |
"\t[-U USA Frequency mode (default: 0)\n" | |
"\t[-g tuner_gain (default: automatic)]\n" | |
"\t[filename] (a '-' dumps samples to stdout)\n" | |
"\n"); | |
exit(1); | |
} | |
char crc8 (char *message, int nBytes) | |
{ | |
char remainder = 0; | |
int byte; | |
char bit; | |
for (byte = 0; byte < nBytes; ++byte) | |
{ | |
remainder ^= message[byte]; | |
for (bit = 8; bit > 0; --bit) | |
{ | |
if (remainder & 0x80) | |
remainder = (remainder << 1) ^ 0x9B; | |
else | |
remainder = (remainder << 1); | |
} | |
} | |
remainder = remainder & 0x000000FF; | |
return remainder; | |
} | |
unsigned short crc16 (char *ptr, unsigned int len) | |
{ | |
unsigned int i, j ; | |
unsigned short crc, c, short_c, tmp; | |
// Init CRC tab. This could be done only once, but I'll do it | |
// everytime for simplicity. | |
for (i=0; i<256; i++) { | |
crc = 0; | |
c = ((unsigned short) i) << 8; | |
for (j=0; j<8; j++) { | |
if ( (crc ^ c) & 0x8000 ) crc = ( crc << 1 ) ^ 0x1021; | |
else crc = crc << 1; | |
c = c << 1; | |
} | |
crc_tab[i] = crc; | |
} | |
// CRC calculation. | |
crc = 0xffff; | |
for (i=0; i<len; i++) { | |
short_c = 0x00ff & (unsigned short) ptr[i]; | |
tmp = (crc >> 8) ^ short_c; | |
crc = (crc << 8) ^ crc_tab[tmp]; | |
} | |
return (crc); | |
} | |
void hexDump (char *desc, char *addr, char *errors, int len) { | |
int i; | |
unsigned char buff[17]; | |
char *pc = addr; | |
// Output description if given. | |
printf("%s:\n",desc); | |
// Process every byte in the data. | |
for (i = 0; i < len; i++) { | |
// Multiple of 16 means new line (with line offset). | |
if ((i % 16) == 0) { | |
// Just don't print ASCII for the zeroth line. | |
if (i != 0) | |
printf (" %s\n", buff); | |
// Output the offset. | |
printf (" %04x ", i); | |
} | |
// Now the hex code for the specific character. | |
if (errors[i] == 1) printf("%c[1;33m",27); | |
printf (" %02x", (pc[i] & 0x000000FF)); | |
if (errors[i] == 1) printf("%c[0;00m",27); | |
// And store a printable ASCII character for later. | |
if ((pc[i] < 0x20) || (pc[i] > 0x7e)) | |
buff[i % 16] = '.'; | |
else | |
buff[i % 16] = pc[i]; | |
buff[(i % 16) + 1] = '\0'; | |
} | |
// Pad out last line if not exactly 16 characters. | |
while ((i % 16) != 0) { | |
printf (" "); | |
i++; | |
} | |
// And print the final ASCII bit. | |
printf (" %s\n", buff); | |
} | |
#ifdef _WIN32 | |
BOOL WINAPI | |
sighandler(int signum) | |
{ | |
if (CTRL_C_EVENT == signum) { | |
fprintf(stderr, "Signal caught, exiting!\n"); | |
do_exit = 1; | |
rtlsdr_cancel_async(dev); | |
return TRUE; | |
} | |
return FALSE; | |
} | |
#else | |
static void sighandler(int signum) | |
{ | |
fprintf(stderr, "Signal caught, exiting!\n"); | |
do_exit = 1; | |
rtlsdr_cancel_async(dev); | |
} | |
#endif | |
void decodeMsg (char *msg, char *msgErr, int msgLen) | |
{ | |
uint16_t value; | |
char crcRes; | |
unsigned short crc16Res; | |
crcRes = crc8 (msg, msgLen-1); | |
crc16Res = crc16 (msg, msgLen-2); | |
if (msg[msgLen-1] == crcRes) { | |
printf("\n - CRC-8........: 0x%.2X (OK)\n", | |
msg[msgLen-1] & 0x000000FF); | |
} else if ((msg[msgLen-1] == (crc16Res&0x00FF)) && | |
(msg[msgLen-2] == ((crc16Res>>8)&0x00FF))) { | |
printf("\n - CRC-16.......: 0x%.4X (OK)\n", | |
crc16Res & 0x0000FFFF ); | |
} else { | |
printf("\n - CRC-8........: 0x%.2X ",msg[msgLen-1]&0x000000FF); | |
printf("(ERROR). Should be 0x%.2X\n",crcRes&0x000000FF); | |
printf("\n - CRC-16.......: 0x%.2X%.2X ", | |
msg[msgLen-2]&0x000000FF,msg[msgLen-1]&0x000000FF); | |
printf("(ERROR). Should be 0x%.4X\n",crc16Res&0x0000FFFF); | |
} | |
printf(" - Device ID....: %.2X%.2X%.2X\n", | |
msg[1] & 0x000000FF, | |
msg[2] & 0x000000FF, | |
msg[3] & 0x000000FF); | |
printf(" - Message type.: 0x%.2X ",msg[0]&0x000000FF); | |
switch (msg[0]&0x000000FF) { | |
case 0x000000A2: | |
printf("(Device discovery)\n\n"); | |
return; | |
break; | |
case 0x000000A5: | |
printf("(Glucometer reading)\n"); | |
value = ((msg[4]&0x000000FF)<<8) | (msg[5]&0x000000FF); | |
printf(" - Reading......: 0x%.2X%.2X ",(msg[4]&0x000000FF), | |
(msg[5]&0x000000FF)); | |
printf("(%d mg/dl)\n\n",value); | |
return; | |
break; | |
case 0x000000A7: | |
printf("(Insulin pump command)\n"); | |
break; | |
default: | |
printf("(Unknown)\n\n"); | |
return; | |
break; | |
} | |
printf(" - Command......: 0x%.2X ",msg[4]&0x000000FF); | |
switch(msg[4]&0x000000FF) { | |
//////////// ACK Message | |
case 0x00000006: | |
printf("(ACK message)\n"); | |
printf(" - Subcommand...: 0x%.2X ",msg[5]&0x000000FF); | |
switch (msg[5]&0x000000FF) { | |
case 0x00000000: | |
printf("(ACK)\n\n"); | |
return; | |
break; | |
case 0x00000001: | |
printf("(NACK)\n\n"); | |
return; | |
break; | |
default: | |
printf("(Unknown)\n\n"); | |
return; | |
break; | |
} | |
////////////// Set RF Interface | |
case 0x0000005D: | |
printf("(RF interface status modification)\n"); | |
printf(" - Subcommand...: 0x%.2X ",msg[5]&0x000000FF); | |
switch(msg[5]&0x000000FF) { | |
case 0x00000000: | |
printf("(Wake up)\n\n"); | |
return; | |
break; | |
case 0x00000002: | |
printf("(Modify RF status)\n"); | |
printf(" - Operand......: 0x%.2X ",msg[6]&0x000000FF); | |
switch(msg[6]&0x000000FF) { | |
case 0x00000000: | |
printf("(Turn RF OFF)\n\n"); | |
return; | |
break; | |
case 0x00000001: | |
printf("(Turn RF ON)\n\n"); | |
return; | |
break; | |
default: | |
printf("(Unknown)\n\n"); | |
return; | |
break; | |
} | |
return; | |
break; | |
} | |
/////////////// Get Pump Model command | |
case 0x0000008D: | |
printf("(Get Pump Model)\n"); | |
printf(" - Subcommand...: 0x%.2X ",msg[5]&0x000000FF); | |
switch(msg[5]&0x000000FF) { | |
case 0x00000000: | |
printf("(Reply)\n\n"); | |
return; | |
break; | |
case 0x00000009: | |
printf("(Response)\n\n"); | |
return; | |
break; | |
default: | |
printf("(Unknown)\n\n"); | |
return; | |
break; | |
} | |
break; | |
////////////////// UNKNOWN MESSAGE | |
/// TODO: LOTS OF MESSAGES TO BE INCLUDED. | |
/// OUT OF THE SCOPE OF THIS TEST. | |
default: | |
printf("(Unknown)\n\n"); | |
return; | |
break; | |
} | |
printf("\n\n"); | |
} | |
inline int decode4b6b (uint16_t symbolIn, uint16_t *symbolOut, int *error) | |
{ | |
*error = 0; | |
switch (symbolIn) { | |
case 21: | |
*symbolOut = 0x00; | |
break; | |
case 49: | |
*symbolOut = 0x01; | |
break; | |
case 50: | |
*symbolOut = 0x02; | |
break; | |
case 35: | |
*symbolOut = 0x03; | |
break; | |
case 52: | |
*symbolOut = 0x04; | |
break; | |
case 37: | |
*symbolOut = 0x05; | |
break; | |
case 38: | |
*symbolOut = 0x06; | |
break; | |
case 22: | |
*symbolOut = 0x07; | |
break; | |
case 26: | |
*symbolOut = 0x08; | |
break; | |
case 25: | |
*symbolOut = 0x09; | |
break; | |
case 42: | |
*symbolOut = 0x0A; | |
break; | |
case 11: | |
*symbolOut = 0x0B; | |
break; | |
case 44: | |
*symbolOut = 0x0C; | |
break; | |
case 13: | |
*symbolOut = 0x0D; | |
break; | |
case 14: | |
*symbolOut = 0x0E; | |
break; | |
case 28: | |
*symbolOut = 0x0F; | |
break; | |
case 0: | |
*symbolOut = 255; | |
break; | |
default: | |
*symbolOut = 0x00; | |
*error = 1; | |
return (1); | |
break; | |
} | |
return (0); | |
} | |
inline int getSymbol (uint16_t *buf, int maximum_i, int *i, | |
double bitSize, uint16_t *Symbol) | |
{ | |
int i2; | |
*Symbol = 0; | |
if ((5*bitSize + *i) > maximum_i) return 1; | |
for (i2=0; i2 < 6; i2++) | |
*Symbol = (*Symbol << 1) | (buf[*i+(int)(i2*bitSize)]&0x0001); | |
*i += (int)(6*bitSize); | |
return 0; | |
} | |
inline int preamble(uint16_t *buf, int i) | |
/* returns 0/1 for preamble at index i */ | |
{ | |
double bitSize, bitPointer; | |
int i2, i3; | |
uint16_t data; | |
uint16_t preambleData[preamble_len] = | |
{1, 0, 1, 0, 1, 0, 1, 0, | |
1, 0, 1, 0, 1, 0, 1, 0, | |
1, 1, 1, 1, 1, 1, 1, 1, | |
0, 0, 0, 0, 0, 0, 0, 0, | |
1, 1, 1, 1, 1, 1, 1, 1, | |
0, 0, 0, 0, 0, 0, 0, 0}; | |
bitSize = (double)MMPUMP_RATE/(double)(16384); | |
for (i2=0; i2<preamble_len; i2++) { | |
data=buf[i+(int)(i2*bitSize)]; | |
if (preambleData[i2] != data) return 0; | |
} | |
return 1; | |
} | |
void filter_signal (uint16_t *buf, int len) | |
{ | |
int accum; | |
int i,j; | |
maxval = 0; | |
for (i=len-1; i>FILTER_LEN-1; i--) { | |
accum = 0; | |
for (j=i-FILTER_LEN; j<i; j++) accum += buf[j]; | |
buf[i] = accum/FILTER_LEN; | |
if (maxval < buf[i]) maxval = buf[i]; | |
} | |
for (i=0; i<FILTER_LEN; i++) buf[i] = 0; | |
} | |
void getBits (uint16_t *buf, int len) | |
{ | |
int i,j; | |
double bitSize = (double)MMPUMP_RATE/(double)(16384); | |
int difJump = (int)(bitSize)-1; | |
j=0; | |
if (msgNotFinished == 1) { | |
for (i=lastPreambleIdx; i<buffer3len; i++) { | |
buffer3[j++] = buffer3[i]; | |
} | |
lastPreambleIdx = 0; | |
} | |
for (i=0; i<difJump; i++) buffer3[j++] = (buf[i] >= 40) ? 1 : 0; | |
for (i=difJump; i<len; i++) { | |
if (buf[i] >= 178) { | |
buffer3[j++] = 1; | |
} else if (buf[i] < 40) { | |
buffer3[j++] = 0; | |
} else { | |
if ((int)(buf[i]-buf[i-difJump]) >= 8) { | |
buffer3[j++] = 1; | |
} else if ((int)(buf[i]-buf[i-difJump]) <= -8) { | |
buffer3[j++] = 0; | |
} else { | |
buffer3[j] = buffer3[j-1]; | |
j++; | |
} | |
} | |
} | |
buffer3len = j; | |
} | |
void getBits2 (uint16_t *buf, int len) | |
{ | |
int i,j,k; | |
double bitSize = (double)MMPUMP_RATE/(double)(16384); | |
int difJump = (int)(bitSize)-1; | |
static uint16_t thres = 50; | |
static uint16_t lastSamples[32*MMPUMP_RATE/16384]; | |
static uint16_t maxVal, minVal; | |
j=0; | |
if (msgNotFinished == 1) { | |
for (i=lastPreambleIdx; i<buffer3len; i++) { | |
buffer3[j++] = buffer3[i]; | |
} | |
lastPreambleIdx = 0; | |
} | |
for (i=0; i<len; i++) { | |
buffer3[j++] = (buf[i] >= thres) ? 1 : 0; | |
maxVal = 0; | |
minVal = 255; | |
for (k=32*MMPUMP_RATE/16384; k>0; k--) { | |
lastSamples[k] = lastSamples[k-1]; | |
if (lastSamples[k] > maxVal) maxVal=lastSamples[k]; | |
if (lastSamples[k] < minVal) minVal=lastSamples[k]; | |
} | |
lastSamples[0] = buf[i]; | |
if (buf[i] > maxVal) maxVal = buf[i]; | |
if (buf[i] < minVal) minVal = buf[i]; | |
thres = (maxVal+minVal)/2; | |
if (thres > 80) thres = 80; | |
else if (thres < 20) thres = 20; | |
} | |
buffer3len = j; | |
} | |
void lookForMsg(uint16_t *buf, int len) | |
{ | |
double bitSize = (double)MMPUMP_RATE/(double)(16384); | |
uint16_t symbol,symbol2; | |
int i, i2, start, errors, errors2, preDect; | |
int maximum_i = len - 1; // len-1 since we look at i and i+1 | |
char msgText[256]; | |
i = 0; | |
preDect = 0; | |
msgNotFinished = 0; | |
while (i < maximum_i) { | |
/* find preamble */ | |
for ( ; (i < (len - preamble_len)) && (preDect == 0); i++) { | |
if ((preDect = preamble(buf, i)) == 1) { | |
actualMsgId++; | |
lastPreambleIdx = i; | |
msgNotFinished = 1; | |
i += (int)(preamble_len*bitSize + bitSize/2); | |
recMsgLen = 0; | |
recTotalErr = 0; | |
} | |
} | |
if (preDect == 1) { | |
do { | |
i2 = getSymbol(buf,maximum_i,&i,bitSize,&symbol); | |
decode4b6b(symbol,&symbol,&errors); | |
i2 += getSymbol(buf,maximum_i,&i,bitSize,&symbol2); | |
decode4b6b(symbol2,&symbol2,&errors2); | |
if (i2 == 0) { | |
if ((symbol < 255) && (symbol2 < 255)) { | |
symbol = (symbol<<4) | symbol2; | |
if (errors == 1 || errors2 == 1) { | |
recErr[recMsgLen] = 1; | |
recTotalErr++; | |
recMsg[recMsgLen++] = symbol; | |
} else { | |
recErr[recMsgLen] = 0; | |
recMsg[recMsgLen++] = symbol; | |
} | |
} else { | |
symbol = 0x0100; | |
msgNotFinished = 0; | |
} | |
} else { | |
symbol = 0x0100; | |
} | |
} while ((symbol != 0x0100) && (i2==0)); | |
if ((symbol == 0x0100) && (msgNotFinished==0)) { | |
printf("---------------------------------------"); | |
printf("------------------------------------\n\n"); | |
printf(" Message nº %d\n\n",actualMsgId); | |
sprintf(msgText," HexDump"); | |
hexDump(msgText,recMsg,recErr,recMsgLen); | |
decodeMsg(recMsg,recErr,recMsgLen); | |
printf("---------------------------------------"); | |
printf("------------------------------------\n\n"); | |
fflush(0); | |
} | |
preDect = 0; | |
} else { | |
i = maximum_i; | |
} | |
} | |
} | |
int magnitute(uint8_t *buf, int len) | |
/* takes i/q, changes buf in place (16 bit), returns new len (16 bit) */ | |
{ | |
int i,j; | |
int realDataI, realDataQ; | |
uint16_t *m; | |
for (i=0; i<len; i+=2) { | |
j = (int)(i/2); | |
realDataI = buf[ i ] - 127; | |
realDataQ = buf[i+1] - 127; | |
buffer2[j] = (uint16_t)sqrt(realDataI*realDataI + | |
realDataQ*realDataQ); | |
} | |
return len/2; | |
} | |
static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) | |
{ | |
if (do_exit) { | |
return;} | |
memcpy(buffer, buf, len); | |
pthread_mutex_trylock(&data_ready); | |
pthread_mutex_unlock(&data_ready); | |
} | |
static void *demod_thread_fn(void *arg) | |
{ | |
int len; | |
while (!do_exit) { | |
pthread_mutex_lock(&data_ready); | |
len = magnitute(buffer, DEFAULT_BUF_LENGTH); | |
filter_signal(buffer2, len); | |
getBits(buffer2, len); | |
lookForMsg(buffer3, buffer3len); | |
} | |
rtlsdr_cancel_async(dev); | |
return 0; | |
} | |
int main(int argc, char **argv) | |
{ | |
#ifndef _WIN32 | |
struct sigaction sigact; | |
#endif | |
char *filename = NULL; | |
int n_read, r, opt; | |
int i, gain = AUTO_GAIN; /* tenths of a dB */ | |
uint32_t dev_index = 0; | |
int device_count; | |
int ppm_error = 0; | |
int usaMode = 0; | |
char vendor[256], product[256], serial[256]; | |
pthread_mutex_init(&data_ready, NULL); | |
while ((opt = getopt(argc, argv, "U:d:g:p:e:Q:VS")) != -1) | |
{ | |
switch (opt) { | |
case 'U': | |
usaMode = atoi(optarg) < 1 ? 0 : 1; | |
break; | |
case 'd': | |
dev_index = atoi(optarg); | |
break; | |
case 'g': | |
gain = (int)(atof(optarg) * 10); | |
break; | |
case 'p': | |
ppm_error = atoi(optarg); | |
break; | |
case 'V': | |
verbose_output = 1; | |
break; | |
case 'S': | |
short_output = 1; | |
break; | |
case 'e': | |
allowed_errors = atoi(optarg); | |
break; | |
case 'Q': | |
quality = atof(optarg); | |
break; | |
default: | |
usage(); | |
return 0; | |
} | |
} | |
if (argc <= optind) { | |
filename = "-"; | |
} else { | |
filename = argv[optind]; | |
} | |
buffer = malloc(DEFAULT_BUF_LENGTH * sizeof(uint8_t)); | |
device_count = rtlsdr_get_device_count(); | |
if (!device_count) { | |
fprintf(stderr, "No supported devices found.\n"); | |
exit(1); | |
} | |
fprintf(stderr, "Found %d device(s):\n", device_count); | |
for (i = 0; i < device_count; i++) { | |
rtlsdr_get_device_usb_strings(i, vendor, product, serial); | |
fprintf(stderr, " %d: %s, %s, SN: %s\n", i, vendor, product, serial); | |
} | |
fprintf(stderr, "\n"); | |
fprintf(stderr, "Using device %d: %s\n", | |
dev_index, rtlsdr_get_device_name(dev_index)); | |
r = rtlsdr_open(&dev, dev_index); | |
if (r < 0) { | |
fprintf(stderr, "Failed to open rtlsdr device #%d.\n", dev_index); | |
exit(1); | |
} | |
#ifndef _WIN32 | |
sigact.sa_handler = sighandler; | |
sigemptyset(&sigact.sa_mask); | |
sigact.sa_flags = 0; | |
sigaction(SIGINT, &sigact, NULL); | |
sigaction(SIGTERM, &sigact, NULL); | |
sigaction(SIGQUIT, &sigact, NULL); | |
sigaction(SIGPIPE, &sigact, NULL); | |
#else | |
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); | |
#endif | |
if (strcmp(filename, "-") == 0) { /* Write samples to stdout */ | |
file = stdout; | |
setvbuf(stdout, NULL, _IONBF, 0); | |
#ifdef _WIN32 | |
_setmode(_fileno(file), _O_BINARY); | |
#endif | |
} else { | |
file = fopen(filename, "wb"); | |
if (!file) { | |
fprintf(stderr, "Failed to open %s\n", filename); | |
exit(1); | |
} | |
} | |
/* Set the tuner gain */ | |
if (gain == AUTO_GAIN) { | |
r = rtlsdr_set_tuner_gain_mode(dev, 0); | |
} else { | |
r = rtlsdr_set_tuner_gain_mode(dev, 1); | |
r = rtlsdr_set_tuner_gain(dev, gain); | |
} | |
if (r != 0) { | |
fprintf(stderr, "WARNING: Failed to set tuner gain.\n"); | |
} else if (gain == AUTO_GAIN) { | |
fprintf(stderr, "Tuner gain set to automatic.\n"); | |
} else { | |
fprintf(stderr, "Tuner gain set to %0.2f dB.\n", gain/10.0); | |
} | |
//r = rtlsdr_set_freq_correction(dev, ppm_error); | |
r = rtlsdr_set_agc_mode(dev, 0); | |
/* Set the tuner frequency */ | |
if (usaMode == 0) { | |
r = rtlsdr_set_center_freq(dev, MMPUMP_FREQ_EUROPE); | |
} else { | |
r = rtlsdr_set_center_freq(dev, MMPUMP_FREQ_USA); | |
} | |
if (r < 0) { | |
fprintf(stderr, "WARNING: Failed to set center freq.\n");} | |
else { | |
if (usaMode == 0) | |
fprintf(stderr, "Tuned to %u Hz. (Europe mode)\n", MMPUMP_FREQ_EUROPE); | |
else fprintf(stderr, "Tuned to %u Hz. (USA mode)\n", MMPUMP_FREQ_USA);} | |
/* Set the sample rate */ | |
fprintf(stderr, "Sampling at %u Hz.\n", MMPUMP_RATE); | |
r = rtlsdr_set_sample_rate(dev, MMPUMP_RATE); | |
if (r < 0) { | |
fprintf(stderr, "WARNING: Failed to set sample rate.\n");} | |
/* Reset endpoint before we start reading from it (mandatory) */ | |
r = rtlsdr_reset_buffer(dev); | |
if (r < 0) { | |
fprintf(stderr, "WARNING: Failed to reset buffers.\n");} | |
/* flush old junk */ | |
sleep(1); | |
rtlsdr_read_sync(dev, NULL, 4096, NULL); | |
actualMsgId = 0; | |
pthread_create(&demod_thread, NULL, demod_thread_fn, (void *)(NULL)); | |
rtlsdr_read_async(dev, rtlsdr_callback, (void *)(NULL), | |
DEFAULT_ASYNC_BUF_NUMBER, | |
DEFAULT_BUF_LENGTH); | |
if (do_exit) { | |
fprintf(stderr, "\nUser cancel, exiting...\n");} | |
else { | |
fprintf(stderr, "\nLibrary error %d, exiting...\n", r);} | |
rtlsdr_cancel_async(dev); | |
pthread_mutex_destroy(&data_ready); | |
if (file != stdout) { | |
fclose(file);} | |
rtlsdr_close(dev); | |
free(buffer); | |
return r >= 0 ? r : -r; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Ran it like this:
While doing blood test with linked meter, and while using my other software to fetch pump model but did not pick up anything interesting.