Merge branch 'master' into simplified-eventing

Conflicts:
	inc/MicroBitMessageBus.h
This commit is contained in:
Joe Finney 2015-10-18 18:20:03 +01:00
commit 424b825185
56 changed files with 12475 additions and 370 deletions

3
CHANGES.md Normal file
View File

@ -0,0 +1,3 @@
# micro:bit BLE profile : Changes
See ble _ issue _ tracker.md for Bluetooth Low Energy profile related issues

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,259 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head><title>Bluetooth Developer Studio - Level 1 Profile Report</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="style.css" />
<script language="javascript" type="text/javascript" src="functions.js"></script>
</head>
<body onLoad="init()">
<div id="id_container" class="container">
<div class="main_heading">
<div id="id_date" class="date">The Date</div>
<div class="heading_title">Bluetooth Developer Studio Level 1 Profile Report</div>
<div class="icon"><img src="BluetoothSIG.png"/></div>
</div>
<!-- Profile Block -->
<div class="section_hdg">
<div class="profile_hdg_text"><p>PROFILE</p></div>
</div>
<div class="profile_item">
<div class="profile_label">Profile Name</div>
</div>
<div class="profile_item">
<div class="profile_value">BBC MICROBIT</div>
</div>
<div class="profile_item">
<div class="profile_label">Abstract:</div>
</div>
<div class="profile_item">
<div class="text_block"><pre>Default 'out of the box' profile for the BBC Micro Bit</pre></div>
</div>
<div class="profile_item">
<div class="profile_label">Summary:</div>
</div>
<div class="profile_item">
<div class="text_block"><pre>Version 1.6 - 17th October 2015
Removed the Battery Service. No way to establish battery levels on the micro:bit
Added a simple Temperature Service to exploit temperature sensors in micro:bit processors with Temperature and Temperature Period characteristics.
Accelerometer and Magnetometer period characteristics now have uint16 fields instead of uint8 which required scaling up by multipling by 10.
Accelerometer Data and Magnetometer Data characteristics now use signed 16 bit integer fields for each of their X, Y and Z parts.
Accelerometer Data and Magnetometer Data characteristics now use signed 16 bit integer fields for each of their X, Y and Z parts.
New characteristic Magnetometer Heading added to the Magnetometer Service. Provides current heading in degrees.
Removed IO Parallel Port characteristic due to complexity and memory considerations.
Added Generic Attribute Service (previously absent in the repository)
Changed the LED Matrix State characteristic field so that we now have one octet per row of LEDs for ease of use.
Version 1.5 - 10th September 2015
Button State 2 characteristic given new, distinct UUID of E95DDA91-251D-470A-A062-FA1922DFA9A8
Removed the System LED State characteristic from the LED Service since it cannot be controlled from the BLE MCU.
Removed the Scrolling State characteristic from the LED Service due to complexity and memory constraints.
Changed LED Matrix State use of “Write Without Response” to “Write” so that no further writes can be made until theres been an ACK back from the previous one.
Removed Write property from MicroBit Requirements characteristic.</pre></div>
</div>
<div class="profile_item">
<div class="profile_label">Base UUID</div>
<div class="profile_value">E95D0000251D470AA062FA1922DFA9A8</div>
</div>
<div class="profile_item">
<div class="profile_label">Server Role</div>
<div class="profile_value"></div>
</div>
<div class="profile_item">
<div class="profile_label">Client Role</div>
<div class="profile_value"></div>
</div>
<!-- End of Profile Block -->
<!-- Services Section -->
<div class="services_section_hdg">
<div class="services_hdg_text"><p>SERVICES</p></div>
</div>
<!-- Service Block -->
<div class="service_hdg">
<div><p class="service_hdg_text1">Generic Access</p></div>
<div class="service_hdg_text2"><p>0000180000001000800000805F9B34FB</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Device Name : 00002A0000001000800000805F9B34FB</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Appearance : 00002A0100001000800000805F9B34FB</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Peripheral Preferred Connection Parameters : 00002A0400001000800000805F9B34FB</p></div>
</div>
<!-- Service Block -->
<div class="service_hdg">
<div><p class="service_hdg_text1">Generic Attribute</p></div>
<div class="service_hdg_text2"><p>0000180100001000800000805F9B34FB</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Service Changed : 2A05</p></div>
</div>
<!-- Service Block -->
<div class="service_hdg">
<div><p class="service_hdg_text1">Device Information</p></div>
<div class="service_hdg_text2"><p>0000180A00001000800000805F9B34FB</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Manufacturer Name String : 00002A2900001000800000805F9B34FB</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Model Number String : 00002A2400001000800000805F9B34FB</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Serial Number String : 00002A2500001000800000805F9B34FB</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Hardware Revision String : 00002A2700001000800000805F9B34FB</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Firmware Revision String : 00002A2600001000800000805F9B34FB</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Software Revision String : 00002A2800001000800000805F9B34FB</p></div>
</div>
<!-- Service Block -->
<div class="service_hdg">
<div><p class="service_hdg_text1">ACCELEROMETER SERVICE</p></div>
<div class="service_hdg_text2"><p>E95D0753251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Accelerometer Data : E95DCA4B251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Accelerometer Period : E95DFB24251D470AA062FA1922DFA9A8</p></div>
</div>
<!-- Service Block -->
<div class="service_hdg">
<div><p class="service_hdg_text1">MAGNETOMETER SERVICE</p></div>
<div class="service_hdg_text2"><p>E95DF2D8251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Magnetometer Data : E95DFB11251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Magnetometer Period : E95D386C251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Magnetometer Bearing : E95D9715251D470AA062FA1922DFA9A8</p></div>
</div>
<!-- Service Block -->
<div class="service_hdg">
<div><p class="service_hdg_text1">Button Service</p></div>
<div class="service_hdg_text2"><p>E95D9882251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Button 1 State : E95DDA90251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Button 2 State : E95DDA91251D470AA062FA1922DFA9A8</p></div>
</div>
<!-- Service Block -->
<div class="service_hdg">
<div><p class="service_hdg_text1">IO PIN SERVICE</p></div>
<div class="service_hdg_text2"><p>E95D127B251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Pin Data : E95D8D00251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Pin AD Configuration : E95D5899251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Pin IO Configuration : E95DB9FE251D470AA062FA1922DFA9A8</p></div>
</div>
<!-- Service Block -->
<div class="service_hdg">
<div><p class="service_hdg_text1">LED SERVICE</p></div>
<div class="service_hdg_text2"><p>E95DD91D251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>LED Matrix State : E95D7B77251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>LED Text : E95D93EE251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Scrolling Delay : E95D0D2D251D470AA062FA1922DFA9A8</p></div>
</div>
<!-- Service Block -->
<div class="service_hdg">
<div><p class="service_hdg_text1">EVENT SERVICE</p></div>
<div class="service_hdg_text2"><p>E95D93AF251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>MicroBit Requirements : E95DB84C251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>MicroBit Event : E95D9775251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Client Requirements : E95D23C4251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Client Event : E95D5404251D470AA062FA1922DFA9A8</p></div>
</div>
<!-- Service Block -->
<div class="service_hdg">
<div><p class="service_hdg_text1">DFU CONTROL SERVICE</p></div>
<div class="service_hdg_text2"><p>E95D93B0251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>DFU Control : E95D93B1251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>DFU Flash Code : E95D93B2251D470AA062FA1922DFA9A8</p></div>
</div>
<!-- Service Block -->
<div class="service_hdg">
<div><p class="service_hdg_text1">TEMPERATURE SERVICE</p></div>
<div class="service_hdg_text2"><p>E95D6100251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Temperature : E95D9250251D470AA062FA1922DFA9A8</p></div>
</div>
<div class="characteristic_hdg">
<div class="characteristic_summary"><p>Temperature Period : E95D1B25251D470AA062FA1922DFA9A8</p></div>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -0,0 +1,5 @@
function init() {
var d = new Date();
var n = d.toLocaleDateString();
document.getElementById("id_date").innerHTML = n;
}

463
docs/Report 1/style.css Normal file
View File

@ -0,0 +1,463 @@
html,body {
height: 100%;
}
* {
padding: 0;
margin: 0;
}
body {
background-color: #ffffff;
padding: 0px;
margin: 0px;
font-family: "lucida sans", verdana, arial, helvetica, sans-serif;
font-size: 75%;
}
p
{
padding-left:5px;
}
.centred_text {
text-align:center
}
/* 8 pixels included for border width 1 between panels */
.container {
background-color: #FFFFFF;
width: 1280px;
margin: 0 auto;
}
.main_heading {
width: 1280px;
line-height: 79px;
height: 79px;
float:left;
font-size: 18px;
font-weight:bold;
color:#000000;
}
.date {
width: 100px;
line-height: 79px;
height: 79px;
float:left;
}
.heading_title {
width: 980px;
line-height: 79px;
height: 79px;
float:left;
text-align:center;
}
.icon {
width: 200px;
line-height: 79px;
height: 79;
float:left;
}
.section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
/* setting line-height to equal the height property causes the text to be centred vertically */
.profile_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1280px;
height:33px;
line-height: 33px;
background-color: #4F81BD
}
.profile_item {
float:left;
width:1265px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
padding-left: 15px;
background-color: #66CCFF
}
.profile_label {
width: 300px;
font-size: 14px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
}
.profile_value {
font-size: 14px;
line-height: 33px;
height: 33px;
float:left;
}
.text_block {
font-size: 14px;
float:left;
padding-top: 5px;
padding-bottom: 5px;
}
.services_section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
padding-top: 15px
}
.services_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1280px;
height:33px;
line-height: 33px;
background-color: #21610B;
}
.service_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.service_hdg_text1 {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:800px;
padding-left: 10px;
height:33px;
line-height: 33px;
background-color: #339933
}
.service_hdg_text2 {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:470px;
height:33px;
line-height: 33px;
background-color: #339933
}
.service_item {
float:left;
width:1265px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
padding-left: 15px;
background-color: #00FFBF;
}
.service_label {
width: 300px;
font-size: 12px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
}
.service_value {
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
}
.characteristics_section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.characteristics_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
height:33px;
line-height: 33px;
background-color: #FF6633;
width:1265px;
padding-left: 15px;
}
.characteristic_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.characteristic_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1250px;
padding-left: 30px;
height:33px;
line-height: 33px;
background-color: #FFCC33
}
.characteristic_item {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #F5F6CE
}
.characteristic_summary {
float:left;
width:1250px;
height:33px;
line-height: 33px;
padding-left: 30px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #F5F6CE
}
.characteristic_label {
width: 300px;
font-size: 12px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
padding-left: 45px;
}
.characteristic_value {
width: 935px;
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
}
.characteristic_field {
float:left;
width:1280px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #F5F6CE;
padding-top: 10px;
}
.characteristic_field_label {
width: 300px;
font-size: 12px;
font-weight:bold;
min-height: 33px;
float:left;
padding-left: 45px;
}
.characteristic_field_value {
width: 935px;
font-size: 12px;
float:left;
}
.descriptors_section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.descriptors_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
height:33px;
line-height: 33px;
background-color: #6600CC;
width:1235px;
padding-left: 45px;
}
.descriptor_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.descriptor_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1230px;
padding-left: 50px;
height:33px;
line-height: 33px;
background-color: #BE81F7;
}
.descriptor_item {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #D8CEF6
}
.descriptor_label {
width: 300px;
font-size: 12px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
padding-left: 60px;
}
.descriptor_value {
width: 920px;
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
}
.char_fields_section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.char_fields_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
height:33px;
line-height: 33px;
background-color: #A4A4A4;
width:1235px;
padding-left: 45px;
}
.char_field_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.char_field_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1230px;
padding-left: 50px;
height:33px;
line-height: 33px;
background-color: #BE81F7;
}
.char_field_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1225px;
padding-left: 55px;
height:33px;
line-height: 33px;
background-color: #E6E6E6;
}
.char_field_item {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #FAFAFA
}
.char_field_label {
width: 300px;
font-size: 12px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
padding-left: 60px;
}
.char_field_value {
width: 920px;
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
}
.align_right
{
text-align: right;
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -0,0 +1,5 @@
function init() {
var d = new Date();
var n = d.toLocaleDateString();
document.getElementById("id_date").innerHTML = n;
}

467
docs/Report 2/style.css Normal file
View File

@ -0,0 +1,467 @@
html,body {
height: 100%;
}
* {
padding: 0;
margin: 0;
}
body {
background-color: #ffffff;
padding: 0px;
margin: 0px;
font-family: "lucida sans", verdana, arial, helvetica, sans-serif;
font-size: 75%;
}
p
{
padding-left:5px;
}
.centred_text {
text-align:center
}
/* 8 pixels included for border width 1 between panels */
.container {
background-color: #FFFFFF;
width: 1280px;
margin: 0 auto;
}
.main_heading {
width: 1280px;
line-height: 79px;
height: 79px;
float:left;
font-size: 18px;
font-weight:bold;
color:#000000;
}
.date {
width: 100px;
line-height: 79px;
height: 79px;
float:left;
}
.heading_title {
width: 980px;
line-height: 79px;
height: 79px;
float:left;
text-align:center;
}
.icon {
width: 200px;
line-height: 79px;
height: 79;
float:left;
}
.section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
/* setting line-height to equal the height property causes the text to be centred vertically */
.profile_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1280px;
height:33px;
line-height: 33px;
background-color: #4F81BD
}
.profile_item {
float:left;
width:1265px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
padding-left: 15px;
background-color: #66CCFF
}
.profile_label {
width: 300px;
font-size: 14px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
}
.profile_value {
font-size: 14px;
line-height: 33px;
height: 33px;
float:left;
}
.text_block {
font-size: 14px;
float:left;
padding-top: 5px;
padding-bottom: 5px;
}
.services_section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
padding-top: 15px
}
.services_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1280px;
height:33px;
line-height: 33px;
background-color: #21610B;
}
.service_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.service_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1270px;
padding-left: 10px;
height:33px;
line-height: 33px;
background-color: #339933
}
.service_item {
float:left;
width:1265px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
padding-left: 15px;
background-color: #00FFBF;
}
.service_label {
width: 300px;
font-size: 12px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
}
.service_value {
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
}
.characteristics_section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.characteristics_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
height:33px;
line-height: 33px;
background-color: #FF6633;
width:1265px;
padding-left: 15px;
}
.characteristic_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.characteristic_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1250px;
padding-left: 30px;
height:33px;
line-height: 33px;
background-color: #FFCC33
}
.characteristic_item {
float:left;
width:1280px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #F5F6CE
}
.characteristic_summary {
float:left;
width:1250px;
height:33px;
line-height: 33px;
padding-left: 30px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #F5F6CE
}
.characteristic_label {
width: 300px;
font-size: 12px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
padding-left: 45px;
}
.char_text_block {
font-size: 14px;
float:left;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 45px;
}
.characteristic_value {
width: 935px;
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
}
.characteristic_field {
float:left;
width:1280px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #F5F6CE;
padding-top: 10px;
}
.characteristic_field_label {
width: 300px;
font-size: 12px;
font-weight:bold;
min-height: 33px;
float:left;
padding-left: 45px;
}
.characteristic_field_value {
width: 935px;
font-size: 12px;
float:left;
}
.descriptors_section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.descriptors_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
height:33px;
line-height: 33px;
background-color: #6600CC;
width:1235px;
padding-left: 45px;
}
.descriptor_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.descriptor_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1230px;
padding-left: 50px;
height:33px;
line-height: 33px;
background-color: #BE81F7;
}
.descriptor_item {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #D8CEF6
}
.descriptor_label {
width: 300px;
font-size: 12px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
padding-left: 60px;
}
.descriptor_value {
width: 920px;
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
}
.char_fields_section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.char_fields_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
height:33px;
line-height: 33px;
background-color: #A4A4A4;
width:1235px;
padding-left: 45px;
}
.char_field_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.char_field_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1230px;
padding-left: 50px;
height:33px;
line-height: 33px;
background-color: #BE81F7;
}
.char_field_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1225px;
padding-left: 55px;
height:33px;
line-height: 33px;
background-color: #E6E6E6;
}
.char_field_item {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #FAFAFA
}
.char_field_label {
width: 300px;
font-size: 12px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
padding-left: 60px;
}
.char_field_value {
width: 920px;
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
}
.align_right
{
text-align: right;
}
.mandatory_property {
width: 935px;
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
font-weight:bold;
color:#ff0000;
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -0,0 +1,5 @@
function init() {
var d = new Date();
var n = d.toLocaleDateString();
document.getElementById("id_date").innerHTML = n;
}

467
docs/Report 3/style.css Normal file
View File

@ -0,0 +1,467 @@
html,body {
height: 100%;
}
* {
padding: 0;
margin: 0;
}
body {
background-color: #ffffff;
padding: 0px;
margin: 0px;
font-family: "lucida sans", verdana, arial, helvetica, sans-serif;
font-size: 75%;
}
p
{
padding-left:5px;
}
.centred_text {
text-align:center
}
/* 8 pixels included for border width 1 between panels */
.container {
background-color: #FFFFFF;
width: 1280px;
margin: 0 auto;
}
.main_heading {
width: 1280px;
line-height: 79px;
height: 79px;
float:left;
font-size: 18px;
font-weight:bold;
color:#000000;
}
.date {
width: 100px;
line-height: 79px;
height: 79px;
float:left;
}
.heading_title {
width: 980px;
line-height: 79px;
height: 79px;
float:left;
text-align:center;
}
.icon {
width: 200px;
line-height: 79px;
height: 79;
float:left;
}
.section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
/* setting line-height to equal the height property causes the text to be centred vertically */
.profile_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1280px;
height:33px;
line-height: 33px;
background-color: #4F81BD
}
.profile_item {
float:left;
width:1265px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
padding-left: 15px;
background-color: #66CCFF
}
.profile_label {
width: 300px;
font-size: 14px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
}
.profile_value {
font-size: 14px;
line-height: 33px;
height: 33px;
float:left;
}
.text_block {
font-size: 14px;
float:left;
padding-top: 5px;
padding-bottom: 5px;
}
.services_section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
padding-top: 15px
}
.services_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1280px;
height:33px;
line-height: 33px;
background-color: #21610B;
}
.service_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.service_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1270px;
padding-left: 10px;
height:33px;
line-height: 33px;
background-color: #339933
}
.service_item {
float:left;
width:1265px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
padding-left: 15px;
background-color: #00FFBF;
}
.service_label {
width: 300px;
font-size: 12px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
}
.service_value {
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
}
.characteristics_section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.characteristics_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
height:33px;
line-height: 33px;
background-color: #FF6633;
width:1265px;
padding-left: 15px;
}
.characteristic_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.characteristic_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1250px;
padding-left: 30px;
height:33px;
line-height: 33px;
background-color: #FFCC33
}
.characteristic_item {
float:left;
width:1280px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #F5F6CE
}
.characteristic_summary {
float:left;
width:1250px;
height:33px;
line-height: 33px;
padding-left: 30px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #F5F6CE
}
.characteristic_label {
width: 300px;
font-size: 12px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
padding-left: 45px;
}
.char_text_block {
font-size: 14px;
float:left;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 45px;
}
.characteristic_value {
width: 935px;
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
}
.characteristic_field {
float:left;
width:1280px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #F5F6CE;
padding-top: 10px;
}
.characteristic_field_label {
width: 300px;
font-size: 12px;
font-weight:bold;
min-height: 33px;
float:left;
padding-left: 45px;
}
.characteristic_field_value {
width: 935px;
font-size: 12px;
float:left;
}
.descriptors_section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.descriptors_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
height:33px;
line-height: 33px;
background-color: #6600CC;
width:1235px;
padding-left: 45px;
}
.descriptor_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.descriptor_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1230px;
padding-left: 50px;
height:33px;
line-height: 33px;
background-color: #BE81F7;
}
.descriptor_item {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #D8CEF6
}
.descriptor_label {
width: 300px;
font-size: 12px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
padding-left: 60px;
}
.descriptor_value {
width: 920px;
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
}
.char_fields_section_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.char_fields_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
height:33px;
line-height: 33px;
background-color: #A4A4A4;
width:1235px;
padding-left: 45px;
}
.char_field_hdg {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
}
.char_field_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1230px;
padding-left: 50px;
height:33px;
line-height: 33px;
background-color: #BE81F7;
}
.char_field_hdg_text {
font-size: 18px;
font-weight:bold;
color:#ffffff;
float:left;
width:1225px;
padding-left: 55px;
height:33px;
line-height: 33px;
background-color: #E6E6E6;
}
.char_field_item {
float:left;
width:1280px;
height:33px;
border-width: 1px;
border-style: solid;
border-color: #FFFFFF;
background-color: #FAFAFA
}
.char_field_label {
width: 300px;
font-size: 12px;
font-weight:bold;
line-height: 33px;
height: 33px;
float:left;
padding-left: 60px;
}
.char_field_value {
width: 920px;
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
}
.align_right
{
text-align: right;
}
.mandatory_property {
width: 935px;
font-size: 12px;
line-height: 33px;
height: 33px;
float:left;
font-weight:bold;
color:#ff0000;
}

