Using a FTDI adapter as an IR emitter – 3

This post is part 3 of 5 of  Using a FTDI adapter as an IR

Now back to where we extracted LIRC:

cd lirc-0.9.4d
./configure

If all conditions are satisfied we get this at the end:

...
checking for FTDI... no
checking for FTDI... yes
...
Summary of selected options:
----------------------------------------
prefix:                         /usr/local
sysconfdir:                     ${prefix}/etc
x_progs:                        
host:                           armv5tejl-unknown-linux-gnueabi
host_os:                        linux-gnueabi
forkpty:                        -lutil
usb_libs                        -lusb -lusb-1.0
lockdir:                        /var/lock/lockdev

Conditionals:

BUILD_ALSA_SB_RC:no
BUILD_DSP:yes
BUILD_FTDI:yes
BUILD_HIDDEV:yes
BUILD_I2CUSER:yes
BUILD_LIBALSA:no
BUILD_LIBPORTAUDIO:no
BUILD_USB:yes
BUILD_XTOOLS:no
HAVE_DOXYGEN:no
HAVE_LIBUDEV:no
HAVE_MAN2HTML:no
HAVE_PYMOD_YAML:no
INSTALL_ETC:yes
NEED_PYTHON3:no
SYSTEMD_INSTALL:yes
DEVEL:no
HAVE_UINPUT:yes
DARWIN:no
LINUX_KERNEL:yes

We may now proceed with

make

and in a perfect world or at least with my Ubuntu it will build everything fine. But on my EV3 for two times I got this:

CDPATH="${ZSH_VERSION+.}:" && cd . && /bin/bash /home/robot/lirc-0.9.4d/missing aclocal-1.15 -I m4
/home/robot/lirc-0.9.4d/missing: line 81: aclocal-1.15: command not found
WARNING: 'aclocal-1.15' is missing on your system.
         You should only need it if you modified 'acinclude.m4' or
         'configure.ac' or m4 files included by 'configure.ac'.
         The 'aclocal' program is part of the GNU Automake package:
         <http://www.gnu.org/software/automake>
         It also requires GNU Autoconf, GNU m4 and Perl in order to run:
         <http://www.gnu.org/software/autoconf>
         <http://www.gnu.org/software/m4/>
         <http://www.perl.org/>
Makefile:479: recipe for target 'aclocal.m4' failed
make: *** [aclocal.m4] Error 127

That’s strange because my Ubuntu doesn’t have autoconf installed.

I tried installing several packages but make always failed. After some googling I found a workaround. Is rather strange and honestly I don’t know why but it works:

sudo apt install automake m4 autoconf
autoreconf -i

This wil take a lot of time (at least half an hour) but after that the compiling process works as expected (almost an hour more):

./configure
make
sudo make install

 

Using a FTDI adapter as an IR emitter – 5

This post is part 5 of 5 of  Using a FTDI adapter as an IR
sudo lircd -dserial=DN01DR29,output=3 -Hftdix

We gave lircd 3 parameters:

  • “DN01DR29” is the serial number of my FTDI adapter reported by dmesg
  • “output=3″ is the CTS pin we use to control the LED (in the ‘hello-ftdi.c” test we see LED defined as 0x08, that’s because LIRC ftdix drivers calculates the pin by left-shifting, so 2<<3 = 2³ = 8)
  • “ftdix” is the driver to use

We should check if lircd is running. In Ubuntu it writes several messages at “/var/log/messages” but this log doesn’t exist in ev3dev so

pgrep lircd
5411

E also see in dmesg that the ttyUSB device was disconnected by libftdi:

[47897.512814] ftdi_sio ttyUSB0: FTDI USB Serial Device converter now disconnected from ttyUSB0
[47897.513393] ftdi_sio 1-1.2:1.0: device disconnected

We now use ‘irsend’ to check for available transmitter:

sudo irsend -d/var/run/lirc/lircd LIST "" ""

LEGO_Combo_Direct
LEGO_Combo_PWM
LEGO_Single_Output

We can also list all commands avaible for a particular transmitter:

sudo irsend -d/var/run/lirc/lircd LIST LEGO_Combo_Direct ""

