├── .gitignore ├── Makefile ├── README.md ├── fourbsixb.c ├── fourbsixb.h ├── ook.c ├── ook.h ├── recordiq.sh └── rtlmm.c /.gitignore: -------------------------------------------------------------------------------- 1 | rtlmm 2 | *.dSYM 3 | *.cu8 4 | *.fc32 5 | *.csv 6 | *.o 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: rtlmm 2 | 3 | CC = gcc 4 | GCCVERSION = $(shell gcc --version | grep ^gcc | sed 's/^.* //g') 5 | 6 | CFLAGS = 7 | 8 | ifeq "$(GCCVERSION)" "4.9.2" 9 | CFLAGS = -std=gnu99 10 | endif 11 | 12 | CFLAGS += -Wall -g -O2 -Wno-unused-variable 13 | 14 | LDFLAGS = -lm -lliquid 15 | 16 | rtlmm.o: rtlmm.c 17 | $(CC) $(CFLAGS) -o rtlmm.o -c rtlmm.c 18 | 19 | fourbsixb.o: fourbsixb.c 20 | $(CC) $(CFLAGS) -o fourbsixb.o -c fourbsixb.c 21 | 22 | ook.o: ook.c 23 | $(CC) $(CFLAGS) -o ook.o -c ook.c 24 | 25 | rtlmm: rtlmm.o fourbsixb.o ook.o 26 | $(CC) -o rtlmm rtlmm.o fourbsixb.o ook.o $(LDFLAGS) 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rtlmm 2 | 3 | _Created by Pete Schwamb. Code is released under MIT license._ 4 | 5 | **rtlmm** is software to sniff minimed RF packets using a RTLSDR dongle 6 | 7 | This work is inspired by and partially based on Evariste Courjaud's great tool: https://github.com/F5OEO/rtlomni 8 | 9 | # Prerequisites 10 | 11 | * liquid-dsp: On mac, you can `brew install liquid-dsp`. On linux systems, you must build from source: https://github.com/jgaeddert/liquid-dsp/ 12 | 13 | # Installation 14 | ```sh 15 | 16 | git clone https://github.com/ps2/rtlmm 17 | cd rtlmm 18 | make 19 | 20 | #Install rtl-sdr driver and utilities (rtl_test, rtl_sdr ...) 21 | sudo apt-get install rtl-sdr 22 | 23 | ``` 24 | 25 | # Launching rtlmm 26 | you can launch : 27 | ```sh 28 | ./rtlmm some_file.cu8 29 | ``` 30 | It outputs messages from a RF sample file included in the folder. 31 | 32 | For live message recording, there is a script 33 | ```sh 34 | ./recordiq.sh 35 | ``` 36 | -------------------------------------------------------------------------------- /fourbsixb.c: -------------------------------------------------------------------------------- 1 | 2 | #include "fourbsixb.h" 3 | 4 | static uint8_t codes[] = {21,49,50,35,52,37,38,22,26,25,42,11,44,13,14,28}; 5 | 6 | void fourbsixb_init_encoder(FourbSixbEncoderState *state) { 7 | state->acc = 0; 8 | state->bits_avail = 0; 9 | } 10 | 11 | void fourbsixb_add_raw_byte(FourbSixbEncoderState *state, uint8_t raw) { 12 | uint16_t new_bits = (codes[raw >> 4] << 6) | codes[raw & 0xf]; 13 | state->acc = (state->acc << 12) | new_bits; 14 | state->bits_avail += 12; 15 | } 16 | 17 | uint8_t fourbsixb_next_encoded_byte(FourbSixbEncoderState *state, uint8_t *encoded) { 18 | if (state->bits_avail < 8) { 19 | return 0; 20 | } 21 | *encoded = state->acc >> (8-state->bits_avail); 22 | state->bits_avail -= 8; 23 | return 1; 24 | } 25 | 26 | void fourbsixb_init_decoder(FourbSixbDecoderState *state) { 27 | state->input_acc = 0; 28 | state->input_bits_avail = 0; 29 | state->output_acc = 0; 30 | state->output_bits_avail = 0; 31 | } 32 | 33 | uint8_t fourbsixb_add_encoded_byte(FourbSixbDecoderState *state, uint8_t encoded) { 34 | uint8_t code, i; 35 | state->input_acc = (state->input_acc << 8) | encoded; 36 | state->input_bits_avail += 8; 37 | while (state->input_bits_avail >= 6) { 38 | code = (state->input_acc >> (state->input_bits_avail - 6)) & 0b111111; 39 | state->input_bits_avail -= 6; 40 | for (i=0; i<16; i++) { 41 | if (codes[i] == code) { 42 | break; 43 | } 44 | } 45 | if (i == 16) { 46 | return 1; // Encoding error 47 | } 48 | state->output_acc = (state->output_acc << 4) | i; 49 | state->output_bits_avail += 4; 50 | } 51 | return 0; 52 | } 53 | 54 | uint8_t fourbsixb_next_decoded_byte(FourbSixbDecoderState *state, uint8_t *decoded) { 55 | if (state->output_bits_avail < 8) { 56 | return 0; 57 | } 58 | *decoded = state->output_acc >> (state->output_bits_avail - 8); 59 | state->output_bits_avail -= 8; 60 | return 1; 61 | } 62 | -------------------------------------------------------------------------------- /fourbsixb.h: -------------------------------------------------------------------------------- 1 | #ifndef FOURBSIXB_H 2 | #define FOURBSIXB_H 3 | 4 | #include 5 | 6 | typedef struct { 7 | uint16_t acc; 8 | uint8_t bits_avail; 9 | } FourbSixbEncoderState; 10 | 11 | typedef struct { 12 | uint16_t input_acc; 13 | uint8_t input_bits_avail; 14 | uint16_t output_acc; 15 | uint8_t output_bits_avail; 16 | } FourbSixbDecoderState; 17 | 18 | void fourbsixb_init_encoder(FourbSixbEncoderState *state); 19 | void fourbsixb_add_raw_byte(FourbSixbEncoderState *state, uint8_t raw); 20 | uint8_t fourbsixb_next_encoded_byte(FourbSixbEncoderState *state, uint8_t *encoded); 21 | void fourbsixb_init_decoder(FourbSixbDecoderState *state); 22 | uint8_t fourbsixb_add_encoded_byte(FourbSixbDecoderState *state, uint8_t raw); 23 | uint8_t fourbsixb_next_decoded_byte(FourbSixbDecoderState *state, uint8_t *decoded); 24 | 25 | #endif //FOURBSIXB_H 26 | -------------------------------------------------------------------------------- /ook.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "ook.h" 4 | 5 | void ook_init(DemodOOK *ook, unsigned int k, uint32_t syncword, double threshold) { 6 | ook->k = k; 7 | ook->sample_counter = 0; 8 | ook->last_level = 0; 9 | ook->sample_index = k/2; 10 | ook->syncword = syncword; 11 | ook->sync_acc = 0; 12 | ook->data_acc = 0; 13 | ook->bits_received = 0; 14 | ook->scan_mode = MODE_SQUELCH; 15 | ook->output_symbol = 0; 16 | ook->threshold = threshold; 17 | } 18 | 19 | bool ook_demod_sample(DemodOOK *ook, float complex sample) { 20 | bool symbol_available = false; 21 | uint8_t level = (cabsf(sample) > ook->threshold) ? 1 : 0; 22 | bool edge = level != ook->last_level; 23 | if (edge) { 24 | ook->sample_counter = 0; 25 | } 26 | if (ook->sample_counter == ook->sample_index) { 27 | if (ook->scan_mode == MODE_SQUELCH) { 28 | if (level) { 29 | ook->scan_mode = MODE_PREAMBLE; 30 | } 31 | } else if (ook->scan_mode == MODE_PREAMBLE) { 32 | ook->sync_acc = (ook->sync_acc << 1) + level; 33 | if (ook->sync_acc == ook->syncword) { 34 | ook->scan_mode = MODE_PACKET; 35 | ook->sync_acc = 0; 36 | } 37 | } else if (ook->scan_mode == MODE_PACKET) { 38 | ook->data_acc = (ook->data_acc << 1) + level; 39 | ook->bits_received = (ook->bits_received + 1) % 8; 40 | if (ook->bits_received == 0) { 41 | ook->output_symbol = ook->data_acc; 42 | symbol_available = true; 43 | ook->data_acc = 0; 44 | } 45 | } 46 | } 47 | ook->last_level = level; 48 | ook->sample_counter = (ook->sample_counter + 1) % ook->k; 49 | return symbol_available; 50 | } 51 | 52 | void ook_end_packet(DemodOOK *ook) { 53 | ook->bits_received = 0; 54 | ook->scan_mode = MODE_SQUELCH; 55 | } 56 | 57 | uint8_t ook_get_symbol(DemodOOK *ook) { 58 | return ook->output_symbol; 59 | } 60 | -------------------------------------------------------------------------------- /ook.h: -------------------------------------------------------------------------------- 1 | #ifndef OOK_H 2 | #define OOK_H 3 | 4 | #include 5 | #include 6 | 7 | typedef enum {MODE_SQUELCH, MODE_PREAMBLE,MODE_PACKET} OokScanMode; 8 | 9 | typedef struct { 10 | unsigned int k; 11 | unsigned int sample_counter; 12 | uint8_t last_level; 13 | unsigned int sample_index; 14 | uint32_t syncword; 15 | uint32_t sync_acc; 16 | uint8_t data_acc; 17 | uint8_t output_symbol; 18 | uint8_t bits_received; 19 | OokScanMode scan_mode; 20 | double threshold; 21 | } DemodOOK; 22 | 23 | void ook_init(DemodOOK *ook, unsigned int k, uint32_t syncword, double threshold); 24 | 25 | // Returns true if a new 8-bit symbol is available. 26 | bool ook_demod_sample(DemodOOK *ook, float complex sample); 27 | 28 | uint8_t ook_get_symbol(DemodOOK *ook); 29 | 30 | void ook_end_packet(DemodOOK *ook); 31 | 32 | 33 | #endif //OOK_H 34 | -------------------------------------------------------------------------------- /recordiq.sh: -------------------------------------------------------------------------------- 1 | mkfifo fifo.cu8 2 | rtl_sdr -p 76 -g 20 -f 916548000 -s 1048576 fifo.cu8 & 3 | ./rtlmm fifo.cu8 1 4 | -------------------------------------------------------------------------------- /rtlmm.c: -------------------------------------------------------------------------------- 1 | /* 2 | rtlmm is a software to sniff minimed RF packets using a RTLSDR dongle. 3 | 4 | Credits : 5 | 6 | This work is inspired by and partially based on Evariste Courjaud's great tool: https://github.com/F5OEO/rtlomni 7 | 8 | License: 9 | 10 | Copyright 2018 Pete Schwamb 11 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "fourbsixb.h" 32 | #include "ook.h" 33 | 34 | // IQ file center frequency 35 | #define IQFREQ 916548000.0 36 | 37 | // IQ file sample rate (should match the -s param to rtl_sdr) 38 | // This gets us about 62 samples per symbol 39 | #define IQSR 1048576.0 40 | 41 | // Symbol rate 42 | #define BAUDRATE 16384 43 | 44 | // Samples per symbol 45 | #define SAMPLES_PER_SYMBOL (IQSR / BAUDRATE) 46 | 47 | // Magnitude threshold for 'on' bit 48 | #define ON_BIT_THRESHOLD 0.05 49 | 50 | #define PACKET_LEN 255 51 | 52 | int main(int argc, char*argv[]) 53 | { 54 | FILE* iqfile = NULL; 55 | char *inputname=argv[1]; 56 | if(argc>=2) 57 | { 58 | if(inputname[strlen(inputname)-1]=='8') { 59 | iqfile = fopen (argv[1], "r"); 60 | if (!iqfile) { 61 | printf("Could not open iqfile: %s\n", inputname); 62 | exit(1); 63 | } 64 | } else { 65 | printf("Unknown input file type: %s\n", inputname); 66 | exit(1); 67 | } 68 | } else { 69 | printf("Please specify input file.\n"); 70 | exit(1); 71 | } 72 | 73 | unsigned int fft_size = 4096; 74 | 75 | unsigned int i,j; 76 | 77 | uint8_t* iq_buffer; // 1Byte I, 1Byte Q 78 | iq_buffer = (uint8_t *)malloc(fft_size*2*sizeof(uint8_t)); // 1Byte I, 1Byte Q 79 | 80 | float *window = (float*)malloc(fft_size*sizeof(float)); 81 | for (i=0; i 0) { 108 | for(j=0, i=0; j 0) { 135 | // Determine center frequency of this packet 136 | if (have_data_for_fft) { 137 | for(j=0;j max_val) { 146 | max_val = val; 147 | max_bin = j; 148 | } 149 | } 150 | printf("freq: %0.02f ", (IQFREQ + ((max_bin ^ (fft_size >>1)) * IQSR / fft_size) - (IQSR / 2)) / 1000000.0); 151 | } 152 | printf("rx: "); 153 | for(j=0; j