View File

@ -0,0 +1,116 @@
micro:bit pairing and over the air firmware updates
---------------------------------------------------
Version: 1.0
Date : 17th September 2015
Authors: Joe Finney (j.finney@lancaster.ac.uk) and Martin Woolley (mwoolley@bluetooth.com)
Terminology
-----------
FOTA: Firmware Over The Air (Nordic's name)
DFU: Device Firmware Update (the process of using FOTA to reprogram a nordic chip)
A Tale of Two DFU GATT Services
-------------------------------
The micro:bit possesses two BLE GATT services that are concerned with FOTA. Only one, however should be "visible" to a GATT client at any one time.
The first is the standard Nordic DFU service which has not been modified. See https://devzone.nordicsemi.com/documentation/nrf51/4.4.1/html/group__dfu__ble__service__spec.html for further details.
The Nordic DFU service is *not* visible to clients most of the time and this is by design.
The second service is the MicroBit DFU Service. This service *is* active/visible in general.
Whilst the Nordic DFU service may not be visible to GATT clients most of the time, it is always resident in the top 20K or so of FLASH program memory.
Flashing the micro:bit OTA involves rebooting the micro:bit in a special way which results in the Nordic boot loader being entered and this brings up the Nordic DFU service instead of the MicroBit DFU service.
The MicroBit DFU Control Service
--------------------------------
This service has two characteristics:
ControlPoint (unsigned 32 bits)
FlashCode (unsigned 32 bits)
The FlashCode characteristic is a primitive used for authentication. Every micro:bit has a unique code (derived from its unique serial ID).
Rebooting into the Nordic Bootloader
------------------------------------
As described, to flash the device OTA we must first instruct the micro:bit to reboot into the Nordic boot loader to bring up the Nordic DFU service which will then process firmware OTA updates from the client.
To reboot the micro:bit into the Nordic bootloader, two things need to happen:
1) The FlashCode characteristic has to be written with the correct secret key
2) The ControlPoint characteristic has to be written with a value of 0x01
At this point the micro:bit should automatically reboot and bring up the Nordic DFU service.
Note that the user doesn't have to press the reboot button. Reboot takes place automatically.
Obtaining and Using the flash code
----------------------------------
To be able to initiate the reboot into the Nordic boot loader therefore, the client must be in possession of the flash code. This gives us two scenarios to consider and essentially gives us a two stage process of which stage 1 is optional.
Either (1) the client does not possess the flash code and therefore must somehow obtain it or (2) it already has it from some previous interaction with the micro:bit and has cached it.
Stage 1 - Client Does Not Possess flash code
------------------------------------------
MicroBit has a special mode of operation or state known currently as "Blue Zone". The device enters this state when rebooted by pressing the reset button whilst at the same time holding down both buttons A and B. The device indicates itself to be in the Blue Zone mode by scrolling "BLUEZONE" across the display.
Once in the Blue Zone state, the MicroBit DFU Service also enables another command via the ControlPoint characteristic known as 'REQUEST_FLASHCODE' which is represented by a value of 0x02.
To obtain the flash code the client should enable GATT notifications on the FlashCode characteristic and then write 0x02 to the Control characteristic. The micro:bit will respond by displaying "PAIR?" on the LED display.
The user must now press Button A on the micro:bit. This is an "authorization to proceed" step and results in the client receiving the flash code value as a GATT notification which it can then store for use in the second stage and any subsequent execution of stage 2 without the need to execute the stage 1 procedure.
Stage 2 - Client in Possession of flash code
-------------------------------------------
If a device already knows the flashcode, it can connect any time and initiate rebooting into "Nordic DFU mode" by writing the FlashCode characteristic with the previously cached value and then writing the 'ENTER NORDIC BOOTLOADER' command (0x01) to the Control characteristic. The device will reboot into the stock nordic bootloader and then the attached device can interact with that to reflash the device. The device does NOT need to be in Blue Zone mode.
Issues for Client Application Developers
----------------------------------------
It should be noted that rebooting into "Nordic DFU Mode" will break any existing BLE connection between the client device and micro:bit. The client will therefore need to re-establish its connection to the MicroBit before being able to proceed with FOTA and discover and then make use of the Nordic DFU service.
More About flash code
---------------------
Each micro:bit has a secret key (flash code) derived from a 128 bit serial number that's etched onto every nordic nrf51822 during manufacture. All chips are different. Half of the serial number is hashed to generate the flash code.
micro:bit human identifiers
---------------------------
In addition to a secret key (flash code) used in the FOTA process as described, micro:bits have a human readable identifier (public name) which is included in BLE advertising packets and can be discovered and used by human users during any process, including FOTA, where there needs to be a confirmation that the device which is to be interacted with is the one the human intends to interact with. In the context of this document, "interact with" means update using the FOTA procedure.
The public name is generated by the run time from the other half of the Nordic serial number. Humans can discover the public name of a device by switching into BLUEZONE mode. The public name is displayed in a coded but simple graphical form on the LED display and can then be entered into (say) a mobile application screen to verify the device to be updated is the one we mean to update.
Summary of the FOTA Process
---------------------------
Case 1 - Client does not know the flash code
--------------------------------------------
a) User switches micro:bit into BLUEZONE mode - must do this first since it involves a reboot and will therefore disconnect the client
b) Client connects to micro:bit
c) Client discovers MicroBit DFU service
d) Client enables notifications on the MicroBit DFU Service::FlashCode characteristic
e) Client writes 0x02 to the MicroBit DFU Service::Control characteristic
f) micro:bit displays "PAIR?" on the LED display
g) User presses Button A
h) Client should receive FlashCode notification containing the flash code value
We then proceed by following the steps for Case 2
Case 2 - Client is in Possession of flash code
----------------------------------------------
i) Client writes the cached flash code value to the MicroBit DFU Service::FlashCode characteristic
Note: this is optional if following directly on from Case 1 as the FlashCode characterisitic would have been written locally by the micro:bit runtime
j) Client writes 0x01 to the MicroBit DFU Service::Control characteristic. This should cause the micro:bit to reboot into the Nordic boot loader. The Nordic DFU GATT service should become active and visible to GATT clients that subsequently connect and the MicroBit DFU Service should disappear.
k) Client reconnects to micro:bit and proceeds with FOTA per the Nordic documentation on using their DFU service.
UUIDs
-----
MicroBit DFU Service : E95D93B0-251D-470A-A062-FA1922DFA9A8
Control Characteristic : E95D93B1-251D-470A-A062-FA1922DFA9A8
FlashCode Characteristic: E95D93B2-251D-470A-A062-FA1922DFA9A8
Nordic DFU Service : 00001530-1212-EFDE-1523-785FEABCD123

View File

@ -22,6 +22,7 @@
#include "MicroBitPin.h"
#include "MicroBitCompass.h"
#include "MicroBitAccelerometer.h"
#include "MicroBitThermometer.h"
#include "MicroBitMultiButton.h"
#include "MicroBitSerial.h"
@ -35,6 +36,12 @@
#include "ble/services/DeviceInformationService.h"
#include "MicroBitDFUService.h"
#include "MicroBitEventService.h"
#include "MicroBitLEDService.h"
#include "MicroBitAccelerometerService.h"
#include "MicroBitMagnetometerService.h"
#include "MicroBitButtonService.h"
#include "MicroBitIOPinService.h"
#include "MicroBitTemperatureService.h"
#include "ExternalEvents.h"
// MicroBit::flags values
@ -43,11 +50,15 @@
#define MICROBIT_FLAG_DISPLAY_RUNNING 0x00000004
#define MICROBIT_FLAG_COMPASS_RUNNING 0x00000008
// MicroBit naming constants
#define MICROBIT_NAME_LENGTH 5
#define MICROBIT_NAME_CODE_LETTERS 5
// Random number generator
#define NRF51822_RNG_ADDRESS 0x4000D000
// mBed pin assignments of core components.
// mbed pin assignments of core components.
#define MICROBIT_PIN_SDA P0_30
#define MICROBIT_PIN_SCL P0_0
@ -99,15 +110,14 @@ class MicroBit
MicroBitMultiButton buttonAB;
MicroBitAccelerometer accelerometer;
MicroBitCompass compass;
MicroBitThermometer thermometer;
//An object of available IO pins on the device
MicroBitIO io;
// Bluetooth related member variables.
BLEDevice *ble;
MicroBitDFUService *ble_firmware_update_service;
MicroBitEventService *ble_event_service;
BLEDevice *ble;
MicroBitDFUService *ble_firmware_update_service;
/**
* Constructor.
@ -142,6 +152,25 @@ class MicroBit
*/
void init();
/**
* Derives the friendly name for this device, autogenerated from our hardware Device ID.
*/
void deriveName();
/**
* Return the friendly name for this device.
*
* @return A string representing the friendly name of this device.
*/
ManagedString getName();
/**
* Return the serial number of this device.
*
* @return A string representing the serial number of this device.
*/
ManagedString getSerial();
/**
* Will reset the micro:bit when called.
*
@ -252,7 +281,6 @@ extern MicroBit uBit;
// Used to reset state and restart advertising ourselves.
//
void bleDisconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason);
extern char MICROBIT_BLE_DEVICE_NAME[];
// Entry point for application programs. Called after the super-main function
// has initialized the device and runtime environment.

View File

@ -33,6 +33,14 @@
*/
#define MMA8653_WHOAMI_VAL 0x5A
#define MMA8653_SAMPLE_RANGES 3
#define MMA8653_SAMPLE_RATES 8
/*
* Accelerometer events
*/
#define MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE 1
struct MMA8653Sample
{
int16_t x;
@ -40,6 +48,21 @@ struct MMA8653Sample
int16_t z;
};
struct MMA8653SampleRateConfig
{
uint32_t sample_period;
uint8_t ctrl_reg1;
};
struct MMA8653SampleRangeConfig
{
uint8_t sample_range;
uint8_t xyz_data_cfg;
};
extern const MMA8653SampleRangeConfig MMA8653SampleRange[];
extern const MMA8653SampleRateConfig MMA8653SampleRate[];
/**
* Class definition for MicroBit Accelerometer.
*
@ -53,8 +76,9 @@ class MicroBitAccelerometer : public MicroBitComponent
* Used to track asynchronous events in the event bus.
*/
//if you are adding status here - don't it's in MicroBitComponent!!!
uint16_t address; // I2C address of this accelerometer.
uint16_t samplePeriod; // The time between samples, in milliseconds.
uint8_t sampleRange; // The sample range of the accelerometer in g.
MMA8653Sample sample; // The last sample read.
DigitalIn int1; // Data ready interrupt.
@ -73,13 +97,48 @@ class MicroBitAccelerometer : public MicroBitComponent
*/
MicroBitAccelerometer(uint16_t id, uint16_t address);
/**
* Configures the accelerometer for G range and sample rate defined
* in this object. The nearest values are chosen to those defined
* that are supported by the hardware. The instance variables are then
* updated to reflect reality.
*/
void configure();
/**
* Reads the acceleration data from the accelerometer, and stores it in our buffer.
* This is called by the tick() member function, if the interrupt is set!
*/
void update();
/**
* Attempts to set the sample rate of the accelerometer to the specified value (in ms).
* n.b. the requested rate may not be possible on the hardware. In this case, the
* nearest lower rate is chosen.
* @param period the requested time between samples, in milliseconds.
*/
void setPeriod(int period);
/**
* Reads the currently configured sample rate of the accelerometer.
* @return The time between samples, in milliseconds.
*/
int getPeriod();
/**
* Attempts to set the sample range of the accelerometer to the specified value (in g).
* n.b. the requested range may not be possible on the hardware. In this case, the
* nearest lower rate is chosen.
* @param range The requested sample range of samples, in g.
*/
void setRange(int range);
/**
* Reads the currently configured sample range of the accelerometer.
* @return The sample range, in g.
*/
int getRange();
/**
* Attempts to determine the 8 bit ID from the accelerometer.
* @return the 8 bit ID returned by the accelerometer

View File

@ -0,0 +1,54 @@
#ifndef MICROBIT_ACCELEROMETER_SERVICE_H
#define MICROBIT_ACCELEROMETER_SERVICE_H
#include "MicroBit.h"
// UUIDs for our service and characteristics
extern const uint8_t MicroBitAccelerometerServiceUUID[];
extern const uint8_t MicroBitAccelerometerServiceDataUUID[];
extern const uint8_t MicroBitAccelerometerServicePeriodUUID[];
/**
* Class definition for a MicroBit BLE Accelerometer Service.
* Provides access to live accelerometer data via BLE, and provides basic configuration options.
*/
class MicroBitAccelerometerService
{
public:
/**
* Constructor.
* Create a representation of the AccelerometerService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitAccelerometerService(BLEDevice &_ble);
private:
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
void onDataWritten(const GattWriteCallbackParams *params);
/**
* Accelerometer update callback
*/
void accelerometerUpdate(MicroBitEvent e);
// Bluetooth stack we're running on.
BLEDevice &ble;
// memory for our 8 bit control characteristics.
uint16_t accelerometerDataCharacteristicBuffer[3];
uint16_t accelerometerPeriodCharacteristicBuffer;
// Handles to access each characteristic when they are held by Soft Device.
GattAttribute::Handle_t accelerometerDataCharacteristicHandle;
GattAttribute::Handle_t accelerometerPeriodCharacteristicHandle;
};
#endif

View File

@ -0,0 +1,54 @@
#ifndef MICROBIT_BUTTON_SERVICE_H
#define MICROBIT_BUTTON_SERVICE_H
#include "MicroBit.h"
// UUIDs for our service and characteristics
extern const uint8_t MicroBitButtonServiceUUID[];
extern const uint8_t MicroBitButtonAServiceDataUUID[];
extern const uint8_t MicroBitButtonBServiceDataUUID[];
/**
* Class definition for a MicroBit BLE Button Service.
* Provides access to live button data via BLE, and provides basic configuration options.
*/
class MicroBitButtonService
{
public:
/**
* Constructor.
* Create a representation of the ButtonService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitButtonService(BLEDevice &_ble);
private:
/**
* Button A update callback
*/
void buttonAUpdate(MicroBitEvent e);
/**
* Button B update callback
*/
void buttonBUpdate(MicroBitEvent e);
// Bluetooth stack we're running on.
BLEDevice &ble;
// memory for our 8 bit control characteristics.
uint8_t buttonADataCharacteristicBuffer;
uint8_t buttonBDataCharacteristicBuffer;
// Handles to access each characteristic when they are held by Soft Device.
GattAttribute::Handle_t buttonADataCharacteristicHandle;
GattAttribute::Handle_t buttonBDataCharacteristicHandle;
};
#endif