000000000000010e FLOAT_FLOAT
000000000000011f FLOAT_FORWARD
000000000000012c FLOAT_BACKWARD
000000000000013d FLOAT_BRAKE
000000000000014a FORWARD_FLOAT
000000000000015b FORWARD_FORWARD
0000000000000168 FORWARD_BACKWARD
0000000000000179 FORWARD_BRAKE
0000000000000186 BACKWARD_FLOAT
0000000000000197 BACKWARD_FORWARD
00000000000001a4 BACKWARD_BACKWARD
00000000000001b5 BACKWARD_BRAKE
00000000000001c2 BRAKE_FLOAT
00000000000001d3 BRAKE_FORWARD
00000000000001e0 BRAKE_BACKWARD
00000000000001f1 BRAKE_BRAKE

For first test we’ll just use “FORWARD_FORWARD” command (move both motors, “Red” and “Blue”, forward):

sudo irsend -d /var/run/lirc/lircd SEND_ONCE LEGO_Combo_Direct FORWARD_FORWARD

And our motor do spin!

So, after such a big post, whats the point?

Well, since LIRC can handle several transmitter and for ftdix it uses the serial number of the FTDI adapter to identify each transmitter… we can have as much transmitters as we want as long as our system can handle it. On a laptop or a Raspberry Pi 3 that’s probably 127 (the max number of USB devices we can have). Most probably the Ev3 will gasp will all that USB devices but at least two I know it can handle:

Will show how in a fourth post, later on.

Using a FTDI adapter as an IR emitter – 2

This post is part 2 of 5 of  Using a FTDI adapter as an IR

We should now compile LIRC  but as I said before I never got it working  without also compiling libftdi.

I downloaded and extracted ibftdi1-1.3 source code. Then:

cd  libftdi1-1.3
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX="/usr" ../

If everything is OK, we see:

...
-- Building unit test
-- Configuring done
-- Generating done
-- Build files have been written to: /home/robot/libftdi1-1.3/build

Then

make

If everything OK:

...
[100%] Built target test_libftdi1

And finally:

sudo make install

 

 

Upgrading EV3 firmware from a VM

After yesterday post I received two precious hints from Laurens Valk and David Lechner that finally allowed me to upgrade the firmware of my EV3.

When changing to firmware upgrade mode, the EV3 changes its USB device ID (that’s why it appears as disconnected in the EV3 tool). So we just need to add a new USB filter rule in the VM settings:

0694:0006 "LEGO EV3 Firmware Update"

The original filter, for normal operating mode, is

0694:0005 "LEGO Group EV3"

And of course I made a video showing how to do it:

LEGO WeDo 2.0 with MIT App Inventor

I got a request for help today, Mr. Rocha is trying to use MIT App Inventor to control the WeDo 2.0 Smart Hub RGB LED.

I’ve never used App Inventor before but I had already installed the Companion once in my Android Phone because I read something somewhere and found it quite similar to Snap! and Scratch (and  also just because it is from MIT… I have a fetiche for MIT back from when I was at college and read Nicholas Negroponte articles on Wired). So let’s give it a try.

I just wanted to connect to the WeDo 2.0 Smart Hub and change the color to RED. When using gatttool that’s done with just

char-write-cmd 3d 06040109

Just needed to add the BLE extension to start working, getting a connection was easy but writing to the handle took a while since App Inventor BLE extension doesn’t use handles, just UUIDs. So I had to go back to my notes and find the Service UUID and the Characteristic UUID:

service_uuid = 00004f0e-1212-efde-1523-785feabcd123
characteristic_uuid = 00001565-1212-efde-1523-785feabcd123

Then I tried a block called “call BluetoothLE. WriteStringValue” but I couldn’t find a way to convert an hexadecimal string (“06040109”) to a proper string to send.

So I tried another block, “call BluetoothLE.WriteIntValue”. At first I made an old mistake, converting “06040109h” to “100925705”. Didn’t work.

Then I wrote it in reverse (“09010406h”) and converted it to “151061510”. And now it works!

WeDoLED

Now that I finally started, I think I will use App Inventor some more times. Damn easy to create an BLE Android app!

LEGO Dimensions + EV3: reading tags

I started fiddling with LEGO Dimensions Toy Pad and the Mindstorms EV3. Later I’ll post better and more organized information but for now here is the script I used with the following video – it shows how to read the NGC tags and change the RGB color of each pad.

All my code is based on woodenphone work.

#!/usr/bin/python

import usb.core
import usb.util
from time import sleep

import lego_dimensions_gateway

# UIDs can be retrieved with Android App (probably in hexadecimal)
uidDarthVader = (4, 161, 158, 210, 227, 64 , 128)

