From 5ea8b024da82871d4054356f8a645c8d61bbcd47 Mon Sep 17 00:00:00 2001 From: Uwe Hermann Date: Sun, 27 May 2012 16:05:34 +0200 Subject: [PATCH] srd: Wii Nunchuk: Complete rewrite, PD works now. The Nintendo Wii Nunchuk protocol decoder, while it was in the repo for a while, didn't really work yet (among other things, due to lack of dumps for testing the code). This is fixed now, the rewritten decoder works fine with most dump files in the sigrok-dumps repo. A few minor issues remain to be added/fixed, though. --- decoders/nunchuk/nunchuk.py | 167 +++++++++++++++++++++--------------- 1 file changed, 99 insertions(+), 68 deletions(-) diff --git a/decoders/nunchuk/nunchuk.py b/decoders/nunchuk/nunchuk.py index 1bcba23..f59fced 100644 --- a/decoders/nunchuk/nunchuk.py +++ b/decoders/nunchuk/nunchuk.py @@ -32,16 +32,18 @@ class Decoder(srd.Decoder): inputs = ['i2c'] outputs = ['nunchuck'] probes = [] - optional_probes = [] # TODO + optional_probes = [] options = {} annotations = [ + ['Text (verbose)', 'Human-readable text (verbose)'], ['Text', 'Human-readable text'], ] def __init__(self, **kwargs): - self.state = 'IDLE' # TODO: Can we assume a certain initial state? + self.state = 'IDLE' self.sx = self.sy = self.ax = self.ay = self.az = self.bz = self.bc = 0 self.databytecount = 0 + self.reg = 0x00 def start(self, metadata): # self.out_proto = self.add(srd.OUTPUT_PROTO, 'nunchuk') @@ -50,79 +52,108 @@ class Decoder(srd.Decoder): def report(self): pass - def decode(self, ss, es, data): + def handle_reg_0x00(self, databyte): + self.sx = databyte + self.put(0, 0, self.out_ann, + [0, ['Analog stick X position: 0x%02x' % self.sx]]) + self.put(0, 0, self.out_ann, [1, ['SX: 0x%02x' % self.sx]]) + + def handle_reg_0x01(self, databyte): + self.sy = databyte + self.put(0, 0, self.out_ann, + [0, ['Analog stick Y position: 0x%02x' % self.sy]]) + self.put(0, 0, self.out_ann, [1, ['SY: 0x%02x' % self.sy]]) + + def handle_reg_0x02(self, databyte): + self.ax = databyte << 2 + self.put(0, 0, self.out_ann, + [0, ['Accelerometer X value bits[9:2]: 0x%03x' % self.ax]]) + self.put(0, 0, self.out_ann, [1, ['AX[9:2]: 0x%03x' % self.ax]]) + + def handle_reg_0x03(self, databyte): + self.ay = databyte << 2 + self.put(0, 0, self.out_ann, + [0, ['Accelerometer Y value bits[9:2]: 0x%03x' % self.ay]]) + self.put(0, 0, self.out_ann, [1, ['AY[9:2]: 0x%x' % self.ay]]) + + def handle_reg_0x04(self, databyte): + self.az = databyte << 2 + self.put(0, 0, self.out_ann, + [0, ['Accelerometer Z value bits[9:2]: 0x%03x' % self.az]]) + self.put(0, 0, self.out_ann, [1, ['AZ[9:2]: 0x%x' % self.az]]) + + # TODO: Bit-exact annotations. + def handle_reg_0x05(self, databyte): + self.bz = (databyte & (1 << 0)) >> 0 # Bits[0:0] + self.bc = (databyte & (1 << 1)) >> 1 # Bits[1:1] + ax_rest = (databyte & (3 << 2)) >> 2 # Bits[3:2] + ay_rest = (databyte & (3 << 4)) >> 4 # Bits[5:4] + az_rest = (databyte & (3 << 6)) >> 6 # Bits[7:6] + self.ax |= ax_rest + self.ay |= ay_rest + self.az |= az_rest + + s = '' if (self.bz == 0) else 'not ' + self.put(0, 0, self.out_ann, [0, ['Z button: %spressed' % s]]) + self.put(0, 0, self.out_ann, [1, ['BZ: %d' % self.bz]]) + + s = '' if (self.bc == 0) else 'not ' + self.put(0, 0, self.out_ann, [0, ['C button: %spressed' % s]]) + self.put(0, 0, self.out_ann, [1, ['BC: %d' % self.bc]]) + + self.put(0, 0, self.out_ann, + [0, ['Accelerometer X value bits[1:0]: 0x%03x' % ax_rest]]) + self.put(0, 0, self.out_ann, [1, ['AX[1:0]: 0x%x' % ax_rest]]) + + self.put(0, 0, self.out_ann, + [0, ['Accelerometer Y value bits[1:0]: 0x%03x' % ay_rest]]) + self.put(0, 0, self.out_ann, [1, ['AY[1:0]: 0x%x' % ay_rest]]) + + self.put(0, 0, self.out_ann, + [0, ['Accelerometer Z value bits[1:0]: 0x%03x' % az_rest]]) + self.put(0, 0, self.out_ann, [1, ['AZ[1:0]: 0x%x' % az_rest]]) + def decode(self, ss, es, data): cmd, databyte = data - if cmd == 'START': # TODO: Handle 'Sr' here, too? - self.state = 'START' - - elif cmd == 'START REPEAT': - pass # FIXME - - elif cmd == 'ADDRESS READ': - # TODO: Error/Warning, not supported, I think. - pass - - elif cmd == 'ADDRESS WRITE': - # The Wii Nunchuk always has slave address 0x54. - # TODO: Handle this stuff more correctly. - if databyte == 0x54: - pass # TODO - else: - pass # TODO: What to do here? Ignore? Error? - - elif cmd == 'DATA READ' and self.state == 'INITIALIZED': - if self.databytecount == 0: - self.sx = databyte - elif self.databytecount == 1: - self.sy = databyte - elif self.databytecount == 2: - self.ax = databyte << 2 - elif self.databytecount == 3: - self.ay = databyte << 2 - elif self.databytecount == 4: - self.az = databyte << 2 - elif self.databytecount == 5: - self.bz = (databyte & (1 << 0)) >> 0 - self.bc = (databyte & (1 << 1)) >> 1 - self.ax |= (databyte & (3 << 2)) >> 2 - self.ay |= (databyte & (3 << 4)) >> 4 - self.az |= (databyte & (3 << 6)) >> 6 - - d = 'sx = 0x%02x, sy = 0x%02x, ax = 0x%02x, ay = 0x%02x, ' \ - 'az = 0x%02x, bz = 0x%02x, bc = 0x%02x' % (self.sx, \ + # Store the start/end samples of this I2C packet. + self.ss, self.es = ss, es + + # State machine. + if self.state == 'IDLE': + # Wait for an I2C START condition. + if cmd != 'START': + return + self.state = 'GET SLAVE ADDR' + self.block_start_sample = ss + elif self.state == 'GET SLAVE ADDR': + # Wait for an address read operation. + if cmd != 'ADDRESS READ': + return + self.state = 'READ REGS' + elif self.state == 'READ REGS': + if cmd == 'DATA READ': + handle_reg = getattr(self, 'handle_reg_0x%02x' % self.reg) + handle_reg(databyte) + self.reg += 1 + elif cmd == 'STOP': + self.block_end_sample = es + + # TODO: Only works if host reads _all_ regs (0x00 - 0x05). + d = 'SX = 0x%02x, SY = 0x%02x, AX = 0x%02x, AY = 0x%02x, ' \ + 'AZ = 0x%02x, BZ = 0x%02x, BC = 0x%02x' % (self.sx, \ self.sy, self.ax, self.ay, self.az, self.bz, self.bc) - self.put(ss, es, self.out_ann, [0, [d]]) + self.put(self.block_start_sample, self.block_end_sample, + self.out_ann, [0, [d]]) self.sx = self.sy = self.ax = self.ay = self.az = 0 self.bz = self.bc = 0 - else: - pass # TODO - - if 0 <= self.databytecount <= 5: - self.databytecount += 1 - - # TODO: If 6 bytes read -> save and reset - # TODO - elif cmd == 'DATA READ' and self.state != 'INITIALIZED': - pass - - elif cmd == 'DATA WRITE': - if self.state == 'IDLE': - self.state = 'INITIALIZED' - return - - if databyte == 0x40 and self.state == 'START': - self.state = 'INIT' - elif databyte == 0x00 and self.state == 'INIT': - self.put(ss, es, self.out_ann, [0, ['Initialize nunchuk']]) - self.state = 'INITIALIZED' + self.state = 'IDLE' else: - pass # TODO - - elif cmd == 'STOP': - self.state = 'INITIALIZED' - self.databytecount = 0 + # self.put(0, 0, self.out_ann, + # [0, ['Ignoring: %s (data=%s)' % (cmd, databyte)]]) + pass + else: + raise Exception('Invalid state: %s' % self.state) -- 2.30.2