View File

@ -36,12 +36,27 @@
#define MAG_CTRL_REG1 0x10
#define MAG_CTRL_REG2 0x11
/**
* Configuration options
*/
struct MAG3110SampleRateConfig
{
uint32_t sample_period;
uint8_t ctrl_reg1;
};
extern const MAG3110SampleRateConfig MAG3110SampleRate[];
#define MAG3110_SAMPLE_RATES 11
/*
* Compass events
*/
#define MICROBIT_COMPASS_EVT_CAL_REQUIRED 1
#define MICROBIT_COMPASS_EVT_CAL_START 2
#define MICROBIT_COMPASS_EVT_CAL_END 3
#define MICROBIT_COMPASS_EVT_DATA_UPDATE 4
#define MICROBIT_COMPASS_EVT_CONFIG_NEEDED 5
/*
* Status Bits
@ -85,17 +100,17 @@ class MicroBitCompass : public MicroBitComponent
* Used to track asynchronous events in the event bus.
*/
uint16_t address; // I2C address of the magnetmometer.
uint16_t address; // I2C address of the magnetmometer.
uint16_t samplePeriod; // The time between samples, in millseconds.
unsigned long eventStartTime; // used to store the current system clock when async calibration has started
unsigned long eventStartTime; // used to store the current system clock when async calibration has started
public:
CompassSample minSample; // Calibration sample.
CompassSample maxSample; // Calibration sample.
CompassSample average; // Centre point of sample data.
CompassSample sample; // The latest sample data recorded.
DigitalIn int1; // Data ready interrupt.
public:
/**
* Constructor.
@ -116,7 +131,29 @@ class MicroBitCompass : public MicroBitComponent
* @endcode
*/
MicroBitCompass(uint16_t id, uint16_t address);
/**
* Configures the compass for the sample rate defined
* in this object. The nearest values are chosen to those defined
* that are supported by the hardware. The instance variables are then
* updated to reflect reality.
*/
void configure();
/**
* Attempts to set the sample rate of the compass to the specified value (in ms).
* n.b. the requested rate may not be possible on the hardware. In this case, the
* nearest lower rate is chosen.
* @param period the requested time between samples, in milliseconds.
*/
void setPeriod(int period);
/**
* Reads the currently configured sample rate of the compass.
* @return The time between samples, in milliseconds.
*/
int getPeriod();
/**
* Gets the current heading of the device, relative to magnetic north.
* @return the current heading, in degrees.
@ -172,6 +209,12 @@ class MicroBitCompass : public MicroBitComponent
*/
int getZ();
/**
* Reads the currently die temperature of the compass.
* @return The temperature, in degrees celsius.
*/
int readTemperature();
/**
* Perform the asynchronous calibration of the compass.
* This will fire MICROBIT_COMPASS_EVT_CAL_START and MICROBIT_COMPASS_EVT_CAL_END when finished.
@ -257,7 +300,7 @@ class MicroBitCompass : public MicroBitComponent
* @param reg The based address of the 16 bit register to access.
* @return The register value, interpreted as a 8 bi signed value.
*/
int16_t read8(uint8_t reg);
uint8_t read8(uint8_t reg);
};
#endif

View File

@ -16,6 +16,7 @@
#define MICROBIT_ID_ACCELEROMETER 4
#define MICROBIT_ID_COMPASS 5
#define MICROBIT_ID_DISPLAY 6
#define MICROBIT_ID_THERMOMETER 7
//EDGE connector events
#define MICROBIT_IO_PINS 20

View File

@ -152,6 +152,52 @@
#define MICROBIT_BLE_DEVICE_INFORMATION_SERVICE 1
#endif
// Enable/Disable BLE Service: MicroBitLEDService
// This enables the control and the LED matrix display via BLE.
// Set '1' to enable.
#ifndef MICROBIT_BLE_LED_SERVICE
#define MICROBIT_BLE_LED_SERVICE 0
#endif
// Enable/Disable BLE Service: MicroBitAccelerometerService
// This enables live access to the on board 3 axis accelerometer.
// Set '1' to enable.
#ifndef MICROBIT_BLE_ACCELEROMETER_SERVICE
#define MICROBIT_BLE_ACCELEROMETER_SERVICE 0
#endif
// Enable/Disable BLE Service: MicroBitMagnetometerService
// This enables live access to the on board 3 axis magnetometer.
// Set '1' to enable.
#ifndef MICROBIT_BLE_MAGNETOMETER_SERVICE
#define MICROBIT_BLE_MAGNETOMETER_SERVICE 0
#endif
// Enable/Disable BLE Service: MicroBitButtonService
// This enables live access to the two micro:bit buttons.
// Set '1' to enable.
#ifndef MICROBIT_BLE_BUTTON_SERVICE
#define MICROBIT_BLE_BUTTON_SERVICE 0
#endif
// This enables live access to the two micro:bit buttons.
// Set '1' to enable.
#ifndef MICROBIT_BLE_IO_PIN_SERVICE
#define MICROBIT_BLE_IO_PIN_SERVICE 0
#endif
// This enables live access to the die temperature sensors on the micro:bit.
// Set '1' to enable.
#ifndef MICROBIT_BLE_TEMPERATURE_SERVICE
#define MICROBIT_BLE_TEMPERATURE_SERVICE 0
#endif
// Defines the maximum length strong that can be written to the
// display over BLE.
#ifndef MICROBIT_BLE_MAXIMUM_SCROLLTEXT
#define MICROBIT_BLE_MAXIMUM_SCROLLTEXT 20
#endif
//
// Accelerometer options
//

View File

@ -47,14 +47,6 @@ class MicroBitDFUService
*/
MicroBitDFUService(BLEDevice &BLE);
/**
* Returns the friendly name for this device, autogenerated from our Device ID.
*
* @param name Pointer to a string where the data will be written.
* @return The number of bytes written.
*/
int getName(char *name);
/**
* Begin the pairing process. Typically called when device is powered up with buttons held down.
* Scroll a description on the display, then displays the device ID code as a histogram on the matrix display.
@ -68,9 +60,6 @@ class MicroBitDFUService
private:
// BLE pairing name of this device, encoded as an integer.
uint32_t flashCode;
// State of paiting process.
bool authenticated;
bool flashCodeRequested;
@ -78,9 +67,12 @@ class MicroBitDFUService
// Bluetooth stack we're running on.
BLEDevice &ble;
// memory for our 8 bit control characteristics.
// memory for our 8 bit control characteristic.
uint8_t controlByte;
// BLE pairing name of this device, encoded as an integer.
uint32_t flashCode;
GattAttribute::Handle_t microBitDFUServiceControlCharacteristicHandle;
GattAttribute::Handle_t microBitDFUServiceFlashCodeCharacteristicHandle;
@ -92,6 +84,10 @@ class MicroBitDFUService
// Update BLE characteristic to release our flash code.
void releaseFlashCode();
// Event handlers for button clicks.
void onButtonA(MicroBitEvent e);
void onButtonB(MicroBitEvent e);
};
#endif

View File

@ -7,6 +7,8 @@
extern const uint8_t MicroBitEventServiceUUID[];
extern const uint8_t MicroBitEventServiceMicroBitEventCharacteristicUUID[];
extern const uint8_t MicroBitEventServiceClientEventCharacteristicUUID[];
extern const uint8_t MicroBitEventServiceMicroBitRequirementsCharacteristicUUID[];
extern const uint8_t MicroBitEventServiceClientRequirementsCharacteristicUUID[];
struct EventServiceEvent
{
@ -19,7 +21,7 @@ struct EventServiceEvent
* Class definition for a MicroBit BLE Event Service.
* Provides a _ble gateway onto the MicroBit Message Bus.
*/
class MicroBitEventService
class MicroBitEventService : public MicroBitComponent
{
public:
@ -29,7 +31,13 @@ class MicroBitEventService
* @param BLE The instance of a BLE device that we're running on.
*/
MicroBitEventService(BLEDevice &_ble);
/**
* Periodic callback from MicroBit scheduler.
* If we're no longer connected, remove any registered Message Bus listeners.
*/
virtual void idleTick();
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
@ -40,17 +48,32 @@ class MicroBitEventService
*/
void onMicroBitEvent(MicroBitEvent evt);
/**
* read callback on microBitRequirements characteristic.
* Used to iterate through the events that the code on this micro:bit is interested in.
*/
void onRequirementsRead(GattReadAuthCallbackParams *params);
private:
// Bluetooth stack we're running on.
BLEDevice &ble;
// memory for our 8 bit control characteristics.
// memory for our event characteristics.
EventServiceEvent clientEventBuffer;
EventServiceEvent microBitEventBuffer;
EventServiceEvent microBitRequirementsBuffer;
EventServiceEvent clientRequirementsBuffer;
// handles on this service's characterisitics.
GattAttribute::Handle_t microBitEventCharacteristicHandle;
GattAttribute::Handle_t clientRequirementsCharacteristicHandle;
GattAttribute::Handle_t clientEventCharacteristicHandle;
GattCharacteristic *microBitRequirementsCharacteristic;
// Message bus offset last sent to the client...
uint16_t messageBusListenerOffset;
};

111
inc/MicroBitIOPinService.h Normal file
View File

@ -0,0 +1,111 @@
#ifndef MICROBIT_IO_PIN_SERVICE_H
#define MICROBIT_IO_PIN_SERVICE_H
#include "MicroBit.h"
#define MICROBIT_IO_PIN_SERVICE_PINCOUNT 20
#define MICROBIT_IO_PIN_SERVICE_DATA_SIZE 10
// UUIDs for our service and characteristics
extern const uint8_t MicroBitIOPinServiceUUID[];
extern const uint8_t MicroBitIOPinServiceADConfigurationUUID[];
extern const uint8_t MicroBitIOPinServiceIOConfigurationUUID[];
extern const uint8_t MicroBitIOPinServiceDataUUID[];
extern MicroBitPin * const MicroBitIOPins[];
/**
* Name value pair definition, as used to read abd write pin values over BLE.
*/
struct IOData
{
uint8_t pin;
uint8_t value;
};
/**
* Class definition for a MicroBit BLE IOPin Service.
* Provides access to live ioPin data via BLE, and provides basic configuration options.
*/
class MicroBitIOPinService : public MicroBitComponent
{
public:
/**
* Constructor.
* Create a representation of the IOPinService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitIOPinService(BLEDevice &_ble);
/**
* periodic callback from MicroBit scheduler.
* Check if any of the pins we're watching need updating. Apply a BLE NOTIFY if so...
*/
virtual void idleTick();
private:
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
void onDataWritten(const GattWriteCallbackParams *params);
/**
* Callback. invoked when the BLE data characteristic is read.
* reads all the pins marked as inputs, and updates the data stored in the BLE stack.
*/
void onDataRead(GattReadAuthCallbackParams *params);
/**
* Determines if the given pin was configured as a digital pin by the BLE ADPinConfigurationCharacterisitic.
*
* @param pin the enumeration of the pin to test
* @return 1 if this pin is configured as a digital value, 0 otherwise
*/
int isDigital(int i);
/**
* Determines if the given pin was configured as an analog pin by the BLE ADPinConfigurationCharacterisitic.
*
* @param pin the enumeration of the pin to test
* @return 1 if this pin is configured as a analog value, 0 otherwise
*/
int isAnalog(int i);
/**
* Determines if the given pin was configured as an input by the BLE IOPinConfigurationCharacterisitic.
*
* @param pin the enumeration of the pin to test
* @return 1 if this pin is configured as an input, 0 otherwise
*/
int isInput(int i);
/**
* Determines if the given pin was configured as output by the BLE IOPinConfigurationCharacterisitic.
*
* @param pin the enumeration of the pin to test
* @return 1 if this pin is configured as an output, 0 otherwise
*/
int isOutput(int i);
// Bluetooth stack we're running on.
BLEDevice &ble;
// memory for our 8 bit control characteristics.
uint32_t ioPinServiceADCharacteristicBuffer;
uint32_t ioPinServiceIOCharacteristicBuffer;
IOData ioPinServiceDataCharacteristicBuffer[MICROBIT_IO_PIN_SERVICE_DATA_SIZE];
// Historic information about our pin data data.
uint8_t ioPinServiceIOData[MICROBIT_IO_PIN_SERVICE_PINCOUNT];
// Handles to access each characteristic when they are held by Soft Device.
GattAttribute::Handle_t ioPinServiceADCharacteristicHandle;
GattAttribute::Handle_t ioPinServiceIOCharacteristicHandle;
GattCharacteristic *ioPinServiceDataCharacteristic;
};
#endif

59
inc/MicroBitLEDService.h Normal file
View File

@ -0,0 +1,59 @@
#ifndef MICROBIT_LED_SERVICE_H
#define MICROBIT_LED_SERVICE_H
#include "MicroBit.h"
// UUIDs for our service and characteristics
extern const uint8_t MicroBitLEDServiceUUID[];
extern const uint8_t MicroBitLEDServiceMatrixUUID[];
extern const uint8_t MicroBitLEDServiceTextUUID[];
extern const uint8_t MicroBitLEDServiceScrollingSpeedUUID[];
/**
* Class definition for a MicroBit BLE Event Service.
* Provides a _ble gateway onto the MicroBit Message Bus.
*/
class MicroBitLEDService
{
public:
/**
* Constructor.
* Create a representation of the LEDService
* @param BLE The instance of a BLE device that we're running on.
*/
MicroBitLEDService(BLEDevice &_ble);
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
void onDataWritten(const GattWriteCallbackParams *params);
/**
* Callback. Invoked when any of our attributes are read via BLE.
*/
void onDataRead(GattReadAuthCallbackParams *params);
private:
// Bluetooth stack we're running on.
BLEDevice &ble;
// memory for our 8 bit control characteristics.
uint8_t matrixCharacteristicBuffer[5];
uint16_t scrollingSpeedCharacteristicBuffer;
uint8_t textCharacteristicBuffer[MICROBIT_BLE_MAXIMUM_SCROLLTEXT];
// Handles to access each characteristic when they are held by Soft Device.
GattAttribute::Handle_t matrixCharacteristicHandle;
GattAttribute::Handle_t textCharacteristicHandle;
GattAttribute::Handle_t scrollingSpeedCharacteristicHandle;
// We hold a copy of the GattCharacteristic, as mbed's BLE API requires this to provide read callbacks (pity!).
GattCharacteristic matrixCharacteristic;
};
#endif

View File