pad1_red = [0x55, 0x0e, 0xc8, 0x06, 0x01, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # left:off center:red right:off

pad1_green = [0x55, 0x0e, 0xc8, 0x06, 0x01, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # left:off center:green

pad2_red = [0x55, 0x0e, 0xc8, 0x06, 0x01, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # left:red center:off right:off

pad2_green = [0x55, 0x0e, 0xc8, 0x06, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # left:green center:off right:off

pad3_red = [0x55, 0x0e, 0xc8, 0x06, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # left:off center:off right:red

pad3_green = [0x55, 0x0e, 0xc8, 0x06, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # left:off center:off right:green

pads_off = [0x55, 0x06, 0xc0, 0x02, 0x00, 0x00, 0x00, 0x00, 29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # Switch all pads off


def init_usb():
    global dev
    # find our device
    dev = usb.core.find(idVendor=0x0e6f)# 0x0e6f Logic3 (made lego dimensions portal hardware)

    # was it found?
    if dev is None:
        raise ValueError('Device not found')

    reattach = False
    if dev.is_kernel_driver_active(0):
        reattach = True
        dev.detach_kernel_driver(0)

    # set the active configuration. With no arguments, the first
    # configuration will be the active one
    dev.set_configuration()

    # Initialise portal
    dev.write(1, [0x55, 0x0f, 0xb0, 0x01, 0x28, 0x63, 0x29, 0x20, 0x4c, 0x45, 0x47, 0x4f, 0x20, 0x32, 0x30, 0x31, 0x34, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])# Startup
    return dev

def uid_compare(uid1, uid2):
  match = True
  for i in range(0,7):
    if (uid1[i] != uid2[i]) :
       match = False
  return match 

def demo():
    while True:
        try:
            inwards_packet = dev.read(0x81, 32, timeout = 10)
            bytelist = list(inwards_packet)

            if not bytelist:# We need a packet
                pass
            elif bytelist[0] != 0x56: # Only listen to NFC packets
                pass
            else:
                pad_num = bytelist[2]
                uid_bytes = bytelist[6:13]
                match = uid_compare(uid_bytes, uidDarthVader)
                action = bytelist[5]
                if action == 0 : #IN
                  if match:
                  # Darth Vader IN
                      if pad_num ==1 :
                          command = pad1_red
                      elif pad_num == 2 :
                          command = pad2_red
                      elif pad_num == 3 :
                          command = pad3_red
                      else :
                          pass
                  else:
                  # some other tag IN
                      if pad_num ==1 :
                          command = pad1_green
                      elif pad_num == 2 :
                          command = pad2_green
                      elif pad_num == 3 :
                          command = pad3_green
                      else :
                          pass                      
                  dev.write(1, command)
                elif action == 1 : # OUT
                  dev.write(1, pads_off)

        except usb.USBError, err:
            pass

def main():
    init_usb()
    demo()
    return

if __name__ == '__main__':
    main()

WeDo 2.0 LED Button Service

This post is part 3 of 6 of  WeDo 2.0 - reverse engineering

And we continue digging into the  WeDo 2.0 Hub primary services, now with the “Nordic LED Button Service”

WeDo 2.0 Hub BLE services

[A0:E6:F8:1E:58:57][LE]> primary
...
attr handle: 0x000c, end grp handle: 0x002f uuid: 00001523-1212-efde-1523-785feabcd123
...

So this Primary service uses handles from 0x000c to 0x002f. Let’s look deeper:

[A0:E6:F8:1E:58:57][LE]> characteristics 000c 002f
handle: 0x000d, char properties: 0x0a, char value handle: 0x000e, uuid: 00001524-1212-efde-1523-785feabcd123
handle: 0x0010, char properties: 0x12, char value handle: 0x0011, uuid: 00001526-1212-efde-1523-785feabcd123
handle: 0x0014, char properties: 0x10, char value handle: 0x0015, uuid: 00001527-1212-efde-1523-785feabcd123
handle: 0x0018, char properties: 0x12, char value handle: 0x0019, uuid: 00001528-1212-efde-1523-785feabcd123
handle: 0x001c, char properties: 0x12, char value handle: 0x001d, uuid: 00001529-1212-efde-1523-785feabcd123
handle: 0x0020, char properties: 0x12, char value handle: 0x0021, uuid: 0000152a-1212-efde-1523-785feabcd123
handle: 0x0024, char properties: 0x08, char value handle: 0x0025, uuid: 0000152b-1212-efde-1523-785feabcd123
handle: 0x0027, char properties: 0x0a, char value handle: 0x0028, uuid: 0000152c-1212-efde-1523-785feabcd123
handle: 0x002a, char properties: 0x02, char value handle: 0x002b, uuid: 0000152d-1212-efde-1523-785feabcd123
handle: 0x002d, char properties: 0x08, char value handle: 0x002e, uuid: 0000152e-1212-efde-1523-785feabcd123

[A0:E6:F8:1E:58:57][LE]> char-desc 000c 002f
handle: 0x000c, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x000d, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000e, uuid: 00001524-1212-efde-1523-785feabcd123
handle: 0x000f, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0010, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0011, uuid: 00001526-1212-efde-1523-785feabcd123
handle: 0x0012, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0013, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0014, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0015, uuid: 00001527-1212-efde-1523-785feabcd123
handle: 0x0016, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0017, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0018, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0019, uuid: 00001528-1212-efde-1523-785feabcd123
handle: 0x001a, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x001b, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x001c, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x001d, uuid: 00001529-1212-efde-1523-785feabcd123
handle: 0x001e, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x001f, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0020, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0021, uuid: 0000152a-1212-efde-1523-785feabcd123
handle: 0x0022, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0023, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0024, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0025, uuid: 0000152b-1212-efde-1523-785feabcd123
handle: 0x0026, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0027, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0028, uuid: 0000152c-1212-efde-1523-785feabcd123
handle: 0x0029, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x002a, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x002b, uuid: 0000152d-1212-efde-1523-785feabcd123
handle: 0x002c, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x002d, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x002e, uuid: 0000152e-1212-efde-1523-785feabcd123
handle: 0x002f, uuid: 00002901-0000-1000-8000-00805f9b34fb

Lot of things here: 10 characteristics and 36 handles!

The first handle (0x000c) just marks the begin of the service (UUID 2800).

Then we see that there are 10 handles with UUID 2803 (Characteristic Declaration Attribute) and also 10 handles with UUID 2901 (Characteristic User Description) – these handles mark the begin of each characteristic and also defines its properties, so let’s read them all  (char-read-hnd) and translate it:

Name Char               0x000e  read+write
Button Char             0x0011  notify+read
Port Type Char          0x0015  notify
Low Voltage alert       0x0019  notify+read
High Current alert      0x001d  notify+read
Low Signal alert        0x0021  notify+read
Turn off device         0x0025  write
Vcc port control        0x0028  read+write
Battery type Indicator  0x002b  read
Disconnect Char         0x002e  write

Some characteristics also have an handle with UUID 2902 (Client Characteristic Configuration). That’s used for Notifications – the 5 characteristics that support this feature use this extra handle to activate or deactivate it.

So let’s read the 7 handles that are readable:

Name Char               75 30 30 30 31 = u0001
Button Char             00
Low Voltage alert       00
High Current alert      00
Low Signal alert        00
Vcc port control        01
Battery type Indicator  00

So ‘Name char’ contains the friendly name of my Hub. And it is writable, so what happens if I change it?

[A0:E6:F8:1E:58:57][LE]> char-write-cmd 0x000e 4d616a6f72
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0x00e
Characteristic value/descriptor: 4d 61 6a 6f 72

Well it retains what I wrote.

And if I now read the ‘Device Name’ it is no longer ‘u0001’:

[A0:E6:F8:1E:58:57][LE]> char-read-uuid 0x2A00
handle: 0x0003      value: 4d 61 6a 6f 72

So now my Hub announces a new name:

$ sudo hcitool -i hci0 lescan
LE Scan ...
A0:E6:F8:1E:58:57 (unknown)
A0:E6:F8:1E:58:57 Major

Changing 'Device Name' attribute

Cool, isn’t it?

Now the ‘Button Char’ just reads zero. But if I press the Hub’s button while I read it:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0011
Characteristic value/descriptor: 01

it reads ‘1’.

And what about ‘Port Type Char’? It’s not defined as readable (just ‘notify’) but I can try to read it anyway:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0015
Characteristic value/descriptor:

Hmm… null value.

But I have nothing connected to the Hub. Let’s try it again with a motor at port 1:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0015
Characteristic value/descriptor: 01 01 00 01 01 00 00 00 01 00 00 00

And removing the motor again:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0015
Characteristic value/descriptor: 01 00

Interesting – it’s not null now.

Let’s do the same again but on port 2:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0015
Characteristic value/descriptor: 02 01 01 01 01 00 00 00 01 00 00 00

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0015
Characteristic value/descriptor: 02 00

So the first byte seems to identify the Port (’01’ or ’02’) and the second byte the action (’01’ might be ‘device plugged’ and ’00’ might be ‘device removed’). I have no explanation for the third byte and the other 8 bytes bytes seem to be some kind of identification of the motor.

Now let’s connect a tilt sensor in port 1 (and nothing in port 2):

01 01 00 22 00 00 00 10 00 00 00 10

and then move it to port 2:

02 01 01 22 00 00 00 10 00 00 00 10

Now just a distance sensor in port 1:

01 01 00 23 00 00 00 10 00 00 00 10

and move it to port 2:

02 01 01 23 00 00 00 10 00 00 00 10

Now just the motor again in port 1 and then the tilt sensor in port 2 (two readings):

01 01 00 01 01 00 00 00 01 00 00 00
02 01 01 22 00 00 00 10 00 00 00 10

So ‘Port Type Char’ doesn’t describe the ports state, it just shows the last action detected at ports. I think that’s the reason it’s not defined as ‘notify + read’, it’s purpose is just to notify that a change ocurred on ports.

Now we have 3 characteristics named “Alert”: Low Voltage Alert, High Current Alert and Low Signal Alert. Their names seem clear enough to understand their purpose and since all read zero everything seems to be OK. But let’s try to force an “High Current Alert” – make the motor run, block it and read the handle:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 00 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 00 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 00 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 00 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 01 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 01 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 01 
[A0:E6:F8:1E:58:57][LE]> char-read-hnd 001d
Characteristic value/descriptor: 00

When I block the motor with my hand, the Hub beeps and flashes the LED twice (in yellow). And sometimes the Alert reads ’01’.

But instead of reading several times the handler, we can activate ‘Notifications’ by turning ON the ‘notification’ flag in the ‘Client Characteristic Configuration’ and then just wait for the Hub to send the notification when the High Current Alert changes it’s state:

[A0:E6:F8:1E:58:57][LE]> char-write-req 001e 0100 -listen
Characteristic value was written successfully
[A0:E6:F8:1E:58:57][LE]> char-write-cmd 003d 01010164
Notification handle = 0x001d value: 01 
Notification handle = 0x001d value: 00

We used a different write command: ‘char-write-req’ instead of ‘char-write-cmd’ expects an answer from the device and ‘-listen’ keeps listening for future ‘answers’.

Now the ‘Vcc port control’ name isn’t much clear about it’s purpose. It reads ‘1’ but it’s also writable… does it allows us to control power in the ports? No matter what I write to 0x003d it seems to retain only ‘0’ or ‘1’ and when I write ‘0’ to it while the motor is running it keeps running.

‘Battery type indicator’ reads zero, I guess that it identifies the kind of battery being used. I’m using 2 AA alcaline batteries, will try again with the LiPo battery when I get it.

And finally the 2 writable-only characteristics: ‘Disconnect Char’ and ‘Turn off device’. They also seem quite clear about their purpose:

[A0:E6:F8:1E:58:57][LE]> char-write-cmd 002e 01
[A0:E6:F8:1E:58:57][LE]> 
(gatttool:8257): GLib-WARNING **: Invalid file descriptor.

[A0:E6:F8:1E:58:57][LE]> connect
Attempting to connect to A0:E6:F8:1E:58:57
Connection successful

Writing to ‘Disconnect Char’ makes the Hub disconnects but keeps it in discovery mode so I cpuld reconnect to it.

[A0:E6:F8:1E:58:57][LE]> char-write-cmd 0025 01
[A0:E6:F8:1E:58:57][LE]> 
(gatttool:8257): GLib-WARNING **: Invalid file descriptor.

[A0:E6:F8:1E:58:57][LE]> connect
Attempting to connect to A0:E6:F8:1E:58:57
[A0:E6:F8:1E:58:57][LE]> 
Error: connect error: Connection refused (111)

Writing to ‘Turn off device’ really turns it off.

So that’s it for ‘Nordic LED button service’. What LED, you ask? Well, the Android App is from Nordic and they have some examples on the Net with this UUID so my explanation is that LEGO used part of their code for the ‘button’ part without changing the UUID so the App recognizes it this way.

Next post: Motors and LED.

WeDo 2.0 Battery Service

This post is part 2 of 6 of  WeDo 2.0 - reverse engineering

In first post we have seen that the WeDo 2.0 Hub offers a “Battery Service” Primary Service:

[A0:E6:F8:1E:58:57][LE]> primary
...
attr handle: 0x0046, end grp handle: 0xffff uuid: 0000180f-0000-1000-8000-00805f9b34fb
...

‘180F’ is defined in the Bluetooth Standard as a ‘Battery Service‘. LEGO assigned all handles from 0x0046 to 0xFFFF to this service (not quite true: since there is no other Primary Service, gatttool assumes 0xFFFF as the last handle).

What handles and characteristics?

[A0:E6:F8:1E:58:57][LE]> characteristics 0x0046 0xffff
handle: 0x0047, char properties: 0x12, char value handle: 0x0048, uuid: 00002a19-0000-1000-8000-00805f9b34fb
[A0:E6:F8:1E:58:57][LE]> char-desc 0x0046 0xffff
handle: 0x0046, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0047, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0048, uuid: 00002a19-0000-1000-8000-00805f9b34fb
handle: 0x0049, uuid: 00002902-0000-1000-8000-00805f9b34fb

So there is  just one useful characterist, the one with UUID ‘00002a19-0000-1000-8000-00805f9b34fb’ or just ‘2a19’ assigned to handle 0x0048.

There are 3 other characteristics (‘2800’, ‘2803’ and ‘2902’) each one assigned to one handle (‘0x0046’, ‘0x0048’ and ‘0x49’). What’s their purpose?

The first characteristic (‘2800’) contains the UUID of the Primary Service (we already know that it is ‘180F’):

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0x046
Characteristic value/descriptor: 0f 18

The second characteristic (‘2803’) describes the Service – something we already know from the ‘characteristics’ command:

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0x047
Characteristic value/descriptor: 12 48 00 19 2a

The first byte is the ‘characteristic properties’. Each bit has a meaning:

Broadcast: 01h
Read: 02h
Write without response: 04h
Write: 08h
Notify:10h
Indicate: 20h
Authenticated Signed Writes:40h
Extended Properties: 80h

So ’12h’ means ‘notify’ + ‘read’ so we can read and the battery level and we can also ask for notifications.

The second and third bytes specify the handle associated to the battery level: ‘0048h’.

The fourth and fifth bytes specify the characteristic UUID of the battery level: ‘2a19’.

Now the last characteristic (‘2902’) is used for notification and indication control.

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0x049
Characteristic value/descriptor: 00 00

Since it’s value is ‘0’ it means ‘Notifications and indications disabled’

Now let’s read the battery level, at the third characteristic (UUID: ‘2a19’/ Handle: 0x0048)

[A0:E6:F8:1E:58:57][LE]> char-read-hnd 0x048
Characteristic value/descriptor: 64

64h = 100d so battery level is 100%

We can also use this other command:

[A0:E6:F8:1E:58:57][LE]> char-read-uuid 2a19
handle: 0x0048      value: 64

Now let’s check with Android nRF Connect App:

WeDo 2.0 Battery Service

Seems ok once again.

Until now we just accessed information defined in the Bluetooth standard. Maybe in the future the Bluetooth SIG decide to include motors, lights and other devices in the standard but for now each vendor (like LEGO) decides how to communicate with its gadgets and if it doesn’t release that information to the public it’s almost impossible to develop third-party applications for it.

LEGO promised to release a SDK in the first half of 2016. That’s a good decision, everyone (including LEGO) will benefit if everyone can create it’s own application and even integrate it with other tools or systems. But we are already in the second half of 2016 and no SDK…

Luckily there are already a few pieces of information scattered around the Web…

Next post: the WeDo 2.0 Hub button.

WeDo 2.0 with EV3 – an ev3dev tutorial

What a great weekend:

  • at Paredes de Coura FAN Weekend with almost 200 AFOL’s from allover the world
  • finally got the LEGO Education WeDo 2.0 App working with my Android phone – thanks Fernando for being such a good PITA 😉
  • github notified me that my ev3dev tutorial got merged so it’s now available in the ev3dev site on the Tutorials section: Controlling a WeDo 2.0 motor