{"id":914,"date":"2016-06-22T16:04:11","date_gmt":"2016-06-22T15:04:11","guid":{"rendered":"http:\/\/ofalcao.pt\/blog\/?p=914"},"modified":"2016-06-22T16:23:42","modified_gmt":"2016-06-22T15:23:42","slug":"wedo-2-0-reverse-engineering","status":"publish","type":"post","link":"https:\/\/ofalcao.pt\/blog\/2016\/wedo-2-0-reverse-engineering","title":{"rendered":"WeDo 2.0 &#8211; reverse engineering"},"content":{"rendered":"<div class=\"seriesmeta\">This post is part 1 of 6 of \u00a0<a href=\"https:\/\/ofalcao.pt\/blog\/series\/wedo-2-0-reverse-engineering\" class=\"series-269\" title=\"WeDo 2.0 - reverse engineering\">WeDo 2.0 - reverse engineering<\/a><\/div><p>This post tries to gather all the information I collected in the last weeks related to the WeDo 2.0.<\/p>\n<p>I&#8217;m not a programmer but I&#8217;m a very stubborn guy so after I managed to get my linux systems (my Ubuntu laptop, some Raspberry Pi&#8217;s and my two Mindstorms EV3) controlling the SBrick I told to myself: I&#8217;m gonna make the same with this new WeDo 2.0 system no matter what it takes.<\/p>\n<p>So first things first: let&#8217;s use my Android mobile to inspect the WeDo 2.0 Hub. Nordic has a very good (and free) app that I like to use: nRF Master Control Panel (recently renamed to nRF Connect). After connecting to the Hub we find 6 services:<\/p>\n<p><a href=\"https:\/\/flic.kr\/p\/HZ3LHo\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/farm8.staticflickr.com\/7201\/27556208400_ebf848cce9_z.jpg?resize=360%2C640&#038;ssl=1\" alt=\"BLE services\" width=\"360\" height=\"640\" \/><\/a><\/p>\n<p>Some of this services, like &#8220;Battery Service&#8221; are known BLE services so [hopefully] it will be easy to use.<\/p>\n<p>There&#8217;s also a very important finding at the top:<\/p>\n<p>&#8220;U0001 A0:E6:F8:1E:58:57<\/p>\n<p>&#8220;A0:E6:F8:1E:58:57&#8221; is the Bluetooth address of my Hub (similar to the MAC Address of every network device). It will be used *a lot* in the rest of this post.<\/p>\n<p>And &#8220;U0001&#8221; is the friendly name that the Hub advertises &#8211; that&#8217;s the name that shows up in the LEGO Education WeDo 2.0 App when connecting to the Hub:<\/p>\n<p><a href=\"https:\/\/flic.kr\/p\/JhYKux\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/farm8.staticflickr.com\/7504\/27759120771_42ccef6463_z.jpg?resize=640%2C360&#038;ssl=1\" alt=\"WeDo 2.0 making a connection\" width=\"640\" height=\"360\" \/><\/a><\/p>\n<p>A note about this name: before I finally managed to make the LEGO Education WeDo 2.0 App work in my Android phone, my Hub advertised itself as &#8220;LPF2 Smart Hub 2 I\/O&#8221;. So the LEGO App changed it to &#8220;u0001&#8221;, probably at the first time it connected to it (but since my Hub was first used by 3 other AFOL&#8217;s at Paredes de Coura I&#8217;m not sure if the process is automatic or the user is given some kind of option).<\/p>\n<p>So the default (factory set) name of the Hub is &#8220;LPF2 Smart Hub 2 I\/O&#8221; &#8211; LEGO Power Functions 2 Smart Hub 2 I\/O&#8221;. Not much to speculate here: LEGO announced that Power Functions and Mindstorms will adopt a new plug type so new devices are expected, this is just the first one. But &#8220;Smart Hub 2 I\/O&#8221; is interesting&#8230; does that means that there will be other Smart Hubs? Perhaps even a &#8220;Smart Hub 4 I\/O&#8221;? That would answer some of the points I have been discussing with Fernando Conchas like &#8220;what&#8217;s the use for a 4.5 Volt device in LEGO Technic unless there&#8217;s also another device with better power features just waiting to come out&#8221;?<\/p>\n<p>Now let&#8217;s look deeper to those BLE services&#8230;<\/p>\n<p>I can use the nRF App and take a lot of screenshots but now that I know the BT address I will switch to my Ubuntu laptop and use 2 of the available BlueZ (the native Linux Bluetooth stack) functions, &#8216;hcitool&#8217; and &#8216;gatttool&#8217;<\/p>\n<pre>$ sudo hcitool -i hci0 lescan\r\nLE Scan ...\r\nA0:E6:F8:1E:58:57 (unknown)\r\nA0:E6:F8:1E:58:57 LPF2 Smart Hub 2 I\/O<\/pre>\n<pre>sudo gatttool -i hci0 -b A0:E6:F8:1E:58:57 --primary\r\nattr handle = 0x0001, end grp handle = 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb\r\nattr handle = 0x0008, end grp handle = 0x000b uuid: 00001801-0000-1000-8000-00805f9b34fb\r\nattr handle = 0x000c, end grp handle = 0x002f uuid: 00001523-1212-efde-1523-785feabcd123\r\nattr handle = 0x0030, end grp handle = 0x003e uuid: 00004f0e-1212-efde-1523-785feabcd123\r\nattr handle = 0x003f, end grp handle = 0x0045 uuid: 0000180a-0000-1000-8000-00805f9b34fb\r\nattr handle = 0x0046, end grp handle = 0xffff uuid: 0000180f-0000-1000-8000-00805f9b34fb<\/pre>\n<p>The &#8216;gatttool&#8217; command is a powerfull tool for BLE &#8211; in the past, without a proper BLE library for python, I used it (through python system calls) to talk with the SBrick. Clumsy but&#8230; hey, I said I&#8217;m not a programmer \ud83d\ude09<\/p>\n<p>The &#8216;gatttool&#8217; can run in an interactive mode that allows us to establish a connection and keep it until we disconnect instead of making a new connection each time we want to test a command:<\/p>\n<pre>$ sudo gatttool -i hci0 -I\r\n[\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ][LE]&gt; connect A0:E6:F8:1E:58:57\r\nAttempting to connect to A0:E6:F8:1E:58:57\r\nConnection successful\r\n[A0:E6:F8:1E:58:57][LE]&gt;<\/pre>\n<p>In this &#8220;interactive&#8221; session we just send &#8216;primary&#8217; to get the same output as using the command with &#8216;&#8211;primary&#8217; option [but sometimes the commands differ a bit, so use &#8216;help&#8217; and &#8216;&#8211;help&#8217; to know what to use.<\/p>\n<p>So the &#8216;primary&#8217; command gets a list of the primary services offered by the WeDo 2.0 Hub. Of course, those are the same 6 services found by the Nordic app but that screenshot looks much better as Nordic developers added lots of intelligence to it.<\/p>\n<p>First service:<\/p>\n<pre>attr handle = 0x0001, end grp handle = 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb<\/pre>\n<p>The Nordic app shows just:<\/p>\n<p style=\"padding-left: 30px;\">Generic Access<br \/>\nUUID: 0x1800<br \/>\nPRIMARY SERVICE<\/p>\n<p>So this service has 7 handles assigned (from 0x0001 to 0x0007) and serves a well know service (the &#8216;<a href=\"https:\/\/developer.bluetooth.org\/gatt\/services\/Pages\/ServiceViewer.aspx?u=org.bluetooth.service.generic_access.xml\">Generic Access<\/a>&#8216;) so it&#8217;s UUID is shortened to just 0x1800 instead of &#8216;00001800-0000-1000-8000-00805f9b34fb&#8217;.<\/p>\n<p>Bluetooth specification for &#8216;Generic Access&#8217; defines 5 properties:<\/p>\n<ul>\n<li style=\"padding-left: 30px;\">Device Name (0x2A00)<\/li>\n<li style=\"padding-left: 30px;\">Appearance (0x2A01)<\/li>\n<li style=\"padding-left: 30px;\">Peripheral Privacy Flag (0x2A02)<\/li>\n<li style=\"padding-left: 30px;\">Reconnection Address (0x2A03)<\/li>\n<li style=\"padding-left: 30px;\">Peripheral Preferred Connection Parameters (0x2A04)<\/li>\n<\/ul>\n<p>From these list, only &#8216;Device Name&#8217; and &#8216;Appearance&#8217; are defined as &#8216;Mandatory&#8217;.<\/p>\n<p>With the gatttool we read these properties with command &#8216;char-read-uuid&#8217;:<\/p>\n<pre>[A0:E6:F8:1E:58:57][LE]&gt; char-read-uuid 0x2A00\r\nhandle: 0x0003 \u00a0\u00a0 \u00a0 value: 75 30 30 30 31 \r\n[A0:E6:F8:1E:58:57][LE]&gt; char-read-uuid 0x2A01\r\nhandle: 0x0005 \u00a0\u00a0 \u00a0 value: 00 00 \r\n[A0:E6:F8:1E:58:57][LE]&gt; char-read-uuid 0x2A02\r\nError: Read characteristics by UUID failed: No attribute found within the given range\r\n[A0:E6:F8:1E:58:57][LE]&gt; char-read-uuid 0x2A03\r\nError: Read characteristics by UUID failed: No attribute found within the given range\r\n[A0:E6:F8:1E:58:57][LE]&gt; char-read-uuid 0x2A04\r\nhandle: 0x0007 \u00a0\u00a0 \u00a0 value: 50 00 a0 00 00 00 e8 03<\/pre>\n<p>So &#8216;Peripheral Privacy Flag&#8217; and &#8216;Reconnection Address&#8217; were not implemented by LEGO. But what&#8217;s the meaning of this hexadecimal values?<\/p>\n<p>&#8216;<a href=\"https:\/\/developer.bluetooth.org\/gatt\/characteristics\/Pages\/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.device_name.xml\">Device Name<\/a>&#8216; is a string so we just convert it to ASCII (we can use an online tool like <a href=\"http:\/\/www.rapidtables.com\/convert\/number\/hex-to-ascii.htm\">RapidTables<\/a>):<\/p>\n<p style=\"text-align: center;\">75 30 30 30 31 -&gt; u0001<\/p>\n<p>Ah-ha!<\/p>\n<p>&#8216;<a href=\"https:\/\/developer.bluetooth.org\/gatt\/characteristics\/Pages\/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml\">Appearance<\/a>&#8216; is two-byte value &#8220;composed of a category (10-bits) and sub-categories (6-bits)&#8221; that classifies the device. Since it is &#8216;0&#8217;, it&#8217;s not classified in any known category (so it is &#8216;Unknown&#8217;).<\/p>\n<p>&#8216;<a href=\"https:\/\/developer.bluetooth.org\/gatt\/characteristics\/Pages\/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.peripheral_preferred_connection_parameters.xml\">Peripheral Preferred Connection Parameters<\/a>&#8216; is an 8-byte value containing 4 parameters (each one is 2-byte):<\/p>\n<p style=\"padding-left: 30px;\">Minimum Connection Interval<br \/>\nMaximum Connection Interval<br \/>\nSlave Latency<br \/>\nConnection Supervision Timeout Multiplier<\/p>\n<p>Each value is written in reverse order so<\/p>\n<p style=\"padding-left: 30px;\">Minimum Connection Interval =005h = 80d<br \/>\nMaximum Connection Interval = 000ah = 160<br \/>\nSlave Latency = 0<br \/>\nConnection Supervision Timeout Multiplier = 03e8h=1000d<\/p>\n<p>According to definition, the Min\/Max Connection Interval values should be multiplied by 1.25 so the range is in fact 100~200 [ms].<\/p>\n<p>So let&#8217;s return to the Android and validate these:<\/p>\n<p><a href=\"https:\/\/flic.kr\/p\/HZjuYW\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/farm8.staticflickr.com\/7374\/27559277270_97e41a4c8f_z.jpg?resize=360%2C640&#038;ssl=1\" alt=\"WeDo 2.0 &#039;Generic Access&#039; primary service\" width=\"360\" height=\"640\" \/><\/a><\/p>\n<p>Yes, it certainly looks good!<\/p>\n<p>Next post we&#8217;ll see another well-know service: the &#8216;Battery Service&#8217;.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"seriesmeta\">This post is part 1  of 6 of \u00a0<a href=\"https:\/\/ofalcao.pt\/blog\/series\/wedo-2-0-reverse-engineering\" class=\"series-269\" title=\"WeDo 2.0 - reverse engineering\">WeDo 2.0 - reverse engineering<\/a><\/div><p>This post tries to gather all the information I collected in the last weeks related to the WeDo 2.0. I&#8217;m not a programmer but I&#8217;m a very stubborn guy so after I managed to get my linux systems (my Ubuntu laptop, some Raspberry Pi&#8217;s and my two Mindstorms EV3) controlling the SBrick I told to &hellip; <a href=\"https:\/\/ofalcao.pt\/blog\/2016\/wedo-2-0-reverse-engineering\" class=\"more-link\">Continuar a ler<span class=\"screen-reader-text\"> &#8220;WeDo 2.0 &#8211; reverse engineering&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[38,39,233,154,18,19,158,20,148,265],"tags":[270,231],"series":[269],"class_list":["post-914","post","type-post","status-publish","format-standard","hentry","category-ble","category-bluetooth","category-bluetooth-pt","category-lego-en","category-lego","category-lego-mindstorms","category-lego-mindstorms-en","category-linux","category-linux-en","category-wedo","tag-gatttool","tag-wedo-2-0","series-wedo-2-0-reverse-engineering"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2Mhyv-eK","_links":{"self":[{"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/posts\/914","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/comments?post=914"}],"version-history":[{"count":0,"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/posts\/914\/revisions"}],"wp:attachment":[{"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/media?parent=914"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/categories?post=914"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/tags?post=914"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/ofalcao.pt\/blog\/wp-json\/wp\/v2\/series?post=914"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}