@ -5,7 +5,7 @@
#include "MicroBitEvent.h"
#include "MemberFunctionCallback.h"
// MessageBusListener flags...
// MicroBitListener flags...
#define MESSAGE_BUS_LISTENER_PARAMETERISED 0x0001
#define MESSAGE_BUS_LISTENER_METHOD 0x0002
#define MESSAGE_BUS_LISTENER_BUSY 0x0004
@ -13,6 +13,9 @@
#define MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY 0x0010
#define MESSAGE_BUS_LISTENER_DROP_IF_BUSY 0x0020
#define MESSAGE_BUS_LISTENER_NONBLOCKING 0x0040
#define MESSAGE_BUS_LISTENER_URGENT 0x0080
#define MESSAGE_BUS_LISTENER_IMMEDIATE (MESSAGE_BUS_LISTENER_NONBLOCKING | MESSAGE_BUS_LISTENER_URGENT)
struct MicroBitListener
{

View File

@ -0,0 +1,63 @@
#ifndef MICROBIT_MAGNETOMETER_SERVICE_H
#define MICROBIT_MAGNETOMETER_SERVICE_H
#include "MicroBit.h"
// UUIDs for our service and characteristics
extern const uint8_t MicroBitMagnetometerServiceUUID[];
extern const uint8_t MicroBitMagnetometerServiceDataUUID[];
extern const uint8_t MicroBitMagnetometerServiceBearingUUID[];
extern const uint8_t MicroBitMagnetometerServicePeriodUUID[];
/**
* Class definition for a MicroBit BLE Magnetometer Service.
* Provides access to live magnetometer data via BLE, and provides basic configuration options.
*/
class MicroBitMagnetometerService
{
public:
/**
* Constructor.
* Create a representation of the MagnetometerService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitMagnetometerService(BLEDevice &_ble);
private:
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
void onDataWritten(const GattWriteCallbackParams *params);
/**
* Magnetometer update callback
*/
void magnetometerUpdate(MicroBitEvent e);
/**
* Sample Period Change Needed callback.
* Reconfiguring the magnetometer can to a REALLY long time (sometimes even seconds to complete)
* So we do this in the background when necessary, through this event handler.
*/
void samplePeriodUpdateNeeded(MicroBitEvent e);
// Bluetooth stack we're running on.
BLEDevice &ble;
// memory for our 8 bit control characteristics.
int16_t magnetometerDataCharacteristicBuffer[3];
uint16_t magnetometerBearingCharacteristicBuffer;
uint16_t magnetometerPeriodCharacteristicBuffer;
// Handles to access each characteristic when they are held by Soft Device.
GattAttribute::Handle_t magnetometerDataCharacteristicHandle;
GattAttribute::Handle_t magnetometerBearingCharacteristicHandle;
GattAttribute::Handle_t magnetometerPeriodCharacteristicHandle;
};
#endif

View File

@ -64,8 +64,10 @@ class MicroBitMessageBus : public MicroBitComponent
* or the constructors provided by MicroBitEvent.
*
* @param evt The event to send.
* @param mask The type of listeners to process (optional). Matches MicroBitListener flags. If not defined, all standard listeners will be processed.
* @return The 1 if all matching listeners were processed, 0 if further processing is required.
*/
void process(MicroBitEvent evt);
int process(MicroBitEvent &evt, uint32_t mask = MESSAGE_BUS_LISTENER_REENTRANT | MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY | MESSAGE_BUS_LISTENER_DROP_IF_BUSY | MESSAGE_BUS_LISTENER_NONBLOCKING);
/**
* Register a listener function.
@ -203,6 +205,13 @@ class MicroBitMessageBus : public MicroBitComponent
template <typename T>
void ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent));
/**
* Returns the microBitListener with the given position in our list.
* @param n The position in the list to return.
* @return the MicroBitListener at postion n in the list, or NULL if the position is invalid.
*/
MicroBitListener *elementAt(int n);
private:
/**

View File

@ -131,6 +131,30 @@ class MicroBitPin : public MicroBitComponent
*/
int getAnalogValue();
/**
* Determines if this IO pin is currently configured as an input.
* @return 1 if pin is an analog or digital input, 0 otherwise.
*/
int isInput();
/**
* Determines if this IO pin is currently configured as an output.
* @return 1 if pin is an analog or digital output, 0 otherwise.
*/
int isOutput();
/**
* Determines if this IO pin is currently configured for digital use.
* @return 1 if pin is digital, 0 otherwise.
*/
int isDigital();
/**
* Determines if this IO pin is currently configured for analog use.
* @return 1 if pin is analog, 0 otherwise.
*/
int isAnalog();
/**
* Configures this IO pin as a makey makey style touch sensor (if necessary) and tests its current debounced state.
* @return 1 if pin is touched, 0 otherwise.

View File

@ -0,0 +1,53 @@
#ifndef MICROBIT_TEMPERATURE_SERVICE_H
#define MICROBIT_TEMPERATURE_SERVICE_H
#include "MicroBit.h"
// UUIDs for our service and characteristics
extern const uint8_t MicroBitTemperatureServiceUUID[];
extern const uint8_t MicroBitTemperatureServiceDataUUID[];
extern const uint8_t MicroBitTemperatureServicePeriodUUID[];
/**
* Class definition for a MicroBit BLE Temperture Service.
* Provides access to live temperature data via BLE.
*/
class MicroBitTemperatureService
{
public:
/**
* Constructor.
* Create a representation of the TempertureService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitTemperatureService(BLEDevice &_ble);
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
void onDataWritten(const GattWriteCallbackParams *params);
/**
* Temperature update callback
*/
void temperatureUpdate(MicroBitEvent e);
private:
// Bluetooth stack we're running on.
BLEDevice &ble;
// memory for our 8 bit temperature characteristic.
int8_t temperatureDataCharacteristicBuffer;
uint16_t temperaturePeriodCharacteristicBuffer;
// Handles to access each characteristic when they are held by Soft Device.
GattAttribute::Handle_t temperatureDataCharacteristicHandle;
GattAttribute::Handle_t temperaturePeriodCharacteristicHandle;
};
#endif

102
inc/MicroBitThermometer.h Normal file
View File

@ -0,0 +1,102 @@
#ifndef MICROBIT_THERMOMETER_H
#define MICROBIT_THERMOMETER_H
#include "mbed.h"
#include "MicroBitComponent.h"
#define MICROBIT_THERMOMETER_PERIOD 1000
#define MAG3110_SAMPLE_RATES 11
/*
* Temperature events
*/
#define MICROBIT_THERMOMETER_EVT_UPDATE 1
/**
* Class definition for MicroBit Thermometer.
*
* Infers and stores the ambient temoperature based on the surface temperature
* of the various chips on the micro:bit.
*
*/
class MicroBitThermometer : public MicroBitComponent
{
unsigned long sampleTime;
uint32_t samplePeriod;
int16_t temperature;
public:
/**
* Constructor.
* Create new object that can sense temperature.
* @param id the ID of the new MicroBitThermometer object.
*
* Example:
* @code
* thermometer(MICROBIT_ID_THERMOMETER);
* @endcode
*
* Possible Events:
* @code
* MICROBIT_THERMOMETER_EVT_CHANGED
* @endcode
*/
MicroBitThermometer(uint16_t id);
/**
* Set the sample rate at which the temperatureis read (in ms).
* n.b. the temperature is alwasy read in the background, so wis only updated
* when the processor is idle, or when the temperature is explicitly read.
* The default sample period is 1 second.
* @param period the requested time between samples, in milliseconds.
*/
void setPeriod(int period);
/**
* Reads the currently configured sample rate of the thermometer.
* @return The time between samples, in milliseconds.
*/
int getPeriod();
/**
* Gets the current temperature of the microbit.
* @return the current temperature, in degrees celsius.
*
* Example:
* @code
* uBit.thermometer.getTemperature();
* @endcode
*/
int getTemperature();
/**
* Periodic callback from MicroBit idle thread.
* Check if any data is ready for reading by checking the interrupt.
*/
virtual void idleTick();
/**
* Indicates if we'd like some processor time to sense the temperature. 0 means we're not due to read the tmeperature yet.
* @returns 1 if we'd like some processor time, 0 otherwise.
*/
virtual int isIdleCallbackNeeded();
private:
/**
* Determines if we're due to take another temeoratur reading
* @return 1 if we're due to take a temperature reading, 0 otherwise.
*/
int isSampleNeeded();
/**
* Updates our recorded temeprature from the many sensors on the micro:bit!
*/
void updateTemperature();
};
#endif

View File

@ -1,6 +1,6 @@
{
"name": "microbit-dal",
"version": "1.2.2",
"version": "1.2.3",
"license": "Apache2",
"description": "The runtime library for the BBC micro:bit, developed by Lancaster University",
"keywords": [

View File

@ -1,76 +1,82 @@
# This file is no longer auto-generated to make the repository builds with GCC
# and ARMCC no matter what.
cmake_minimum_required(VERSION 2.8.11)
enable_language(ASM)
set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES
"MicroBitSuperMain.cpp"
"MicroBitI2C.cpp"
"MicroBitMultiButton.cpp"
"MicroBitFont.cpp"
"MicroBit.cpp"
"MicroBitButton.cpp"
"MicroBitMessageBus.cpp"
"MicroBitCompass.cpp"
"MicroBitEventService.cpp"
"MicroBitEvent.cpp"
"MicroBitFiber.cpp"
"ManagedString.cpp"
"MicroBitAccelerometer.cpp"
"MicroBitDFUService.cpp"
"MicroBitIO.cpp"
"MicroBitCompat.cpp"
"MicroBitImage.cpp"
"MicroBitDisplay.cpp"
"DynamicPwm.cpp"
"MicroBitPin.cpp"
"MicroBitSerial.cpp"
"MicroBitHeapAllocator.cpp"
"MicroBitListener.cpp"
"MemberFunctionCallback.cpp"
)
execute_process(WORKING_DIRECTORY "../../yotta_modules/${PROJECT_NAME}" COMMAND "git" "log" "--pretty=format:%h" "-n" "1" OUTPUT_VARIABLE git_hash)
execute_process(WORKING_DIRECTORY "../../yotta_modules/${PROJECT_NAME}" COMMAND "git" "rev-parse" "--abbrev-ref" "HEAD" OUTPUT_VARIABLE git_branch OUTPUT_STRIP_TRAILING_WHITESPACE)
if (${git_branch} STREQUAL "master")
set(MICROBIT_DAL_VERSION_STRING "${YOTTA_MICROBIT_DAL_VERSION_STRING}")
else()
set(MICROBIT_DAL_VERSION_STRING "${YOTTA_MICROBIT_DAL_VERSION_STRING}-${git_branch}-g${git_hash}")
endif()
set(MICROBIT_DAL_VERSION_FLAGS "-DMICROBIT_DAL_VERSION=\\\"${MICROBIT_DAL_VERSION_STRING}\\\"")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MICROBIT_DAL_VERSION_FLAGS}")
if (YOTTA_CFG_MICROBIT_CONFIGFILE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${YOTTA_FORCE_INCLUDE_FLAG} \"${YOTTA_CFG_MICROBIT_CONFIGFILE}\"")
endif ()
if(CMAKE_COMPILER_IS_GNUCC)
file(REMOVE "CortexContextSwitch.s")
configure_file("CortexContextSwitch.s.gcc" "CortexContextSwitch.s" COPYONLY)
else()
file(REMOVE "CortexContextSwitch.s")
configure_file("CortexContextSwitch.s.armcc" "CortexContextSwitch.s" COPYONLY)
endif()
set(YOTTA_AUTO_MICROBIT-DAL_S_FILES
"CortexContextSwitch.s"
)
add_library(microbit-dal
${YOTTA_AUTO_MICROBIT-DAL_CPP_FILES}
${YOTTA_AUTO_MICROBIT-DAL_S_FILES}
)
yotta_postprocess_target(LIBRARY microbit-dal)
target_link_libraries(microbit-dal
mbed-classic
ble
ble-nrf51822
)
# This file is no longer auto-generated to make the repository builds with GCC
# and ARMCC no matter what.
cmake_minimum_required(VERSION 2.8.11)
enable_language(ASM)
set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES
"MicroBitSuperMain.cpp"
"MicroBitI2C.cpp"
"MicroBitMultiButton.cpp"
"MicroBitFont.cpp"
"MicroBit.cpp"
"MicroBitButton.cpp"
"MicroBitMessageBus.cpp"
"MicroBitCompass.cpp"
"MicroBitEvent.cpp"
"MicroBitFiber.cpp"
"ManagedString.cpp"
"MicroBitAccelerometer.cpp"
"MicroBitThermometer.cpp"
"MicroBitIO.cpp"
"MicroBitCompat.cpp"
"MicroBitImage.cpp"
"MicroBitDisplay.cpp"
"DynamicPwm.cpp"
"MicroBitPin.cpp"
"MicroBitSerial.cpp"
"MicroBitHeapAllocator.cpp"
"MicroBitListener.cpp"
"MemberFunctionCallback.cpp"
"ble-services/MicroBitDFUService.cpp"
"ble-services/MicroBitEventService.cpp"
"ble-services/MicroBitLEDService.cpp"
"ble-services/MicroBitAccelerometerService.cpp"
"ble-services/MicroBitMagnetometerService.cpp"
"ble-services/MicroBitButtonService.cpp"
"ble-services/MicroBitIOPinService.cpp"
"ble-services/MicroBitTemperatureService.cpp"
)
execute_process(WORKING_DIRECTORY "../../yotta_modules/${PROJECT_NAME}" COMMAND "git" "log" "--pretty=format:%h" "-n" "1" OUTPUT_VARIABLE git_hash)
execute_process(WORKING_DIRECTORY "../../yotta_modules/${PROJECT_NAME}" COMMAND "git" "rev-parse" "--abbrev-ref" "HEAD" OUTPUT_VARIABLE git_branch OUTPUT_STRIP_TRAILING_WHITESPACE)
if (${git_branch} STREQUAL "master")
set(MICROBIT_DAL_VERSION_STRING "${YOTTA_MICROBIT_DAL_VERSION_STRING}")
else()
set(MICROBIT_DAL_VERSION_STRING "${YOTTA_MICROBIT_DAL_VERSION_STRING}-${git_branch}-g${git_hash}")
endif()
set(MICROBIT_DAL_VERSION_FLAGS "-DMICROBIT_DAL_VERSION=\\\"${MICROBIT_DAL_VERSION_STRING}\\\"")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MICROBIT_DAL_VERSION_FLAGS}")
if (YOTTA_CFG_MICROBIT_CONFIGFILE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${YOTTA_FORCE_INCLUDE_FLAG} \"${YOTTA_CFG_MICROBIT_CONFIGFILE}\"")
endif ()
if(CMAKE_COMPILER_IS_GNUCC)
file(REMOVE "asm/CortexContextSwitch.s")
configure_file("asm/CortexContextSwitch.s.gcc" "asm/CortexContextSwitch.s" COPYONLY)
else()
file(REMOVE "asm/CortexContextSwitch.s")
configure_file("asm/CortexContextSwitch.s.armcc" "asm/CortexContextSwitch.s" COPYONLY)
endif()
set(YOTTA_AUTO_MICROBIT-DAL_S_FILES
"asm/CortexContextSwitch.s"
)
add_library(microbit-dal
${YOTTA_AUTO_MICROBIT-DAL_CPP_FILES}
${YOTTA_AUTO_MICROBIT-DAL_S_FILES}
)
yotta_postprocess_target(LIBRARY microbit-dal)
target_link_libraries(microbit-dal
mbed-classic
ble
ble-nrf51822
)

View File

