DreamTeam/thinkgear: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
(notes) |
||
| (7 intermediate revisions by one other user not shown) | |||
| Line 1: | Line 1: | ||
<pre> | <pre> | ||
(some notes ...) | |||
want complete packets read from buffer | |||
input sequence of buffer "reads" | |||
output sequence of synced packets | |||
a complete packet will have correct length | |||
(and matching checksum - check elsewhere) | |||
(how will partial packets be handled?) | |||
error checks might anticipate several issues: | |||
- transmission (dropped or incomplete packets) | |||
- device (scrambled data) | |||
- parser logic (anything goes) | |||
other non-error conditions might include: | |||
- poor signal (electrode contact) | |||
- artifact rejection (poor signal, eye blink) | |||
- protocol edge cases (data bytes mimic sync, etc) | |||
expect varying packet size 4 (empty payload) to 173 bytes | |||
(173 is theoretical max, if larger then invalid) | |||
how many samples per packet of raw eeg | |||
2 byte value, 1 byte typecode per datarow | |||
3 * 56 samples = 168 byte payload | |||
+ 2 sync + 1 length + 1 checksum = 172 | |||
= at least 10 packets per 512 raw samples | |||
expect additional packet(s) | |||
for device-processed data (power spectra, 'esense') | |||
need to handle time - ie, esense every second | |||
may allow interpolating raw sample times inbetween | |||
</pre> | |||
<pre> | |||
(some code, not tested ...) | |||
syncval = 0xaa | |||
syncpos = 0 | syncpos = 0 | ||
synclen = 2 | synclen = 2 | ||
synced = False | |||
synced = (syncval == | while not synced: | ||
buffer = get_next_buffer() | |||
if buffer.count(syncval) < 2: | |||
continue | |||
try: | |||
syncpos = buffer.index(syncval) | |||
except ValueError: | |||
print "no sync wtf???" | |||
nextpos = syncpos + 1 | |||
if nextpos < len(buffer) && buffer[nextpos] == syncval: | |||
synced = True | |||
lenpos = syncpos + synclen | lenpos = syncpos + synclen | ||
lenlen = 1 | lenlen = 1 | ||
paylen = | paylen = buffer[syncpos+2] | ||
assert paylen < 170 # note 170 is 0xaa - just coincidentally? | assert paylen < 170 # note 170 is 0xaa - just coincidentally? | ||
# now can examine paylen and if necessary handle case where packet is not complete | |||
# needs rest of expected "paylen" data + checksum from next buffer | |||
expected_len = paylen + 4 | |||
lastpos = len(buffer) - 1 | |||
if expected_len > lastpos - syncpos: | |||
# need rest of packet from next buffer | |||
if len(packet) < expected_len: | |||
need_len = expected_len - len(packet) | |||
buffer = get_next_buffer() | |||
packet.extend(buffer[:needlen]) | |||
# would be good to store this for the next time, so don't have to re-iterate looking for next sync | |||
loadpos = lenpos + lenlen | loadpos = lenpos + lenlen | ||
| Line 35: | Line 102: | ||
getdatalen = lambda x, y:y[x][1] | getdatalen = lambda x, y:y[x][1] | ||
ptr = payload | ptr = payload | ||
codelen = 1 # unless extended code, not handled here. | |||
codepos = 0 | codepos = 0 | ||
codetype = ptr[codepos] | datalen = 0 | ||
datalen = getdatalen(codetype, codons) | |||
def testdatalen(datalen, codetype): | |||
dataval = ptr[datapos:datalen] | if datalen > 1: | ||
assert codetype >= 0x80 | |||
else: | |||
assert codetype < 0x80 | |||
nextpos = 0 | |||
while nextpos < paylen: | |||
codepos = nextpos | |||
codetype = ptr[codepos] | |||
assert codetype in codons | |||
assert codetype != 0x55 # we don't handle extended code bytes. | |||
datalen = getdatalen(codetype, codons) | |||
nextpos = codepos + codelen | |||
datapos = nextpos | |||
nextpos = datapos + datalen | |||
if nextpos >= paylen: | |||
break | |||
dataval = ptr[datapos:nextpos] | |||
newpos = datapos + datalen | |||
</pre> | |||
<pre> | |||
def syncromesh(): | |||
buffer = init_buffer() | |||
paylen = 0 | |||
while True: | |||
synced_buffer_portion = discard_until_sync(buffer) | |||
expected_paylen = synced_buffer_portion[0] # written by device, packet is 4 bytes larger including 2 sync bytes | |||
assert expected_paylen < 170 | |||
complete_packet_len = expected_paylen + 1 | |||
buflen = len(synced_buffer_portion) | |||
if buflen < expected_paylen: | |||
# copy remaining buffer | |||
packet = synced_buffer_portion[:] | |||
# will need to "extend" packet with data from next buffer | |||
buffer = get_next_buffer | |||
expected_remaining = expected_paylen - buflen | |||
packet.extend(buffer[:expected_remaining]) | |||
assert len(packet) == expected_ | |||
# want function to loop, reading buffer, writing packets | |||
# initial state, before loop: | |||
# unsynced buffer (contains fractional packet, sync signal, then possibly complete packet/s) | |||
# blank packet | |||
# So, discard buffer contents before first sync signal | |||
# begin loop | |||
# at beginning of loop, have blank packet and synced buffer position | |||
# write from buffer to packet | |||
# until either | |||
# A) buffer end reached | |||
# B) logical packet content end reached | |||
# C) new sync signal detected (either before or at - or after! - logical packet end) | |||
What is "logical packet end" ? | |||
It is max 171 bytes after sync | |||
(total 173 bytes = 2 sync, 1 len, payload max 169 and 1 checksum byte) | |||
Precise length should be the data paylen value written by device + 4 | |||
if A) buffer end reached | |||
then, still in loop, get new buffer, keep writing packet | |||
if B) "logical packet end" according to device-written "paylen" byte | |||
then, send packet, start new blank packet | |||
if C) sync signal detected before "logical packet end" | |||
then, handle (apparent) dropped packet and/or logic error | |||
- Code this logic last, just flag dropped packet for now | |||
Log incomplete packet for analysis separate from "good" data | |||
and start new blank packet | |||
</pre> | </pre> | ||
Latest revision as of 00:43, 3 June 2013
(some notes ...) want complete packets read from buffer input sequence of buffer "reads" output sequence of synced packets a complete packet will have correct length (and matching checksum - check elsewhere) (how will partial packets be handled?) error checks might anticipate several issues: - transmission (dropped or incomplete packets) - device (scrambled data) - parser logic (anything goes) other non-error conditions might include: - poor signal (electrode contact) - artifact rejection (poor signal, eye blink) - protocol edge cases (data bytes mimic sync, etc) expect varying packet size 4 (empty payload) to 173 bytes (173 is theoretical max, if larger then invalid) how many samples per packet of raw eeg 2 byte value, 1 byte typecode per datarow 3 * 56 samples = 168 byte payload + 2 sync + 1 length + 1 checksum = 172 = at least 10 packets per 512 raw samples expect additional packet(s) for device-processed data (power spectra, 'esense') need to handle time - ie, esense every second may allow interpolating raw sample times inbetween
(some code, not tested ...)
syncval = 0xaa
syncpos = 0
synclen = 2
synced = False
while not synced:
buffer = get_next_buffer()
if buffer.count(syncval) < 2:
continue
try:
syncpos = buffer.index(syncval)
except ValueError:
print "no sync wtf???"
nextpos = syncpos + 1
if nextpos < len(buffer) && buffer[nextpos] == syncval:
synced = True
lenpos = syncpos + synclen
lenlen = 1
paylen = buffer[syncpos+2]
assert paylen < 170 # note 170 is 0xaa - just coincidentally?
# now can examine paylen and if necessary handle case where packet is not complete
# needs rest of expected "paylen" data + checksum from next buffer
expected_len = paylen + 4
lastpos = len(buffer) - 1
if expected_len > lastpos - syncpos:
# need rest of packet from next buffer
if len(packet) < expected_len:
need_len = expected_len - len(packet)
buffer = get_next_buffer()
packet.extend(buffer[:needlen])
# would be good to store this for the next time, so don't have to re-iterate looking for next sync
loadpos = lenpos + lenlen
checkpos = loadpos + paylen
payload = packet[loadpos:checkpos] # slice so payload is a copy.
paycheck = packet[checkpos]
assert paycheck == 0xff & ~( sum(payload) & 0xff )
codons = {
0x02: ('POOR_SIGNAL', 1),
0x04: ('ATTENTION', 1),
0x05: ('MEDITATION', 1),
0x16: ('BLINK_EVENT', 1),
0x55: ('EXTENDED_CODE', 1),
0x80: ('RAW_EEG', 2),
0x83: ('ASIC_POWER', 24),
0xaa: ('SYNC', 172)
}
getdatalen = lambda x, y:y[x][1]
ptr = payload
codelen = 1 # unless extended code, not handled here.
codepos = 0
datalen = 0
def testdatalen(datalen, codetype):
if datalen > 1:
assert codetype >= 0x80
else:
assert codetype < 0x80
nextpos = 0
while nextpos < paylen:
codepos = nextpos
codetype = ptr[codepos]
assert codetype in codons
assert codetype != 0x55 # we don't handle extended code bytes.
datalen = getdatalen(codetype, codons)
nextpos = codepos + codelen
datapos = nextpos
nextpos = datapos + datalen
if nextpos >= paylen:
break
dataval = ptr[datapos:nextpos]
newpos = datapos + datalen
def syncromesh():
buffer = init_buffer()
paylen = 0
while True:
synced_buffer_portion = discard_until_sync(buffer)
expected_paylen = synced_buffer_portion[0] # written by device, packet is 4 bytes larger including 2 sync bytes
assert expected_paylen < 170
complete_packet_len = expected_paylen + 1
buflen = len(synced_buffer_portion)
if buflen < expected_paylen:
# copy remaining buffer
packet = synced_buffer_portion[:]
# will need to "extend" packet with data from next buffer
buffer = get_next_buffer
expected_remaining = expected_paylen - buflen
packet.extend(buffer[:expected_remaining])
assert len(packet) == expected_
# want function to loop, reading buffer, writing packets
# initial state, before loop:
# unsynced buffer (contains fractional packet, sync signal, then possibly complete packet/s)
# blank packet
# So, discard buffer contents before first sync signal
# begin loop
# at beginning of loop, have blank packet and synced buffer position
# write from buffer to packet
# until either
# A) buffer end reached
# B) logical packet content end reached
# C) new sync signal detected (either before or at - or after! - logical packet end)
What is "logical packet end" ?
It is max 171 bytes after sync
(total 173 bytes = 2 sync, 1 len, payload max 169 and 1 checksum byte)
Precise length should be the data paylen value written by device + 4
if A) buffer end reached
then, still in loop, get new buffer, keep writing packet
if B) "logical packet end" according to device-written "paylen" byte
then, send packet, start new blank packet
if C) sync signal detected before "logical packet end"
then, handle (apparent) dropped packet and/or logic error
- Code this logic last, just flag dropped packet for now
Log incomplete packet for analysis separate from "good" data
and start new blank packet