diff --git a/tools/ge-device-discovery.py b/tools/ge-device-discovery.py new file mode 100755 index 0000000..8a3f189 --- /dev/null +++ b/tools/ge-device-discovery.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python2 + +''' + Copyright (C) 2016 Bastille Networks + + 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 3 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 . +''' + +import time, logging, sys +sys.path.append('../nrf-research-firmware/tools') +from lib import common + +# Parse command line arguments and initialize the radio +common.init_args('./ge-device-discovery.py') +common.parser.add_argument('-d', '--dwell', type=float, help='Dwell time per channel, in milliseconds', default='200') +common.parse_and_init() + +# Put the radio in promiscuous mode +common.radio.enter_promiscuous_mode_generic("\x33\x33\x33\x30", common.RF_RATE_1M, 32) + +# Set the channels to {18..63..3} +common.channels = range(18, 63+1, 3) + +# Convert dwell time from milliseconds to seconds +dwell_time = common.args.dwell / 1000 + +# Set the initial channel +common.radio.set_channel(common.channels[0]) + +# Potentially valid address counts +addresses = {} + +# Update a CRC-CCITT with one byte of data +def crc_update(crc, data): + crc ^= (data << 8) + for x in range(8): + if (crc & 0x8000) == 0x8000: crc = ((crc << 1) ^ 0x1021) & 0xFFFF + else: crc <<= 1 + crc &= 0xFFFF + return crc + +# Sweep through the channels and decode packets in pseudo-promiscuous mode +last_tune = time.time() +channel_index = 0 +while True: + + # Increment the channel + if len(common.channels) > 1 and time.time() - last_tune > dwell_time: + channel_index = (channel_index + 1) % (len(common.channels)) + common.radio.set_channel(common.channels[channel_index]) + last_tune = time.time() + + # Receive payloads + value = common.radio.receive_payload() + if len(value) < 32: continue + + # Decode + bits = ''.join(bin(c)[2:].zfill(8) for c in value)[::2] + decoded = [] + for x in range(len(bits)/8): + decoded.append(int(bits[x*8:(x+1)*8], 2)) + decoded = decoded[1:] + + print ':'.join('{:02X}'.format(b) for b in decoded) + + # Validate the CRC + crc = 0x1D0F + for x in range(9): + crc = crc_update(crc, decoded[4+x]) + crc_given = decoded[13] << 8 | decoded[14] + if crc == crc_given: + + # Log the address and quit + logging.info('\033[92m\033[1mGE 98614 dongle found on channel {0} with address {1}\033[0m'.format( + common.channels[channel_index], + ':'.join('{:02X}'.format(b) for b in decoded[0:4]))) + + quit() + diff --git a/tools/mosart-device-discovery.py b/tools/mosart-device-discovery.py new file mode 100755 index 0000000..161d244 --- /dev/null +++ b/tools/mosart-device-discovery.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python2 + +''' + Copyright (C) 2016 Bastille Networks + + 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 3 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 . +''' + +import time, logging, sys +sys.path.append('../nrf-research-firmware/tools') +from lib import common + +# Parse command line arguments and initialize the radio +common.init_args('./mosart-device-discovery.py') +common.parser.add_argument('-d', '--dwell', type=float, help='Dwell time per channel, in milliseconds', default='200') +common.parse_and_init() + +# Put the radio in promiscuous mode +common.radio.enter_promiscuous_mode_generic("\xAA\xAA\xAA", common.RF_RATE_1M) + +# Set the channels to {2..84..2} +common.channels = range(2, 84, 2) + +# Convert dwell time from milliseconds to seconds +dwell_time = common.args.dwell / 1000 + +# Set the initial channel +common.radio.set_channel(common.channels[0]) + +# Potentially valid address counts +addresses = {} + +# Sweep through the channels and decode ESB packets in pseudo-promiscuous mode +last_tune = time.time() +channel_index = 0 +while True: + + # Increment the channel + if len(common.channels) > 1 and time.time() - last_tune > dwell_time: + channel_index = (channel_index + 1) % (len(common.channels)) + common.radio.set_channel(common.channels[channel_index]) + last_tune = time.time() + + # Receive payloads + value = common.radio.receive_payload() + if value[0] == 0xFF: continue + + # De-whiten the payload + for x in range(len(value)): value[x] ^= 0x5A + + # Look for the 11:22 sequence + for x in range(len(value)-6): + if value[x+4] == 0x11 and value[x+5] == 0x22: + + address = chr(value[x]) + chr(value[x+1]) + chr(value[x+2]) + chr(value[x+3]) + if not address in addresses: addresses[address] = 0 + addresses[address] += 1 + if addresses[address] > 10: + + # Log the address and quit + logging.info('\033[92m\033[1mMOSART dongle found on channel {0} with address {1}\033[0m'.format( + common.channels[channel_index], + ':'.join('{:02X}'.format(ord(b)) for b in address))) + + quit() + + # Log the packet + logging.debug('{0: >2} {1: >2} {2}'.format( + common.channels[channel_index], + len(value), + ':'.join('{:02X}'.format(b) for b in value))) +