@ -1,14 +1,13 @@
#include "MicroBit.h"
char MICROBIT_BLE_DEVICE_NAME[] = "BBC MicroBit [xxxxx]";
char MICROBIT_BLE_DEVICE_NAME[] = "BBC micro:bit [xxxxx]";
#if CONFIG_ENABLED(MICROBIT_BLE_ENABLED) && CONFIG_ENABLED(MICROBIT_BLE_DEVICE_INFORMATION_SERVICE)
const char MICROBIT_BLE_MANUFACTURER[] = "The Cast of W1A";
const char MICROBIT_BLE_MODEL[] = "micro:bit";
const char MICROBIT_BLE_SERIAL[] = "SN1";
const char MICROBIT_BLE_HARDWARE_VERSION[] = "0.2";
const char MICROBIT_BLE_FIRMWARE_VERSION[] = MICROBIT_DAL_VERSION;
const char MICROBIT_BLE_SOFTWARE_VERSION[] = "1.0";
const char* MICROBIT_BLE_MANUFACTURER = "The Cast of W1A";
const char* MICROBIT_BLE_MODEL = "BBC micro:bit";
const char* MICROBIT_BLE_HARDWARE_VERSION = "1.0";
const char* MICROBIT_BLE_FIRMWARE_VERSION = MICROBIT_DAL_VERSION;
const char* MICROBIT_BLE_SOFTWARE_VERSION = NULL;
#endif
/**
@ -69,6 +68,7 @@ MicroBit::MicroBit() :
buttonAB(MICROBIT_ID_BUTTON_AB,MICROBIT_ID_BUTTON_A,MICROBIT_ID_BUTTON_B),
accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR),
compass(MICROBIT_ID_COMPASS, MAG3110_DEFAULT_ADDR),
thermometer(MICROBIT_ID_THERMOMETER),
io(MICROBIT_ID_IO_P0,MICROBIT_ID_IO_P1,MICROBIT_ID_IO_P2,
MICROBIT_ID_IO_P3,MICROBIT_ID_IO_P4,MICROBIT_ID_IO_P5,
MICROBIT_ID_IO_P6,MICROBIT_ID_IO_P7,MICROBIT_ID_IO_P8,
@ -103,35 +103,65 @@ void MicroBit::init()
// Seed our random number generator
seedRandom();
// Generate the name for our device.
this->deriveName();
#if CONFIG_ENABLED(MICROBIT_BLE_ENABLED)
// Start the BLE stack.
ble = new BLEDevice();
ble->init();
ble->onDisconnection(bleDisconnectionCallback);
// Bring up any configured auxiliary services.
#if CONFIG_ENABLED(MICROBIT_BLE_DFU_SERVICE)
ble_firmware_update_service = new MicroBitDFUService(*ble);
// Compute our auto-generated MicroBit device name.
ble_firmware_update_service->getName(MICROBIT_BLE_DEVICE_NAME+14);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_DEVICE_INFORMATION_SERVICE)
DeviceInformationService ble_device_information_service (*ble, MICROBIT_BLE_MANUFACTURER, MICROBIT_BLE_MODEL, MICROBIT_BLE_SERIAL, MICROBIT_BLE_HARDWARE_VERSION, MICROBIT_BLE_FIRMWARE_VERSION, MICROBIT_BLE_SOFTWARE_VERSION);
DeviceInformationService ble_device_information_service (*ble, MICROBIT_BLE_MANUFACTURER, MICROBIT_BLE_MODEL, getSerial().toCharArray(), MICROBIT_BLE_HARDWARE_VERSION, MICROBIT_BLE_FIRMWARE_VERSION, MICROBIT_BLE_SOFTWARE_VERSION);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_EVENT_SERVICE)
ble_event_service = new MicroBitEventService(*ble);
new MicroBitEventService(*ble);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_LED_SERVICE)
new MicroBitLEDService(*ble);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_ACCELEROMETER_SERVICE)
new MicroBitAccelerometerService(*ble);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_MAGNETOMETER_SERVICE)
new MicroBitMagnetometerService(*ble);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_BUTTON_SERVICE)
new MicroBitButtonService(*ble);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_IO_PIN_SERVICE)
new MicroBitIOPinService(*ble);
#endif
#if CONFIG_ENABLED(MICROBIT_BLE_TEMPERATURE_SERVICE)
new MicroBitTemperatureService(*ble);
#endif
// Configure for high speed mode where possible.
Gap::ConnectionParams_t fast;
ble->getPreferredConnectionParams(&fast);
fast.minConnectionInterval = 8; // 10 ms
fast.maxConnectionInterval = 16; // 20 ms
fast.slaveLatency = 0;
ble->setPreferredConnectionParams(&fast);
// Setup advertising.
ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)MICROBIT_BLE_DEVICE_NAME, sizeof(MICROBIT_BLE_DEVICE_NAME));
ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
ble->setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000));
ble->setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(200));
ble->startAdvertising();
#endif
@ -139,6 +169,69 @@ void MicroBit::init()
systemTicker.attach(this, &MicroBit::systemTick, MICROBIT_DISPLAY_REFRESH_PERIOD);
}
/**
* Derives the friendly name for this device, autogenerated from our hardware Device ID.
*/
void MicroBit::deriveName()
{
const uint8_t codebook[MICROBIT_NAME_LENGTH][MICROBIT_NAME_CODE_LETTERS] =
{
{'z', 'v', 'g', 'p', 't'},
{'u', 'o', 'i', 'e', 'a'},
{'z', 'v', 'g', 'p', 't'},
{'u', 'o', 'i', 'e', 'a'},
{'z', 'v', 'g', 'p', 't'}
};
char *name = MICROBIT_BLE_DEVICE_NAME+15;
// We count right to left, so fast forward the pointer.
name += MICROBIT_NAME_LENGTH;
uint32_t n = NRF_FICR->DEVICEID[1];
int ld = 1;
int d = MICROBIT_NAME_CODE_LETTERS;
int h;
for (int i=0; i<MICROBIT_NAME_LENGTH;i++)
{
h = (n % d) / ld;
n -= h;
d *= MICROBIT_NAME_CODE_LETTERS;
ld *= MICROBIT_NAME_CODE_LETTERS;
*--name = codebook[i][h];
}
}
/**
* Return the friendly name for this device.
*
* @return A string representing the friendly name of this device.
*/
ManagedString MicroBit::getName()
{
return ManagedString(MICROBIT_BLE_DEVICE_NAME+15, MICROBIT_NAME_LENGTH);
}
/**
* Return the serial number of this device.
*
* @return A string representing the serial number of this device.
*/
ManagedString MicroBit::getSerial()
{
// We take to 16 bit numbers here, as we want the full range of ID bits, but don't want negative numbers...
int n1 = NRF_FICR->DEVICEID[1] & 0xffff;
int n2 = (NRF_FICR->DEVICEID[1] >> 16) & 0xffff;
// Simply concat the two numbers.
ManagedString s1 = ManagedString(n1);
ManagedString s2 = ManagedString(n2);
return s1+s2;
}
/**
* Will reset the micro:bit when called.
*

View File

@ -7,6 +7,61 @@
#include "MicroBit.h"
/**
* Configures the accelerometer for G range and sample rate defined
* in this object. The nearest values are chosen to those defined
* that are supported by the hardware. The instance variables are then
* updated to reflect reality.
*/
void MicroBitAccelerometer::configure()
{
const MMA8653SampleRangeConfig *actualSampleRange;
const MMA8653SampleRateConfig *actualSampleRate;
// First find the nearest sample rate to that specified.
actualSampleRate = &MMA8653SampleRate[MMA8653_SAMPLE_RATES-1];
for (int i=MMA8653_SAMPLE_RATES-1; i>=0; i--)
{
if(MMA8653SampleRate[i].sample_period < this->samplePeriod * 1000)
break;
actualSampleRate = &MMA8653SampleRate[i];
}
// Now find the nearest sample range to that specified.
actualSampleRange = &MMA8653SampleRange[MMA8653_SAMPLE_RANGES-1];
for (int i=MMA8653_SAMPLE_RANGES-1; i>=0; i--)
{
if(MMA8653SampleRange[i].sample_range < this->sampleRange)
break;
actualSampleRange = &MMA8653SampleRange[i];
}
// OK, we have the correct data. Update our local state.
this->samplePeriod = actualSampleRate->sample_period / 1000;
this->sampleRange = actualSampleRange->sample_range;
// Now configure the accelerometer accordingly.
// First place the device into standby mode, so it can be configured.
writeCommand(MMA8653_CTRL_REG1, 0x00);
// Enable high precisiosn mode. This consumes a bit more power, but still only 184 uA!
writeCommand(MMA8653_CTRL_REG2, 0x10);
// Enable the INT1 interrupt pin.
writeCommand(MMA8653_CTRL_REG4, 0x01);
// Select the DATA_READY event source to be routed to INT1
writeCommand(MMA8653_CTRL_REG5, 0x01);
// Configure for the selected g range.
writeCommand(MMA8653_XYZ_DATA_CFG, actualSampleRange->xyz_data_cfg);
// Bring the device back online, with 10bit wide samples at the requested frequency.
writeCommand(MMA8653_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
}
/**
* Issues a standard, 2 byte I2C command write to the accelerometer.
* Blocks the calling thread until complete.
@ -54,21 +109,12 @@ MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address) : sa
this->id = id;
this->address = address;
// Enable the accelerometer.
// First place the device into standby mode, so it can be configured.
writeCommand(MMA8653_CTRL_REG1, 0x00);
// Enable the INT1 interrupt pin.
writeCommand(MMA8653_CTRL_REG4, 0x01);
// Update our internal state for 50Hz at +/- 2g (50Hz has a period af 20ms).
this->samplePeriod = 20;
this->sampleRange = 2;
// Select the DATA_READY event source to be routed to INT1
writeCommand(MMA8653_CTRL_REG5, 0x01);
// Configure for a +/- 2g range.
writeCommand(MMA8653_XYZ_DATA_CFG, 0x00);
// Bring the device back online, with 10bit wide samples at a 50Hz frequency.
writeCommand(MMA8653_CTRL_REG1, 0x21);
// Configure and enable the accelerometer.
this->configure();
// indicate that we're ready to receive tick callbacks.
uBit.flags |= MICROBIT_FLAG_ACCELEROMETER_RUNNING;
@ -105,19 +151,16 @@ void MicroBitAccelerometer::update()
sample.x = data[0];
sample.y = data[2];
sample.z = data[4];
// Scale into millig (approx!)
sample.x *= 16;
sample.y *= 16;
sample.z *= 16;
// Normalize the data in the 0..1024 range.
sample.x *= 8;
sample.y *= 8;
sample.z *= 8;
// Invert the x and y axes, so that the reference frame aligns with micro:bit expectations
sample.x = -sample.x;
sample.y = -sample.y;
// We ignore the LSB bits for now, as they're just noise...
// TODO: Revist this when we have working samples to see if additional resolution is needed.
#if CONFIG_ENABLED(USE_ACCEL_LSB)
// Add in LSB values.
sample.x += (data[1] / 64);
@ -125,9 +168,57 @@ void MicroBitAccelerometer::update()
sample.z += (data[5] / 64);
#endif
//TODO: Issue an event.
// Scale into millig (approx!)
sample.x *= this->sampleRange;
sample.y *= this->sampleRange;
sample.z *= this->sampleRange;
// Indicate that a new sample is available
MicroBitEvent e(id, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE);
};
/**
* Attempts to set the sample rate of the accelerometer to the specified value (in ms).
* n.b. the requested rate may not be possible on the hardware. In this case, the
* nearest lower rate is chosen.
* @param period the requested time between samples, in milliseconds.
*/
void MicroBitAccelerometer::setPeriod(int period)
{
this->samplePeriod = period;
this->configure();
}
/**
* Reads the currently configured sample rate of the accelerometer.
* @return The time between samples, in milliseconds.
*/
int MicroBitAccelerometer::getPeriod()
{
return (int)samplePeriod;
}
/**
* Attempts to set the sample range of the accelerometer to the specified value (in g).
* n.b. the requested range may not be possible on the hardware. In this case, the
* nearest lower rate is chosen.
* @param range The requested sample range of samples, in g.
*/
void MicroBitAccelerometer::setRange(int range)
{
this->sampleRange = range;
this->configure();
}
/**
* Reads the currently configured sample range of the accelerometer.
* @return The sample range, in g.
*/
int MicroBitAccelerometer::getRange()
{
return (int)sampleRange;
}
/**
* Reads the X axis value of the latest update from the accelerometer.
* Currently limited to +/- 2g
@ -172,7 +263,7 @@ int MicroBitAccelerometer::getZ()
{
return sample.z;
}
/**
* periodic callback from MicroBit clock.
@ -182,6 +273,7 @@ void MicroBitAccelerometer::idleTick()
{
// Poll interrupt line from accelerometer.
// n.b. Default is Active LO. Interrupt is cleared in data read.
//
if(!int1)
update();
}
@ -193,3 +285,20 @@ int MicroBitAccelerometer::isIdleCallbackNeeded()
{
return !int1;
}
const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = {
{2, 0},
{4, 1},
{8, 2}
};
const MMA8653SampleRateConfig MMA8653SampleRate[MMA8653_SAMPLE_RATES] = {
{1250, 0x00},
{2500, 0x08},
{5000, 0x10},
{10000, 0x18},
{20000, 0x20},
{80000, 0x28},
{160000, 0x30},
{640000, 0x38}
};

View File

@ -23,23 +23,21 @@ MicroBitCompass::MicroBitCompass(uint16_t id, uint16_t address) : average(), sam
this->id = id;
this->address = address;
//we presume it's calibrated until the average values are read.
//we presume the device calibrated until the average values are read.
this->status = 0x01;
//initialise eventStartTime to 0
this->eventStartTime = 0;
// Enable automatic reset after each sample;
writeCommand(MAG_CTRL_REG2, 0xA0);
// Select 10Hz update rate, with oversampling. Also enables the device.
writeCommand(MAG_CTRL_REG1, 0x61);
// Select 10Hz update rate, with oversampling, and enable the device.
this->samplePeriod = 100;
this->configure();
//fetch our previous average values
average.x = read16(MAG_OFF_X_MSB);
average.y = read16(MAG_OFF_Y_MSB);
average.z = read16(MAG_OFF_Z_MSB);
if(average.x == 0 && average.y == 0 && average.z == 0)
status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED;
@ -106,9 +104,9 @@ int16_t MicroBitCompass::read16(uint8_t reg)
* @param reg The based address of the 16 bit register to access.
* @return The register value, interpreted as a 8 bi signed value.
*/
int16_t MicroBitCompass::read8(uint8_t reg)
uint8_t MicroBitCompass::read8(uint8_t reg)
{
int8_t data;
uint8_t data;
data = 0;
readCommand(reg, (uint8_t*) &data, 1);
@ -131,6 +129,7 @@ int MicroBitCompass::heading()
{
if(status & MICROBIT_COMPASS_STATUS_CALIBRATING)
return MICROBIT_COMPASS_IS_CALIBRATING;
else if(!(status & MICROBIT_COMPASS_STATUS_CALIBRATED))
{
MicroBitEvent(id, MICROBIT_COMPASS_EVT_CAL_REQUIRED);
@ -174,8 +173,14 @@ void MicroBitCompass::idleTick()
eventStartTime = 0;
calibrateEnd();
}
}
else
{
// Indicate that a new sample is available
MicroBitEvent e(id, MICROBIT_COMPASS_EVT_DATA_UPDATE);
}
}
}
/**
@ -220,6 +225,65 @@ int MicroBitCompass::getZ()
return sample.z;
}
/**
* Configures the compass for the sample rate defined
* in this object. The nearest values are chosen to those defined
* that are supported by the hardware. The instance variables are then
* updated to reflect reality.
*/
void MicroBitCompass::configure()
{
const MAG3110SampleRateConfig *actualSampleRate;
// First, take the device offline, so it can be configured.
writeCommand(MAG_CTRL_REG1, 0x00);
// Wait for the part to enter standby mode...
while(this->read8(MAG_SYSMOD) & 0x03)
uBit.sleep(100);
// Find the nearest sample rate to that specified.
actualSampleRate = &MAG3110SampleRate[MAG3110_SAMPLE_RATES-1];
for (int i=MAG3110_SAMPLE_RATES-1; i>=0; i--)
{
if(MAG3110SampleRate[i].sample_period < this->samplePeriod * 1000)
break;
actualSampleRate = &MAG3110SampleRate[i];
}
// OK, we have the correct data. Update our local state.
this->samplePeriod = actualSampleRate->sample_period / 1000;
// Enable automatic reset after each sample;
writeCommand(MAG_CTRL_REG2, 0xA0);
// Bring the device online, with the requested sample frequency.
writeCommand(MAG_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
}
/**
* Attempts to set the sample rate of the compass to the specified value (in ms).
* n.b. the requested rate may not be possible on the hardware. In this case, the
* nearest lower rate is chosen.
* @param period the requested time between samples, in milliseconds.
*/
void MicroBitCompass::setPeriod(int period)
{
this->samplePeriod = period;
this->configure();
}
/**
* Reads the currently configured sample rate of the compass.
* @return The time between samples, in milliseconds.
*/
int MicroBitCompass::getPeriod()
{
return (int)samplePeriod;
}
/**
* Attempts to determine the 8 bit ID from the magnetometer.
* @return the id of the compass (magnetometer)
@ -237,6 +301,18 @@ int MicroBitCompass::whoAmI()
return (int)data;
}
/**
* Reads the currently die temperature of the compass.
* @return The temperature, in degrees celsius.
*/
int MicroBitCompass::readTemperature()
{
int8_t temperature;
readCommand(MAG_DIE_TEMP, (uint8_t *)&temperature, 1);
return temperature;
}
/**
* Perform a calibration of the compass.
* This will fire MICROBIT_COMPASS_EVT_CAL_START.
@ -281,7 +357,7 @@ void MicroBitCompass::calibrateEnd()
status &= ~MICROBIT_COMPASS_STATUS_CALIBRATING;
status |= MICROBIT_COMPASS_STATUS_CALIBRATED;
//Store x, y and z values in persistent storage on the MAG3110
writeCommand(MAG_OFF_X_LSB, (uint8_t)average.x);
writeCommand(MAG_OFF_X_MSB, (uint8_t)(average.x >> 8));
@ -333,6 +409,21 @@ void MicroBitCompass::clearCalibration()
*/
int MicroBitCompass::isIdleCallbackNeeded()
{
//Active HI
// The MAG3110 raises an interrupt line when data is ready, which we sample here.
// The interrupt line is active HI, so simply return the state of the pin.
return int1;
}
const MAG3110SampleRateConfig MAG3110SampleRate[MAG3110_SAMPLE_RATES] = {
{12500, 0x00}, // 80 Hz
{25000, 0x20}, // 40 Hz
{50000, 0x40}, // 20 Hz
{100000, 0x60}, // 10 hz
{200000, 0x80}, // 5 hz
{400000, 0x88}, // 2.5 hz
{800000, 0x90}, // 1.25 hz
{1600000, 0xb0}, // 0.63 hz
{3200000, 0xd0}, // 0.31 hz
{6400000, 0xf0}, // 0.16 hz
{12800000, 0xf8} // 0.08 hz
};

View File

@ -1,88 +0,0 @@
/**
* Class definition for a MicroBit BLE Event Service.
* Provides a BLE gateway onto the MicroBit Message Bus.
*/
#include "MicroBit.h"
#include "ble/UUID.h"
#include "ExternalEvents.h"
/**
* Constructor.
* Create a representation of the EventService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitEventService::MicroBitEventService(BLEDevice &_ble) :
ble(_ble)
{
GattCharacteristic microBitEventCharacteristic(MicroBitEventServiceMicroBitEventCharacteristicUUID, (uint8_t *)&microBitEventBuffer, 0, sizeof(EventServiceEvent),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic clientEventCharacteristic(MicroBitEventServiceClientEventCharacteristicUUID, (uint8_t *)&clientEventBuffer, 0, sizeof(EventServiceEvent),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
clientEventBuffer.type = 0x00;
clientEventBuffer.reason = 0x00;
microBitEventBuffer.type = 0x00;
microBitEventBuffer.reason = 0x00;
GattCharacteristic *characteristics[] = {&microBitEventCharacteristic, &clientEventCharacteristic};
GattService service(MicroBitEventServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
ble.addService(service);
microBitEventCharacteristicHandle = microBitEventCharacteristic.getValueHandle();
clientEventCharacteristicHandle = clientEventCharacteristic.getValueHandle();
ble.onDataWritten(this, &MicroBitEventService::onDataWritten);
}
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
void MicroBitEventService::onDataWritten(const GattWriteCallbackParams *params)
{
int len = params->len;
EventServiceEvent *e = (EventServiceEvent *)params->data;
if (params->handle == clientEventCharacteristicHandle) {
// Read and fire all events...
while (len >= 4)
{
MicroBitEvent evt(e->type, e->reason);
len-=4;
e++;
}
}
}
/**
* Callback. Invoked when any events are sent on the microBit message bus.
*/
void MicroBitEventService::onMicroBitEvent(MicroBitEvent evt)
{
EventServiceEvent *e = &microBitEventBuffer;
if (ble.getGapState().connected) {
e->type = evt.source;
e->reason = evt.value;
ble.updateCharacteristicValue(microBitEventCharacteristicHandle, (const uint8_t *)e, sizeof(EventServiceEvent));
}
}
const uint8_t MicroBitEventServiceUUID[] = {
0xe9,0x5d,0x93,0xaf,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitEventServiceMicroBitEventCharacteristicUUID[] = {
0xe9,0x5d,0x97,0x75,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitEventServiceClientEventCharacteristicUUID[] = {
0xe9,0x5d,0x54,0x04,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};

View File

@ -162,7 +162,7 @@ void scheduler_init()
idleFiber = getFiberContext();
idleFiber->tcb.SP = CORTEX_M0_STACK_BASE - 0x04;
idleFiber->tcb.LR = (uint32_t) &idle_task;
// Flag that we now have a scheduler running
uBit.flags |= MICROBIT_FLAG_SCHEDULER_RUNNING;
}
@ -234,6 +234,9 @@ void scheduler_event(MicroBitEvent evt)
f = t;
}
// Unregister this event, as we've woken up all the fibers with this match.
uBit.MessageBus.ignore(evt.source, evt.value, scheduler_event);
}
@ -316,6 +319,9 @@ void fiber_wait_for_event(uint16_t id, uint16_t value)
// Add ourselves to the sleep queue. We maintain strict ordering here to reduce lookup times.
queue_fiber(f, &waitQueue);
// Register to receive this event, so we can wake up the fiber when it happens.
uBit.MessageBus.listen(id, value, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE);
// Finally, enter the scheduler.
schedule();
}

View File

