This is the code I came up with, it will print a stream of bits and there durations in microseconds.
uint8_t lastinput = LOW; uint32_t lastinputat; void setup() { pinMode(2, INPUT); Serial.begin(115200*8); lastinputat = micros(); } void loop() { uint8_t input = digitalRead(2); if(input != lastinput) { uint32_t now = micros(); uint32_t dt = now - lastinputat; lastinput = input; lastinputat = now; Serial.print(input, 10); Serial.print(' '); Serial.println(dt, 10); } }
The output looks something like this:
1 1068 0 472 1 488 0 416 1 568 ...
The durations were not as consistent as I had hoped they would be, so to get a better idea of what I was dealing with, I wrote a python gui application to graph the durations.
import wx import re import serial import sys import time import math WIN_HEIGHT = 128 WIN_WIDTH = 590 # pixels DURATION_PER_PIXEL = 0.003 / (WIN_WIDTH-1) class TestFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, title='test', size=(WIN_WIDTH, WIN_HEIGHT)) self.line_re = re.compile('([01]) *([0-9]+)') self.ser = serial.Serial('/dev/ttyACM0', 115200*8, timeout=0.000) self.last = None self.recvqueue = '' self.durations = [[0]*WIN_WIDTH, [0]*WIN_WIDTH] self.panel = wx.Panel(self, size=(WIN_WIDTH, WIN_HEIGHT)) self.panel.Bind(wx.EVT_PAINT, self.on_paint) self.Fit() self.Show(True) self.timer = wx.Timer(self.panel, 123) wx.EVT_TIMER(self.panel, 123, self.on_timer) self.timer.Start(10) def on_paint(self, event): dc = wx.PaintDC(self.panel) dc.SetPen(wx.Pen('red', 1)) dc.DrawLine(0, WIN_HEIGHT/2, WIN_WIDTH, WIN_HEIGHT/2) for i in range(0, WIN_WIDTH, 1): t = i*DURATION_PER_PIXEL if math.floor(t/0.001) != math.floor((t-DURATION_PER_PIXEL)/0.001): dc.DrawLine(i, 0, i, WIN_HEIGHT) elif math.floor(t/0.0001) != math.floor((t-DURATION_PER_PIXEL)/0.0001): dc.DrawLine(i, WIN_HEIGHT/2-8, i, WIN_HEIGHT/2+8) dc.SetPen(wx.Pen('black', 1)) for i in range(WIN_WIDTH): dc.DrawLine(i, WIN_HEIGHT/2+1, i, WIN_HEIGHT/2+1+self.durations[0][i]) dc.DrawLine(i, WIN_HEIGHT/2-1, i, WIN_HEIGHT/2-1-self.durations[1][i]) def on_timer(self, event): redraw = False while True: line = self.ser.readline() if not line: break m = self.line_re.match(line) if not m: continue bit = int(m.group(1)) duration = float(m.group(2))/1000000.0 print bit, duration self.durations[bit][min(int(duration/DURATION_PER_PIXEL), WIN_WIDTH-1)] += 1 redraw = True if redraw: self.panel.Refresh() app = wx.App(False) frame = TestFrame() app.MainLoop()
The result looked like this. The window covers a durations of 3 milliseconds, so there is a tall vertical line per millisecond.
It's now possible to see that the durations fall into 4 groups:
- short high pulses (logic level 1) in the range 400-600 milliseconds.
- short low pulses (logic level 0) in the range 300-500 milliseconds.
- long high pulses in the range 900-1100 milliseconds.
- long low pulses in the range 800-1000 milliseconds.
I suspect the difference in timing from the high and low pulses is because the sender has an extremely slow cpu, and it spends a few more cycles when sending a 1 than sending a 0. A bit of goggling suggest that 32.768 kHz is very common speed for low powered embedded micro controllers. At that speed, the time difference (0.15 ms) between high and low pulses are just around 5 cycles.
Visualizing the data as a pulse train, using __, _ for low pulses, and --, - for high pulses, a pattern start to revel itself. Here are 4 bursts of data:
__--__--__-_--_-_-_-_-_-__--_-_-__-_-_--__--_-__-_--__--_-__-_-_--_-_-_-_-_-_-_-_-__--_-_-__-_--_-__--__--_-_- __--__--__-_--_-_-_-_-_-__--_-_-__-_-_--_-_-__-_-_-_-_-_--__-_-_--_-_-_-_-_-_-_-_-_-_-__-_-_--_-__--_-__--__-- __--__--__-_--_-_-_-_-_-__--_-_-__-_-_--__-_-_--_-_-_-_-__--_-_-__-_-_-_-_-_-_-_-_-_-_--__-_-_--_-__--_-_-__-_ __--__--__-_--_-_-_-_-_-__--_-_-__-_-_--__-_--_-_-__-_-_--__-_-_--_-_-_-_-_-_-_-_-__-_--__-_--_-_-_-_-__-_--__
The script used to print these pulse trains:
import serial import sys import time serdev = '/dev/ttyACM0' ser = serial.Serial(serdev, 115200*8) def decode(bit, duration): if bit==1 and duration>=400 and duration<=600: return '-' if bit==1 and duration>=900 and duration<=1100: return '--' if bit==0 and duration>=300 and duration<=500: return '_' if bit==0 and duration>=800 and duration<=1000: return '__' return None while True: line = ser.readline().strip() pulse = decode(int(line[0]), int(line[2:])) if pulse: sys.stdout.write(pulse) else: sys.stdout.write('\n') sys.stdout.flush()A examination of the pulse trains reveals that short pulses always come in pairs! This suggest that the data is likely to be Manchester encoded, or more likely Differential Manchester encoded. After applying a differential Manchester decoder to the data, we see some very promising patterns:
1111101000001100100111011011000010000000101000010000110 (100 ms delay) 1111101000001100100111011011000010000000101000010000110 (43 s delay) 11111010100011001001101000100100100111010000000000000000101011110111110 1111101000001100100111100011000010000000001000101011110 1111101000001100100110011101000010000000110001011010101 1111101000001100100110011101000010000000110001011010101 11111010100011001001010110100100100111010000000000000000001000001101111 1111101000001100100110000011000010000000001001001101101 1111101000001100100111000011000010000000001000001001111 1111101000001100100111000011000010000000001000001001111 11111010100011001001011101100100100111010000000000000000111000101001001 1111101000001100100111011101000010000000110000011110111The data is being send it bursts with around 43 seconds between them. In each burst there are two frames, separated by around 100 ms. As can be seen, every second burst have a longer frame than usual, the other bursts just appear to be repeating the same frame twice. The differential Manchester decoder:
lastshort = False while True: line = ser.readline().strip() pulse = decode(int(line[0]), int(line[2:])) if pulse in ('_', '-'): if lastshort: sys.stdout.write('0') lastshort = not lastshort elif pulse in ('__', '--'): if lastshort: print 'ERROR' lastshort = False else: sys.stdout.write('1') else: lastshort = False sys.stdout.write('\n') sys.stdout.flush()That's it for now, next time I will try to make some sense of the newly discovered bits...
Top 10 best slots in the world list: Microgaming, NetEnt, and
ReplyDeleteFind out 카지노사이트 what's the best slots by NetEnt, Microgaming and more. Discover the top casinos to play with real money, as well as exclusive casino bonuses! 우리카지노