@ -125,10 +125,7 @@ void microbit_initialise_heap(HeapDefinition &heap)
int
microbit_create_sd_heap(HeapDefinition &heap)
{
#if CONFIG_DISABLED(MICROBIT_HEAP_REUSE_SD)
// We're not configure to use memory of this sort.
return 0;
#endif
#if CONFIG_ENABLED(MICROBIT_HEAP_REUSE_SD)
// OK, see how much of the RAM assigned to Soft Device we can reclaim.
#if CONFIG_ENABLED(MICROBIT_BLE_ENABLED)
@ -141,6 +138,9 @@ microbit_create_sd_heap(HeapDefinition &heap)
microbit_initialise_heap(heap);
return 1;
#else
return 0;
#endif
}
int

View File

@ -95,16 +95,25 @@ void async_callback(void *param)
*/
void MicroBitMessageBus::queueEvent(MicroBitEvent &evt)
{
MicroBitEventQueueItem *item = new MicroBitEventQueueItem(evt);
int processingComplete;
__disable_irq();
if (evt_queue_tail == NULL)
evt_queue_head = evt_queue_tail = item;
else
evt_queue_tail->next = item;
// Firstly, process all handler regsitered as URGENT. These pre-empt the queue, and are useful for fast, high priority services.
processingComplete = this->process(evt, MESSAGE_BUS_LISTENER_URGENT);
__enable_irq();
if (!processingComplete)
{
// We need to queue this event for later processing...
MicroBitEventQueueItem *item = new MicroBitEventQueueItem(evt);
__disable_irq();
if (evt_queue_tail == NULL)
evt_queue_head = evt_queue_tail = item;
else
evt_queue_tail->next = item;
__enable_irq();
}
}
/**
@ -145,7 +154,7 @@ void MicroBitMessageBus::idleTick()
// Whilst there are events to process and we have no useful other work to do, pull them off the queue and process them.
while (item)
{
// send the event.
// send the event to all standard event listeners.
this->process(item->evt);
// Free the queue item.
@ -203,43 +212,43 @@ void MicroBitMessageBus::send(MicroBitEvent evt)
* This will attempt to call the event handler directly, but spawn a fiber should that
* event handler attempt a blocking operation.
* @param evt The event to be delivered.
* @param mask The type of listeners to process (optional). Matches MicroBitListener flags. If not defined, all standard listeners will be processed.
* @return The 1 if all matching listeners were processed, 0 if further processing is required.
*/
void MicroBitMessageBus::process(MicroBitEvent evt)
int MicroBitMessageBus::process(MicroBitEvent &evt, uint32_t mask)
{
MicroBitListener *l;
int complete = 1;
l = listeners;
while (l != NULL)
{
if((l->id == evt.source || l->id == MICROBIT_ID_ANY) && (l->value == evt.value || l->value == MICROBIT_EVT_ANY))
{
l->evt = evt;
if(l->flags & mask)
{
l->evt = evt;
// OK, if this handler has regisitered itself as non-blocking, we just execute it directly...
// This is normally only done for trusted system components.
// Otherwise, we invoke it in a 'fork on block' context, that will automatically create a fiber
// should the event handler attempt a blocking operation, but doesn't have the overhead
// of creating a fiber needlessly. (cool huh?)
if (l->flags & MESSAGE_BUS_LISTENER_NONBLOCKING || currentFiber->flags & MICROBIT_FIBER_FLAG_DO_NOT_PAGE)
async_callback(l);
// OK, if this handler has regisitered itself as non-blocking, we just execute it directly...
// This is normally only done for trusted system components.
// Otherwise, we invoke it in a 'fork on block' context, that will automatically create a fiber
// should the event handler attempt a blocking operation, but doesn't have the overhead
// of creating a fiber needlessly. (cool huh?)
if (l->flags & MESSAGE_BUS_LISTENER_NONBLOCKING)
async_callback(l);
else
invoke(async_callback, l);
}
else
invoke(async_callback, l);
{
complete = 0;
}
}
l = l->next;
}
// Finally, forward the event to any other internal subsystems that may be interested.
// We *could* do this through the message bus of course, but this saves additional RAM,
// and procssor time (as we know these are non-blocking calls).
// Wake up any fibers that are blocked on this event
if (uBit.flags & MICROBIT_FLAG_SCHEDULER_RUNNING)
scheduler_event(evt);
// See if this event needs to be propogated through our BLE interface
if (uBit.ble_event_service)
uBit.ble_event_service->onMicroBitEvent(evt);
return complete;
}
/**
@ -357,7 +366,6 @@ int MicroBitMessageBus::add(MicroBitListener *newListener)
if (newListener == NULL)
return 0;
l = listeners;
// Firstly, we treat a listener as an idempotent operation. Ensure we don't already have this handler
@ -442,25 +450,28 @@ int MicroBitMessageBus::remove(MicroBitListener *listener)
// Walk this list of event handlers. Delete any that match the given listener.
while (l != NULL)
{
if (l->id == listener->id && l->value == listener->value && ((listener->flags & MESSAGE_BUS_LISTENER_METHOD) == (l->flags & MESSAGE_BUS_LISTENER_METHOD)))
if ((listener->flags & MESSAGE_BUS_LISTENER_METHOD) == (l->flags & MESSAGE_BUS_LISTENER_METHOD))
{
if(((listener->flags & MESSAGE_BUS_LISTENER_METHOD) && (*l->cb_method == *listener->cb_method)) ||
((!(listener->flags & MESSAGE_BUS_LISTENER_METHOD) && l->cb == listener->cb)))
((!(listener->flags & MESSAGE_BUS_LISTENER_METHOD) && l->cb == listener->cb)))
{
// Found a match. Remove from the list.
if (p == NULL)
listeners = l->next;
else
p->next = l->next;
if ((listener->id == MICROBIT_ID_ANY || listener->id == l->id) && (listener->value == MICROBIT_EVT_ANY || listener->value == l->value))
{
// Found a match. Remove from the list.
if (p == NULL)
listeners = l->next;
else
p->next = l->next;
// delete the listener.
MicroBitListener *t = l;
l = l->next;
// delete the listener.
MicroBitListener *t = l;
l = l->next;
delete t;
removed++;
delete t;
removed++;
continue;
continue;
}
}
}
@ -471,3 +482,24 @@ int MicroBitMessageBus::remove(MicroBitListener *listener)
return removed;
}
/**
* Returns the microBitListener with the given position in our list.
* @param n The position in the list to return.
* @return the MicroBitListener at postion n in the list, or NULL if the position is invalid.
*/
MicroBitListener* MicroBitMessageBus::elementAt(int n)
{
MicroBitListener *l = listeners;
while (n > 0)
{
if (l == NULL)
return NULL;
n--;
l = l->next;
}
return l;
}

View File

@ -35,8 +35,8 @@ MicroBitMultiButton::MicroBitMultiButton(uint16_t id, uint16_t button1, uint16_t
this->button1 = button1;
this->button2 = button2;
uBit.MessageBus.listen(button1, MICROBIT_EVT_ANY, onMultiButtonEvent);
uBit.MessageBus.listen(button2, MICROBIT_EVT_ANY, onMultiButtonEvent);
uBit.MessageBus.listen(button1, MICROBIT_EVT_ANY, onMultiButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
uBit.MessageBus.listen(button2, MICROBIT_EVT_ANY, onMultiButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
}
uint16_t MicroBitMultiButton::otherSubButton(uint16_t b)

View File

@ -171,6 +171,42 @@ int MicroBitPin::getAnalogValue()
return ((AnalogIn *)pin)->read_u16();
}
/**
* Determines if this IO pin is currently configured as an input.
* @return 1 if pin is an analog or digital input, 0 otherwise.
*/
int MicroBitPin::isInput()
{
return (status & (IO_STATUS_DIGITAL_IN | IO_STATUS_ANALOG_IN)) == 0 ? 0 : 1;
}
/**
* Determines if this IO pin is currently configured as an output.
* @return 1 if pin is an analog or digital output, 0 otherwise.
*/
int MicroBitPin::isOutput()
{
return (status & (IO_STATUS_DIGITAL_OUT | IO_STATUS_ANALOG_OUT)) == 0 ? 0 : 1;
}
/**
* Determines if this IO pin is currently configured for digital use.
* @return 1 if pin is digital, 0 otherwise.
*/
int MicroBitPin::isDigital()
{
return (status & (IO_STATUS_DIGITAL_IN | IO_STATUS_DIGITAL_OUT)) == 0 ? 0 : 1;
}
/**
* Determines if this IO pin is currently configured for analog use.
* @return 1 if pin is analog, 0 otherwise.
*/
int MicroBitPin::isAnalog()
{
return (status & (IO_STATUS_ANALOG_IN | IO_STATUS_ANALOG_OUT)) == 0 ? 0 : 1;
}
/**
* Configures this IO pin as a makey makey style touch sensor (if necessary) and tests its current debounced state.
* @return 1 if pin is touched, 0 otherwise.

View File

@ -7,6 +7,8 @@ Serial pc(USBTX, USBRX);
MicroBit uBit;
InterruptIn resetButton(MICROBIT_PIN_BUTTON_RESET);
extern char* MICROBIT_BLE_DEVICE_NAME;
int main()
{
// Bring up soft reset button.
@ -61,10 +63,7 @@ int main()
}
if (!uBit.ble_firmware_update_service)
{
uBit.ble_firmware_update_service = new MicroBitDFUService(*uBit.ble);
uBit.ble_firmware_update_service->getName(MICROBIT_BLE_DEVICE_NAME+14);
}
// Ensure we're advertising.
uBit.ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);

View File

@ -0,0 +1,136 @@
#include "MicroBit.h"
#include "nrf_soc.h"
/**
* Constructor.
* Create new object that can sense temperature.
* @param id the ID of the new MicroBitThermometer object.
*
* Example:
* @code
* thermometer(MICROBIT_ID_THERMOMETER);
* @endcode
*
* Possible Events:
* @code
* MICROBIT_THERMOMETER_EVT_CHANGED
* @endcode
*/
MicroBitThermometer::MicroBitThermometer(uint16_t id)
{
this->id = id;
this->samplePeriod = MICROBIT_THERMOMETER_PERIOD;
this->sampleTime = 0;
uBit.addIdleComponent(this);
}
/**
* Gets the current temperature of the microbit.
* @return the current temperature, in degrees celsius.
*
* Example:
* @code
* uBit.thermometer.getTemperature();
* @endcode
*/
int MicroBitThermometer::getTemperature()
{
if (isSampleNeeded())
updateTemperature();
return temperature;
}
/**
* Indicates if we'd like some processor time to sense the temperature. 0 means we're not due to read the tmeperature yet.
* @returns 1 if we'd like some processor time, 0 otherwise.
*/
int MicroBitThermometer::isIdleCallbackNeeded()
{
return isSampleNeeded();
}
/**
* periodic callback.
* Check once every second or so for a new temperature reading.
*/
void MicroBitThermometer::idleTick()
{
if (isSampleNeeded())
updateTemperature();
}
/**
* Determines if we're due to take another temeoratur reading
* @return 1 if we're due to take a temperature reading, 0 otherwise.
*/
int MicroBitThermometer::isSampleNeeded()
{
return ticks >= sampleTime;
}
/**
* Set the sample rate at which the temperatureis read (in ms).
* n.b. the temperature is alwasy read in the background, so wis only updated
* when the processor is idle, or when the temperature is explicitly read.
* The default sample period is 1 second.
* @param period the requested time between samples, in milliseconds.
*/
void MicroBitThermometer::setPeriod(int period)
{
samplePeriod = period;
}
/**
* Reads the currently configured sample rate of the thermometer.
* @return The time between samples, in milliseconds.
*/
int MicroBitThermometer::getPeriod()
{
return samplePeriod;
}
/**
* Updates our recorded temperature from the many sensors on the micro:bit!
*/
void MicroBitThermometer::updateTemperature()
{
int32_t processorTemperature;
// For now, we just rely on the nrf senesor to be the most accurate.
// The compass module also has a temperature sensor, and has the lowest power consumption, so will run the cooler...
// ...however it isn't trimmed for accuracy during manufacture, so requires calibration.
if (uBit.ble)
{
// If Bluetooth is enabled, we need to go through the Nordic software to safely do this
sd_temp_get(&processorTemperature);
}
else
{
// Othwerwise, we access the information directly...
uint32_t *TEMP = (uint32_t *)0x4000C508;
NRF_TEMP->TASKS_START = 1;
while (NRF_TEMP->EVENTS_DATARDY == 0);
NRF_TEMP->EVENTS_DATARDY = 0;
processorTemperature = *TEMP;
NRF_TEMP->TASKS_STOP = 1;
}
// Record our reading...
temperature = processorTemperature / 4;
// Schedule our next sample.
sampleTime = ticks + samplePeriod;
// Send an event to indicate that we'e updated our temperature.
MicroBitEvent e(id, MICROBIT_THERMOMETER_EVT_UPDATE);
}

View File

@ -0,0 +1,92 @@
/**
* Class definition for the custom MicroBit Accelerometer Service.
* Provides a BLE service to remotely read the state of the accelerometer, and configure its behaviour.
*/
#include "MicroBit.h"
#include "ble/UUID.h"
#include "MicroBitAccelerometerService.h"
/**
* Constructor.
* Create a representation of the AccelerometerService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble) :
ble(_ble)
{
// Create the data structures that represent each of our characteristics in Soft Device.
GattCharacteristic accelerometerDataCharacteristic(MicroBitAccelerometerServiceDataUUID, (uint8_t *)accelerometerDataCharacteristicBuffer, 0,
sizeof(accelerometerDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic accelerometerPeriodCharacteristic(MicroBitAccelerometerServicePeriodUUID, (uint8_t *)&accelerometerPeriodCharacteristicBuffer, 0,
sizeof(accelerometerPeriodCharacteristicBuffer),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
// Initialise our characteristic values.
accelerometerDataCharacteristicBuffer[0] = 0;
accelerometerDataCharacteristicBuffer[1] = 0;
accelerometerDataCharacteristicBuffer[2] = 0;
accelerometerPeriodCharacteristicBuffer = uBit.accelerometer.getPeriod();
GattCharacteristic *characteristics[] = {&accelerometerDataCharacteristic, &accelerometerPeriodCharacteristic};
GattService service(MicroBitAccelerometerServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
ble.addService(service);
accelerometerDataCharacteristicHandle = accelerometerDataCharacteristic.getValueHandle();
accelerometerPeriodCharacteristicHandle = accelerometerPeriodCharacteristic.getValueHandle();
ble.gattServer().write(accelerometerDataCharacteristicHandle,(uint8_t *)accelerometerDataCharacteristicBuffer, sizeof(accelerometerDataCharacteristicBuffer));
ble.gattServer().write(accelerometerPeriodCharacteristicHandle, (const uint8_t *)&accelerometerPeriodCharacteristicBuffer, sizeof(accelerometerPeriodCharacteristicBuffer));
ble.onDataWritten(this, &MicroBitAccelerometerService::onDataWritten);
uBit.MessageBus.listen(MICROBIT_ID_ACCELEROMETER, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE, this, &MicroBitAccelerometerService::accelerometerUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
}
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
void MicroBitAccelerometerService::onDataWritten(const GattWriteCallbackParams *params)
{
if (params->handle == accelerometerPeriodCharacteristicHandle && params->len >= sizeof(accelerometerPeriodCharacteristicBuffer))
{
accelerometerPeriodCharacteristicBuffer = *((uint16_t *)params->data);
uBit.accelerometer.setPeriod(accelerometerPeriodCharacteristicBuffer);
// The accelerometer will choose the nearest period to that requested that it can support
// Read back the ACTUAL period it is using, and report this back.
accelerometerPeriodCharacteristicBuffer = uBit.accelerometer.getPeriod();
ble.gattServer().write(accelerometerPeriodCharacteristicHandle, (const uint8_t *)&accelerometerPeriodCharacteristicBuffer, sizeof(accelerometerPeriodCharacteristicBuffer));
}
}
/**
* Accelerometer update callback
*/
void MicroBitAccelerometerService::accelerometerUpdate(MicroBitEvent e)
{
if (ble.getGapState().connected)
{
accelerometerDataCharacteristicBuffer[0] = uBit.accelerometer.getX();
accelerometerDataCharacteristicBuffer[1] = uBit.accelerometer.getY();
accelerometerDataCharacteristicBuffer[2] = uBit.accelerometer.getZ();
ble.gattServer().notify(accelerometerDataCharacteristicHandle,(uint8_t *)accelerometerDataCharacteristicBuffer, sizeof(accelerometerDataCharacteristicBuffer));
}
}
const uint8_t MicroBitAccelerometerServiceUUID[] = {
0xe9,0x5d,0x07,0x53,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitAccelerometerServiceDataUUID[] = {
0xe9,0x5d,0xca,0x4b,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitAccelerometerServicePeriodUUID[] = {
0xe9,0x5d,0xfb,0x24,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};

View File

@ -0,0 +1,112 @@
/**
* Class definition for the custom MicroBit Button Service.
* Provides a BLE service to remotely read the state of each button, and configure its behaviour.
*/
#include "MicroBit.h"
#include "ble/UUID.h"
#include "MicroBitButtonService.h"
/**
* Constructor.
* Create a representation of the ButtonService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitButtonService::MicroBitButtonService(BLEDevice &_ble) :
ble(_ble)
{
// Create the data structures that represent each of our characteristics in Soft Device.
GattCharacteristic buttonADataCharacteristic(MicroBitButtonAServiceDataUUID, (uint8_t *)&buttonADataCharacteristicBuffer, 0,
sizeof(buttonADataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic buttonBDataCharacteristic(MicroBitButtonBServiceDataUUID, (uint8_t *)&buttonADataCharacteristicBuffer, 0,
sizeof(buttonADataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
// Initialise our characteristic values.
buttonADataCharacteristicBuffer = 0;
buttonBDataCharacteristicBuffer = 0;
GattCharacteristic *characteristics[] = {&buttonADataCharacteristic, &buttonBDataCharacteristic};
GattService service(MicroBitButtonServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
ble.addService(service);
buttonADataCharacteristicHandle = buttonADataCharacteristic.getValueHandle();
buttonBDataCharacteristicHandle = buttonBDataCharacteristic.getValueHandle();
ble.gattServer().write(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer));
ble.gattServer().write(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer));
uBit.MessageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonAUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
uBit.MessageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonBUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
}
/**
* Button B update callback
*/
void MicroBitButtonService::buttonAUpdate(MicroBitEvent e)
{
if (ble.getGapState().connected)
{
if (e.value == MICROBIT_BUTTON_EVT_UP)
{
buttonADataCharacteristicBuffer = 0;
ble.gattServer().notify(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer));
}
if (e.value == MICROBIT_BUTTON_EVT_DOWN)
{
buttonADataCharacteristicBuffer = 1;
ble.gattServer().notify(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer));
}
if (e.value == MICROBIT_BUTTON_EVT_HOLD)
{
buttonADataCharacteristicBuffer = 2;
ble.gattServer().notify(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer));
}
}
}
/**
* Button A update callback
*/
void MicroBitButtonService::buttonBUpdate(MicroBitEvent e)
{
if (ble.getGapState().connected)
{
if (e.value == MICROBIT_BUTTON_EVT_UP)
{
buttonBDataCharacteristicBuffer = 0;
ble.gattServer().notify(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer));
}
if (e.value == MICROBIT_BUTTON_EVT_DOWN)
{
buttonBDataCharacteristicBuffer = 1;
ble.gattServer().notify(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer));
}
if (e.value == MICROBIT_BUTTON_EVT_HOLD)
{
buttonBDataCharacteristicBuffer = 2;
ble.gattServer().notify(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer));
}
}
}
const uint8_t MicroBitButtonServiceUUID[] = {
0xe9,0x5d,0x98,0x82,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitButtonAServiceDataUUID[] = {
0xe9,0x5d,0xda,0x90,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
}
;
const uint8_t MicroBitButtonBServiceDataUUID[] = {
0xe9,0x5d,0xda,0x91,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};

View File

@ -46,46 +46,25 @@ MicroBitDFUService::MicroBitDFUService(BLEDevice &_ble) :
microBitDFUServiceControlCharacteristicHandle = microBitDFUServiceControlCharacteristic.getValueHandle();
microBitDFUServiceFlashCodeCharacteristicHandle = microBitDFUServiceFlashCodeCharacteristic.getValueHandle();
ble.onDataWritten(this, &MicroBitDFUService::onDataWritten);
ble.gattServer().onDataWritten(this, &MicroBitDFUService::onDataWritten);
}
/**
* Returns the friendly name for this device, autogenerated from our Device ID.
*
* @param name Pointer to a string where the data will be written.
* @return The number of bytes written.
*/
int MicroBitDFUService::getName(char *name)
void MicroBitDFUService::onButtonA(MicroBitEvent e)
{
const uint8_t codebook[5][5] =
if (flashCodeRequested)
{
{'z', 'v', 'g', 'p', 't'},
{'u', 'o', 'i', 'e', 'a'},
{'z', 'v', 'g', 'p', 't'},
{'u', 'o', 'i', 'e', 'a'},
{'z', 'v', 'g', 'p', 't'}
};
// We count right to left, so fast forward the pointer.
name += MICROBIT_DFU_HISTOGRAM_WIDTH;
uint32_t n = NRF_FICR->DEVICEID[1];
int ld = 1;
int d = MICROBIT_DFU_HISTOGRAM_HEIGHT;
int h;
for (int i=0; i<MICROBIT_DFU_HISTOGRAM_WIDTH;i++)
{
h = (n % d) / ld;
n -= h;
d *= MICROBIT_DFU_HISTOGRAM_HEIGHT;
ld *= MICROBIT_DFU_HISTOGRAM_HEIGHT;
*--name = codebook[i][h];
releaseFlashCode();
uBit.display.scroll("");
showTick();
flashCodeRequested = false;
authenticated = true;
}
}
return MICROBIT_DFU_HISTOGRAM_WIDTH;
void MicroBitDFUService::onButtonB(MicroBitEvent e)
{
uBit.display.scroll("VERSION: TODO");
showNameHistogram();
}
/**
@ -94,48 +73,30 @@ int MicroBitDFUService::getName(char *name)
*/
void MicroBitDFUService::pair()
{
ManagedString blueZoneString("BLUE ZONE...");
ManagedString pairString("PAIR?");
uBit.display.scroll(blueZoneString);
uBit.MessageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, this, &MicroBitDFUService::onButtonA);
uBit.MessageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, this, &MicroBitDFUService::onButtonB);
uBit.display.scroll("BLUE ZONE...");
showNameHistogram();
while(1)
{
for (int i=0; i<100; i++)
{
if (flashCodeRequested)
{
uBit.display.scrollAsync(pairString);
for (int j=0; j<40; j++)
{
if (uBit.buttonA.isPressed())
{
i=100;
releaseFlashCode();
showTick();
flashCodeRequested = false;
authenticated = true;
break;
}
wait(0.1);
}
}
wait (0.1);
if (flashCodeRequested)
uBit.display.scroll("PAIR?");
// If our peer disconnects, drop all state.
if ((authenticated || flashCodeRequested) && !ble.getGapState().connected)
{
authenticated = false;
flashCodeRequested = false;
flashCode = 0x00;
}
// If our peer disconnects, drop all state.
if ((authenticated || flashCodeRequested) && !ble.getGapState().connected)
{
authenticated = false;
flashCodeRequested = false;
flashCode = 0x00;
}
uBit.sleep(500);
}
}
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
@ -152,6 +113,9 @@ void MicroBitDFUService::onDataWritten(const GattWriteCallbackParams *params)
if (authenticated)
{
uBit.display.scroll("");
uBit.display.clear();
#if CONFIG_ENABLED(MICROBIT_DBG)
pc.printf(" ACTIVATING BOOTLOADER.\n");
#endif
@ -161,6 +125,9 @@ void MicroBitDFUService::onDataWritten(const GattWriteCallbackParams *params)
break;
case MICROBIT_DFU_OPCODE_START_PAIR:
#if CONFIG_ENABLED(MICROBIT_DBG)
pc.printf(" PAIRING REQUESTED.\n");
#endif
flashCodeRequested = true;
break;
@ -242,13 +209,13 @@ void MicroBitDFUService::releaseFlashCode()
*/
const uint8_t MicroBitDFUServiceUUID[] = {
0xd8,0xaf,0x99,0x1c,0x71,0x44,0x43,0xd7,0x95,0x4b,0x99,0x51,0x2f,0x95,0xf9,0x9c
0xe9,0x5d,0x93,0xb0,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitDFUServiceControlCharacteristicUUID[] = {
0x97,0x10,0x95,0x47,0xe6,0x3a,0x44,0x2a,0xbf,0x89,0x9d,0x73,0x04,0x13,0xdc,0x2f
0xe9,0x5d,0x93,0xb1,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitDFUServiceFlashCodeCharacteristicUUID[] = {
0x94,0x7b,0x69,0x34,0x64,0xd1,0x4f,0xad,0x9b,0xd0,0xcc,0x9d,0x6e,0x9f,0x3e,0xa3
0xe9,0x5d,0x93,0xb2,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};

View File

@ -0,0 +1,154 @@
/**
* Class definition for a MicroBit BLE Event Service.
* Provides a BLE gateway onto the MicroBit Message Bus.
*/
#include "MicroBit.h"
#include "ble/UUID.h"
#include "ExternalEvents.h"
/**
* Constructor.
* Create a representation of the EventService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitEventService::MicroBitEventService(BLEDevice &_ble) :
ble(_ble)
{
GattCharacteristic microBitEventCharacteristic(MicroBitEventServiceMicroBitEventCharacteristicUUID, (uint8_t *)&microBitEventBuffer, 0, sizeof(EventServiceEvent),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic clientEventCharacteristic(MicroBitEventServiceClientEventCharacteristicUUID, (uint8_t *)&clientEventBuffer, 0, sizeof(EventServiceEvent),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
GattCharacteristic clientRequirementsCharacteristic(MicroBitEventServiceClientRequirementsCharacteristicUUID, (uint8_t *)&clientRequirementsBuffer, 0, sizeof(EventServiceEvent), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
microBitRequirementsCharacteristic = new GattCharacteristic(MicroBitEventServiceMicroBitRequirementsCharacteristicUUID, (uint8_t *)&microBitRequirementsBuffer, 0, sizeof(EventServiceEvent), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
microBitRequirementsCharacteristic->setReadAuthorizationCallback(this, &MicroBitEventService::onRequirementsRead);
clientEventBuffer.type = 0x00;
clientEventBuffer.reason = 0x00;
microBitEventBuffer = microBitRequirementsBuffer = clientRequirementsBuffer = clientEventBuffer;
messageBusListenerOffset = 0;
GattCharacteristic *characteristics[] = {&microBitEventCharacteristic, &clientEventCharacteristic, &clientRequirementsCharacteristic, microBitRequirementsCharacteristic};
GattService service(MicroBitEventServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
ble.addService(service);
microBitEventCharacteristicHandle = microBitEventCharacteristic.getValueHandle();
clientEventCharacteristicHandle = clientEventCharacteristic.getValueHandle();
clientRequirementsCharacteristicHandle = clientRequirementsCharacteristic.getValueHandle();
ble.onDataWritten(this, &MicroBitEventService::onDataWritten);
uBit.addIdleComponent(this);
}
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
void MicroBitEventService::onDataWritten(const GattWriteCallbackParams *params)
{
int len = params->len;
EventServiceEvent *e = (EventServiceEvent *)params->data;
if (params->handle == clientEventCharacteristicHandle) {
// Read and fire all events...
while (len >= 4)
{
MicroBitEvent evt(e->type, e->reason);
len-=4;
e++;
}
return;
}
if (params->handle == clientRequirementsCharacteristicHandle) {
// Read and register for all the events given...
while (len >= 4)
{
uBit.MessageBus.listen(e->type, e->reason, this, &MicroBitEventService::onMicroBitEvent, MESSAGE_BUS_LISTENER_IMMEDIATE);
len-=4;
e++;
}
return;
}
}
/**
* Callback. Invoked when any events are sent on the microBit message bus.
*/
void MicroBitEventService::onMicroBitEvent(MicroBitEvent evt)
{
EventServiceEvent *e = &microBitEventBuffer;
if (ble.getGapState().connected) {
e->type = evt.source;
e->reason = evt.value;
ble.gattServer().notify(microBitEventCharacteristicHandle, (const uint8_t *)e, sizeof(EventServiceEvent));
}
}
/**
* Periodic callback from MicroBit scheduler.
* If we're no longer connected, remove any registered Message Bus listeners.
*/
void MicroBitEventService::idleTick()
{
if (!ble.getGapState().connected && messageBusListenerOffset >0) {
messageBusListenerOffset = 0;
uBit.MessageBus.ignore(MICROBIT_ID_ANY, MICROBIT_EVT_ANY, this, &MicroBitEventService::onMicroBitEvent);
}
}
/**
* read callback on data characteristic.
* reads all the pins marked as inputs, and updates the data stored in the BLE stack.
*/
void MicroBitEventService::onRequirementsRead(GattReadAuthCallbackParams *params)
{
if (params->handle == microBitRequirementsCharacteristic->getValueHandle())
{
// Walk through the lsit of message bus listeners.
// We send one at a time, and our client can keep reading from this characterisitic until we return an emtpy value.
MicroBitListener *l = uBit.MessageBus.elementAt(messageBusListenerOffset++);
if (l != NULL)
{
microBitRequirementsBuffer.type = l->id;
microBitRequirementsBuffer.reason = l->value;
ble.gattServer().write(microBitRequirementsCharacteristic->getValueHandle(), (uint8_t *)&microBitRequirementsBuffer, sizeof(EventServiceEvent));
} else {
ble.gattServer().write(microBitRequirementsCharacteristic->getValueHandle(), (uint8_t *)&microBitRequirementsBuffer, 0);
}
}
}
const uint8_t MicroBitEventServiceUUID[] = {
0xe9,0x5d,0x93,0xaf,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitEventServiceMicroBitEventCharacteristicUUID[] = {
0xe9,0x5d,0x97,0x75,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitEventServiceClientEventCharacteristicUUID[] = {
0xe9,0x5d,0x54,0x04,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitEventServiceMicroBitRequirementsCharacteristicUUID[] = {
0xe9,0x5d,0xb8,0x4c,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitEventServiceClientRequirementsCharacteristicUUID[] = {
0xe9,0x5d,0x23,0xc4,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};

View File

@ -0,0 +1,285 @@
/**
* Class definition for the custom MicroBit IOPin Service.
* Provides a BLE service to remotely read the state of the ioPin, and configure its behaviour.
*/
#include "MicroBit.h"
#include "ble/UUID.h"
#include "MicroBitIOPinService.h"
/**
* Constructor.
* Create a representation of the IOPinService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitIOPinService::MicroBitIOPinService(BLEDevice &_ble) :
ble(_ble)
{
// Create the AD characteristic, that defines whether each pin is treated as analogue or digital
GattCharacteristic ioPinServiceADCharacteristic(MicroBitIOPinServiceADConfigurationUUID, (uint8_t *)&ioPinServiceADCharacteristicBuffer, 0, sizeof(ioPinServiceADCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
// Create the IO characteristic, that defines whether each pin is treated as input or output
GattCharacteristic ioPinServiceIOCharacteristic(MicroBitIOPinServiceIOConfigurationUUID, (uint8_t *)&ioPinServiceIOCharacteristicBuffer, 0, sizeof(ioPinServiceIOCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
// Create the Data characteristic, that allows the actual read and write operations.
ioPinServiceDataCharacteristic = new GattCharacteristic(MicroBitIOPinServiceDataUUID, (uint8_t *)ioPinServiceDataCharacteristicBuffer, 0, sizeof(ioPinServiceDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
ioPinServiceDataCharacteristic->setReadAuthorizationCallback(this, &MicroBitIOPinService::onDataRead);
ioPinServiceADCharacteristicBuffer = 0;
ioPinServiceIOCharacteristicBuffer = 0;
memset(ioPinServiceIOData, 0, sizeof(ioPinServiceIOData));
GattCharacteristic *characteristics[] = {&ioPinServiceADCharacteristic, &ioPinServiceIOCharacteristic, ioPinServiceDataCharacteristic};
GattService service(MicroBitIOPinServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
ble.addService(service);
ioPinServiceADCharacteristicHandle = ioPinServiceADCharacteristic.getValueHandle();
ioPinServiceIOCharacteristicHandle = ioPinServiceIOCharacteristic.getValueHandle();
ble.gattServer().write(ioPinServiceADCharacteristicHandle, (const uint8_t *)&ioPinServiceADCharacteristicBuffer, sizeof(ioPinServiceADCharacteristicBuffer));
ble.gattServer().write(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer));
ble.onDataWritten(this, &MicroBitIOPinService::onDataWritten);
uBit.addIdleComponent(this);
}
/**
* Determines if the given pin was configured as a digital pin by the BLE IOPinConfigurationCharacterisitic.
*
* @param pin the enumeration of the pin to test
* @return 1 if this pin is configured as a digital value, 0 otherwise
*/
int MicroBitIOPinService::isDigital(int i)
{
return ((ioPinServiceADCharacteristicBuffer & (1 << i)) == 0);
}
/**
* Determines if the given pin was configured as an analog pin by the BLE IOPinConfigurationCharacterisitic.
*
* @param pin the enumeration of the pin to test
* @return 1 if this pin is configured as a analog value, 0 otherwise
*/
int MicroBitIOPinService::isAnalog(int i)
{
return ((ioPinServiceADCharacteristicBuffer & (1 << i)) != 0);
}
/**
* Determines if the given pin was configured as an input by the BLE IOPinConfigurationCharacterisitic.
*
* @param pin the enumeration of the pin to test
* @return 1 if this pin is configured as an input, 0 otherwise
*/
int MicroBitIOPinService::isInput(int i)
{
return ((ioPinServiceIOCharacteristicBuffer & (1 << i)) != 0);
}
/**
* Determines if the given pin was configured as output by the BLE IOPinConfigurationCharacterisitic.
*
* @param pin the enumeration of the pin to test
* @return 1 if this pin is configured as an output, 0 otherwise
*/
int MicroBitIOPinService::isOutput(int i)
{
return ((ioPinServiceIOCharacteristicBuffer & (1 << i)) == 0);
}
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params)
{
// Check for writes to the IO configuration characteristic
if (params->handle == ioPinServiceIOCharacteristicHandle && params->len >= sizeof(ioPinServiceIOCharacteristicBuffer))
{
uint32_t *value = (uint32_t *)params->data;
// Our IO configuration may be changing... read the new value, and push it back into the BLE stack.
ioPinServiceIOCharacteristicBuffer = *value;
ble.gattServer().write(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer));
// Also, drop any selected pins into input mode, so we can pick up changes later
for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
{
if(isDigital(i) && isInput(i))
MicroBitIOPins[i]->getDigitalValue();
if(isAnalog(i) && isInput(i))
MicroBitIOPins[i]->getAnalogValue();
}
}
// Check for writes to the IO configuration characteristic
if (params->handle == ioPinServiceADCharacteristicHandle && params->len >= sizeof(ioPinServiceADCharacteristicBuffer))
{
uint32_t *value = (uint32_t *)params->data;
// Our IO configuration may be changing... read the new value, and push it back into the BLE stack.
ioPinServiceADCharacteristicBuffer = *value;
ble.gattServer().write(ioPinServiceADCharacteristicHandle, (const uint8_t *)&ioPinServiceADCharacteristicBuffer, sizeof(ioPinServiceADCharacteristicBuffer));
// Also, drop any selected pins into input mode, so we can pick up changes later
for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
{
if(isDigital(i) && isInput(i))
MicroBitIOPins[i]->getDigitalValue();
if(isAnalog(i) && isInput(i))
MicroBitIOPins[i]->getAnalogValue();
}
}
if (params->handle == ioPinServiceDataCharacteristic->getValueHandle())
{
// We have some pin data to change...
int len = params->len;
IOData *data = (IOData *)params->data;
// There may be multiple write operaitons... take each in turn and update the pin values
while (len >= sizeof(IOData))
{
if (isOutput(data->pin))
{
if (isDigital(data->pin))
MicroBitIOPins[data->pin]->setDigitalValue(data->value);
else
MicroBitIOPins[data->pin]->setAnalogValue(data->value*4);
}
data++;
len -= sizeof(IOData);
}
}
}
/**
* read callback on data characteristic.
* reads all the pins marked as inputs, and updates the data stored in the BLE stack.
*/
void MicroBitIOPinService::onDataRead(GattReadAuthCallbackParams *params)
{
if (params->handle == ioPinServiceDataCharacteristic->getValueHandle())
{
// Scan through all pins that our BLE client may be listening for. If any have changed value, update the BLE characterisitc, and NOTIFY our client.
int pairs = 0;
for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
{
if (isInput(i))
{
uint8_t value;
if (isDigital(i))
value = MicroBitIOPins[i]->getDigitalValue();
else
value = MicroBitIOPins[i]->getAnalogValue();
ioPinServiceIOData[i] = value;
ioPinServiceDataCharacteristicBuffer[pairs].pin = i;
ioPinServiceDataCharacteristicBuffer[pairs].value = value;
pairs++;
if (pairs >= MICROBIT_IO_PIN_SERVICE_DATA_SIZE)
break;
}
}
// If there's any data, issue a BLE notification.
if (pairs > 0)
ble.gattServer().notify(ioPinServiceDataCharacteristic->getValueHandle(), (uint8_t *)ioPinServiceDataCharacteristicBuffer, pairs * sizeof(IOData));
}
}
/**
* Periodic callback from MicroBit scheduler.
* Check if any of the pins we're watching need updating. Apply a BLE NOTIFY if so...
*/
void MicroBitIOPinService::idleTick()
{
// If we're not we're connected, then there's nothing to do...
if (!ble.getGapState().connected)
return;
// Scan through all pins that our BLE client may be listening for. If any have changed value, update the BLE characterisitc, and NOTIFY our client.
int pairs = 0;
for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
{
if (isInput(i))
{
uint8_t value;
if (isDigital(i))
value = MicroBitIOPins[i]->getDigitalValue();
else
value = MicroBitIOPins[i]->getAnalogValue();
// If the data has changed, send an update.
if (value != ioPinServiceIOData[i])
{
ioPinServiceIOData[i] = value;
ioPinServiceDataCharacteristicBuffer[pairs].pin = i;
ioPinServiceDataCharacteristicBuffer[pairs].value = value;
pairs++;
if (pairs >= MICROBIT_IO_PIN_SERVICE_DATA_SIZE)
break;
}
}
}
// If there were any changes, issue a BLE notification.
if (pairs > 0)
ble.gattServer().notify(ioPinServiceDataCharacteristic->getValueHandle(), (uint8_t *)ioPinServiceDataCharacteristicBuffer, pairs * sizeof(IOData));
}
const uint8_t MicroBitIOPinServiceUUID[] = {
0xe9,0x5d,0x12,0x7b,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitIOPinServiceIOConfigurationUUID[] = {
0xe9,0x5d,0xb9,0xfe,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitIOPinServiceADConfigurationUUID[] = {
0xe9,0x5d,0x58,0x99,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitIOPinServiceDataUUID[] = {
0xe9,0x5d,0x8d,0x00,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
MicroBitPin * const MicroBitIOPins[] = {
&uBit.io.P0,
&uBit.io.P1,
&uBit.io.P2,
&uBit.io.P3,
&uBit.io.P4,
&uBit.io.P5,
&uBit.io.P6,
&uBit.io.P7,
&uBit.io.P8,
&uBit.io.P9,
&uBit.io.P10,
&uBit.io.P11,
&uBit.io.P12,
&uBit.io.P13,
&uBit.io.P14,
&uBit.io.P15,
&uBit.io.P16,
&uBit.io.P19,
&uBit.io.P20
};

View File

@ -0,0 +1,122 @@
/**
* Class definition for the custom MicroBit LED Service.
* Provides a BLE service to remotely read and write the state of the LED display.
*/
#include "MicroBit.h"
#include "ble/UUID.h"
#include "MicroBitLEDService.h"
/**
* Constructor.
* Create a representation of the LEDService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitLEDService::MicroBitLEDService(BLEDevice &_ble) :
ble(_ble),
matrixCharacteristic(MicroBitLEDServiceMatrixUUID, (uint8_t *)&matrixCharacteristicBuffer, 0, sizeof(matrixCharacteristicBuffer),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ)
{
// Create the data structures that represent each of our characteristics in Soft Device.
GattCharacteristic textCharacteristic(MicroBitLEDServiceTextUUID, (uint8_t *)textCharacteristicBuffer, 0, MICROBIT_BLE_MAXIMUM_SCROLLTEXT,
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
GattCharacteristic scrollingSpeedCharacteristic(MicroBitLEDServiceScrollingSpeedUUID, (uint8_t *)&scrollingSpeedCharacteristicBuffer, 0,
sizeof(scrollingSpeedCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
// Initialise our characteristic values.
memclr(matrixCharacteristicBuffer, sizeof(matrixCharacteristicBuffer));
textCharacteristicBuffer[0] = 0;
scrollingSpeedCharacteristicBuffer = MICROBIT_DEFAULT_SCROLL_SPEED;
matrixCharacteristic.setReadAuthorizationCallback(this, &MicroBitLEDService::onDataRead);
GattCharacteristic *characteristics[] = {&matrixCharacteristic, &textCharacteristic, &scrollingSpeedCharacteristic};
GattService service(MicroBitLEDServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
ble.addService(service);
matrixCharacteristicHandle = matrixCharacteristic.getValueHandle();
textCharacteristicHandle = textCharacteristic.getValueHandle();
scrollingSpeedCharacteristicHandle = scrollingSpeedCharacteristic.getValueHandle();
ble.gattServer().write(scrollingSpeedCharacteristicHandle, (const uint8_t *)&scrollingSpeedCharacteristicBuffer, sizeof(scrollingSpeedCharacteristicBuffer));
ble.gattServer().write(matrixCharacteristicHandle, (const uint8_t *)&matrixCharacteristicBuffer, sizeof(matrixCharacteristicBuffer));
ble.onDataWritten(this, &MicroBitLEDService::onDataWritten);
}
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
void MicroBitLEDService::onDataWritten(const GattWriteCallbackParams *params)
{
uint8_t *data = (uint8_t *)params->data;
if (params->handle == matrixCharacteristicHandle && params->len > 0 && params->len < 6)
{
for (int y=0; y<params->len; y++)
for (int x=0; x<5; x++)
uBit.display.image.setPixelValue(x, y, (data[y] & (0x01 << 4-x)) ? 255 : 0);
}
else if (params->handle == textCharacteristicHandle)
{
// Create a ManagedString representation from the UTF8 data.
// We do this explicitly to control the length (in case the string is not NULL terminated!)
ManagedString s((char *)params->data, params->len);
// Start the string scrolling and we're done.
uBit.display.scrollAsync(s, (int) scrollingSpeedCharacteristicBuffer);
}
else if (params->handle == scrollingSpeedCharacteristicHandle && params->len >= sizeof(scrollingSpeedCharacteristicBuffer))
{
// Read the speed requested, and store it locally.
// We use this as the speed for all scroll operations subsquently initiated from BLE.
scrollingSpeedCharacteristicBuffer = *((uint16_t *)params->data);
}
}
/**
* Callback. Invoked when any of our attributes are read via BLE.
*/
void MicroBitLEDService::onDataRead(GattReadAuthCallbackParams *params)
{
if (params->handle == matrixCharacteristicHandle)
{
for (int y=0; y<5; y++)
{
matrixCharacteristicBuffer[y] = 0;
for (int x=0; x<5; x++)
{
if (uBit.display.image.getPixelValue(x, y))
matrixCharacteristicBuffer[y] |= 0x01 << 4-x;
}
}
ble.gattServer().write(matrixCharacteristicHandle, (const uint8_t *)&matrixCharacteristicBuffer, sizeof(matrixCharacteristicBuffer));
}
}
const uint8_t MicroBitLEDServiceUUID[] = {
0xe9,0x5d,0xd9,0x1d,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitLEDServiceMatrixUUID[] = {
0xe9,0x5d,0x7b,0x77,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitLEDServiceTextUUID[] = {
0xe9,0x5d,0x93,0xee,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitLEDServiceScrollingSpeedUUID[] = {
0xe9,0x5d,0x0d,0x2d,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};

View File

@ -0,0 +1,122 @@
/**
* Class definition for the custom MicroBit Magnetometer Service.
* Provides a BLE service to remotely read the state of the magnetometer, and configure its behaviour.
*/
#include "MicroBit.h"
#include "ble/UUID.h"
#include "MicroBitMagnetometerService.h"
/**
* Constructor.
* Create a representation of the MagnetometerService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble) :
ble(_ble)
{
// Create the data structures that represent each of our characteristics in Soft Device.
GattCharacteristic magnetometerDataCharacteristic(MicroBitMagnetometerServiceDataUUID, (uint8_t *)magnetometerDataCharacteristicBuffer, 0,
sizeof(magnetometerDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic magnetometerBearingCharacteristic(MicroBitMagnetometerServiceBearingUUID, (uint8_t *)&magnetometerBearingCharacteristicBuffer, 0,
sizeof(magnetometerBearingCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic magnetometerPeriodCharacteristic(MicroBitMagnetometerServicePeriodUUID, (uint8_t *)&magnetometerPeriodCharacteristicBuffer, 0,
sizeof(magnetometerPeriodCharacteristicBuffer),
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
// Initialise our characteristic values.
magnetometerDataCharacteristicBuffer[0] = 0;
magnetometerDataCharacteristicBuffer[1] = 0;
magnetometerDataCharacteristicBuffer[2] = 0;
magnetometerBearingCharacteristicBuffer = 0;
magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod();
GattCharacteristic *characteristics[] = {&magnetometerDataCharacteristic, &magnetometerBearingCharacteristic, &magnetometerPeriodCharacteristic};
GattService service(MicroBitMagnetometerServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
ble.addService(service);
magnetometerDataCharacteristicHandle = magnetometerDataCharacteristic.getValueHandle();
magnetometerBearingCharacteristicHandle = magnetometerBearingCharacteristic.getValueHandle();
magnetometerPeriodCharacteristicHandle = magnetometerPeriodCharacteristic.getValueHandle();
ble.gattServer().notify(magnetometerDataCharacteristicHandle,(uint8_t *)magnetometerDataCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer));
ble.gattServer().notify(magnetometerBearingCharacteristicHandle,(uint8_t *)&magnetometerBearingCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer));
ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer));
ble.onDataWritten(this, &MicroBitMagnetometerService::onDataWritten);
uBit.MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_DATA_UPDATE, this, &MicroBitMagnetometerService::magnetometerUpdate);
uBit.MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CONFIG_NEEDED, this, &MicroBitMagnetometerService::samplePeriodUpdateNeeded);
}
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
void MicroBitMagnetometerService::onDataWritten(const GattWriteCallbackParams *params)
{
if (params->handle == magnetometerPeriodCharacteristicHandle && params->len >= sizeof(magnetometerPeriodCharacteristicBuffer))
{
magnetometerPeriodCharacteristicBuffer = *((uint16_t *)params->data);
MicroBitEvent evt(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CONFIG_NEEDED);
}
}
/**
* Magnetometer update callback
*/
void MicroBitMagnetometerService::magnetometerUpdate(MicroBitEvent e)
{
if (ble.getGapState().connected)
{
magnetometerDataCharacteristicBuffer[0] = uBit.compass.getX();
magnetometerDataCharacteristicBuffer[1] = uBit.compass.getY();
magnetometerDataCharacteristicBuffer[2] = uBit.compass.getZ();
magnetometerBearingCharacteristicBuffer = (uint16_t) uBit.compass.heading();
magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod();
ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer));
ble.gattServer().notify(magnetometerDataCharacteristicHandle,(uint8_t *)magnetometerDataCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer));
ble.gattServer().notify(magnetometerBearingCharacteristicHandle,(uint8_t *)&magnetometerBearingCharacteristicBuffer, sizeof(magnetometerBearingCharacteristicBuffer));
}
}
/**
* Sample Period Change Needed callback.
* Reconfiguring the magnetometer can to a REALLY long time (sometimes even seconds to complete)
* So we do this in the background when necessary, through this event handler.
*/
void MicroBitMagnetometerService::samplePeriodUpdateNeeded(MicroBitEvent e)
{
// Reconfigure the compass. This might take a while...
uBit.compass.setPeriod(magnetometerPeriodCharacteristicBuffer);
// The compass will choose the nearest sample period to that we've specified.
// Read the ACTUAL sample period back.
magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod();
// Ensure this is reflected in our BLE connection.
ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer));
}
const uint8_t MicroBitMagnetometerServiceUUID[] = {
0xe9,0x5d,0xf2,0xd8,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitMagnetometerServiceDataUUID[] = {
0xe9,0x5d,0xfb,0x11,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitMagnetometerServicePeriodUUID[] = {
0xe9,0x5d,0x38,0x6c,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitMagnetometerServiceBearingUUID[] = {
0xe9,0x5d,0x97,0x15,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};

View File

@ -0,0 +1,87 @@
/**
* Class definition for the custom MicroBit Temperature Service.
* Provides a BLE service to remotely read the state of the temperature, and configure its behaviour.
*/
#include "MicroBit.h"
#include "ble/UUID.h"
#include "MicroBitTemperatureService.h"
/**
* Constructor.
* Create a representation of the TemperatureService
* @param _ble The instance of a BLE device that we're running on.
*/
MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble) :
ble(_ble)
{
// Create the data structures that represent each of our characteristics in Soft Device.
GattCharacteristic temperatureDataCharacteristic(MicroBitTemperatureServiceDataUUID, (uint8_t *)&temperatureDataCharacteristicBuffer, 0,
sizeof(temperatureDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
GattCharacteristic temperaturePeriodCharacteristic(MicroBitTemperatureServicePeriodUUID, (uint8_t *)&temperaturePeriodCharacteristicBuffer, 0,
sizeof(temperaturePeriodCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
// Initialise our characteristic values.
temperatureDataCharacteristicBuffer = 0;
temperaturePeriodCharacteristicBuffer = uBit.thermometer.getPeriod();
GattCharacteristic *characteristics[] = {&temperatureDataCharacteristic, &temperaturePeriodCharacteristic};
GattService service(MicroBitTemperatureServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
ble.addService(service);
temperatureDataCharacteristicHandle = temperatureDataCharacteristic.getValueHandle();
temperaturePeriodCharacteristicHandle = temperaturePeriodCharacteristic.getValueHandle();
ble.gattServer().write(temperatureDataCharacteristicHandle,(uint8_t *)&temperatureDataCharacteristicBuffer, sizeof(temperatureDataCharacteristicBuffer));
ble.gattServer().write(temperaturePeriodCharacteristicHandle,(uint8_t *)&temperaturePeriodCharacteristicBuffer, sizeof(temperaturePeriodCharacteristicBuffer));
ble.onDataWritten(this, &MicroBitTemperatureService::onDataWritten);
uBit.MessageBus.listen(MICROBIT_ID_THERMOMETER, MICROBIT_THERMOMETER_EVT_UPDATE, this, &MicroBitTemperatureService::temperatureUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
}
/**
* Temperature update callback
*/
void MicroBitTemperatureService::temperatureUpdate(MicroBitEvent e)
{
if (ble.getGapState().connected)
{
temperatureDataCharacteristicBuffer = uBit.thermometer.getTemperature();
ble.gattServer().notify(temperatureDataCharacteristicHandle,(uint8_t *)&temperatureDataCharacteristicBuffer, sizeof(temperatureDataCharacteristicBuffer));
}
}
/**
* Callback. Invoked when any of our attributes are written via BLE.
*/
void MicroBitTemperatureService::onDataWritten(const GattWriteCallbackParams *params)
{
if (params->handle == temperaturePeriodCharacteristicHandle && params->len >= sizeof(temperaturePeriodCharacteristicBuffer))
{
temperaturePeriodCharacteristicBuffer = *((uint16_t *)params->data);
uBit.thermometer.setPeriod(temperaturePeriodCharacteristicBuffer);
// The accelerometer will choose the nearest period to that requested that it can support
// Read back the ACTUAL period it is using, and report this back.
temperaturePeriodCharacteristicBuffer = uBit.accelerometer.getPeriod();
ble.gattServer().write(temperaturePeriodCharacteristicHandle, (const uint8_t *)&temperaturePeriodCharacteristicBuffer, sizeof(temperaturePeriodCharacteristicBuffer));
}
}
const uint8_t MicroBitTemperatureServiceUUID[] = {
0xe9,0x5d,0x61,0x00,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitTemperatureServiceDataUUID[] = {
0xe9,0x5d,0x92,0x50,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};
const uint8_t MicroBitTemperatureServicePeriodUUID[] = {
0xe9,0x5d,0x1b,0x25,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
};