mirror of
https://github.com/lupyuen/lupyuen.github.io.git
synced 2025-01-13 10:18:33 +08:00
1102 lines
No EOL
61 KiB
HTML
1102 lines
No EOL
61 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="generator" content="rustdoc">
|
||
<title>Encode Sensor Data with CBOR on BL602</title>
|
||
|
||
|
||
<!-- Begin scripts/articles/*-header.html: Article Header for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
<meta property="og:title"
|
||
content="Encode Sensor Data with CBOR on BL602"
|
||
data-rh="true">
|
||
<meta property="og:description"
|
||
content="How we compress Sensor Data with CBOR... And transmit over LoRaWAN on the BL602 / BL604 RISC-V SoC"
|
||
data-rh="true">
|
||
<meta property="og:image"
|
||
content="https://lupyuen.github.io/images/cbor-title.jpg">
|
||
<meta property="og:type"
|
||
content="article" data-rh="true">
|
||
<link rel="canonical" href="https://lupyuen.org/articles/cbor.html" />
|
||
<!-- End scripts/articles/*-header.html -->
|
||
<!-- Begin scripts/rustdoc-header.html: Header for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
<link rel="alternate" type="application/rss+xml" title="RSS Feed for lupyuen" href="/rss.xml" />
|
||
<link rel="stylesheet" type="text/css" href="../normalize.css">
|
||
<link rel="stylesheet" type="text/css" href="../rustdoc.css" id="mainThemeStyle">
|
||
<link rel="stylesheet" type="text/css" href="../dark.css">
|
||
<link rel="stylesheet" type="text/css" href="../light.css" id="themeStyle">
|
||
<link rel="stylesheet" type="text/css" href="../prism.css">
|
||
<script src="../storage.js"></script><noscript>
|
||
<link rel="stylesheet" href="../noscript.css"></noscript>
|
||
<link rel="shortcut icon" href="../favicon.ico">
|
||
<style type="text/css">
|
||
#crate-search {
|
||
background-image: url("../down-arrow.svg");
|
||
}
|
||
</style>
|
||
<!-- End scripts/rustdoc-header.html -->
|
||
|
||
|
||
</head>
|
||
<body class="rustdoc">
|
||
<!--[if lte IE 8]>
|
||
<div class="warning">
|
||
This old browser is unsupported and will most likely display funky
|
||
things.
|
||
</div>
|
||
<![endif]-->
|
||
|
||
|
||
<!-- Begin scripts/rustdoc-before.html: Pre-HTML for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
|
||
<!-- Begin Theme Picker -->
|
||
<div class="theme-picker" style="left: 0"><button id="theme-picker" aria-label="Pick another theme!"><img src="../brush.svg"
|
||
width="18" alt="Pick another theme!"></button>
|
||
<div id="theme-choices"></div>
|
||
</div>
|
||
<!-- Theme Picker -->
|
||
|
||
<!-- End scripts/rustdoc-before.html -->
|
||
|
||
|
||
<h1 class="title">Encode Sensor Data with CBOR on BL602</h1>
|
||
<nav id="rustdoc"><ul>
|
||
<li><a href="#encode-sensor-data-with-tinycbor" title="Encode Sensor Data with TinyCBOR">1 Encode Sensor Data with TinyCBOR</a><ul>
|
||
<li><a href="#output-buffer-and-cbor-encoder" title="Output Buffer and CBOR Encoder">1.1 Output Buffer and CBOR Encoder</a><ul></ul></li>
|
||
<li><a href="#create-map-encoder" title="Create Map Encoder">1.2 Create Map Encoder</a><ul></ul></li>
|
||
<li><a href="#encode-key-and-value" title="Encode Key and Value">1.3 Encode Key and Value</a><ul></ul></li>
|
||
<li><a href="#close-map-encoder" title="Close Map Encoder">1.4 Close Map Encoder</a><ul></ul></li>
|
||
<li><a href="#get-encoded-output" title="Get Encoded Output">1.5 Get Encoded Output</a><ul></ul></li>
|
||
<li><a href="#magic-happens" title="Magic Happens">1.6 Magic Happens</a><ul></ul></li></ul></li>
|
||
<li><a href="#add-another-field" title="Add Another Field">2 Add Another Field</a><ul>
|
||
<li><a href="#modify-map-encoder" title="Modify Map Encoder">2.1 Modify Map Encoder</a><ul></ul></li>
|
||
<li><a href="#encode-first-key-and-value" title="Encode First Key and Value">2.2 Encode First Key and Value</a><ul></ul></li>
|
||
<li><a href="#encode-second-key-and-value" title="Encode Second Key and Value">2.3 Encode Second Key and Value</a><ul></ul></li>
|
||
<li><a href="#watch-the-magic" title="Watch the Magic">2.4 Watch the Magic</a><ul></ul></li></ul></li>
|
||
<li><a href="#cbor-data-types" title="CBOR Data Types">3 CBOR Data Types</a><ul>
|
||
<li><a href="#numbers" title="Numbers">3.1 Numbers</a><ul></ul></li>
|
||
<li><a href="#strings" title="Strings">3.2 Strings</a><ul></ul></li>
|
||
<li><a href="#other-types" title="Other Types">3.3 Other Types</a><ul></ul></li></ul></li>
|
||
<li><a href="#floating-point-numbers" title="Floating-Point Numbers">4 Floating-Point Numbers</a><ul>
|
||
<li><a href="#encode-floats-as-integers" title="Encode Floats as Integers">4.1 Encode Floats as Integers</a><ul></ul></li>
|
||
<li><a href="#accuracy-and-precision" title="Accuracy and Precision">4.2 Accuracy and Precision</a><ul></ul></li></ul></li>
|
||
<li><a href="#lorawan-with-cbor" title="LoRaWAN With CBOR">5 LoRaWAN With CBOR</a><ul>
|
||
<li><a href="#encode-sensor-data" title="Encode Sensor Data">5.1 Encode Sensor Data</a><ul></ul></li>
|
||
<li><a href="#send-lorawan-packet" title="Send LoRaWAN Packet">5.2 Send LoRaWAN Packet</a><ul></ul></li>
|
||
<li><a href="#cbor-in-action" title="CBOR In Action">5.3 CBOR In Action</a><ul></ul></li></ul></li>
|
||
<li><a href="#decode-cbor" title="Decode CBOR">6 Decode CBOR</a><ul></ul></li>
|
||
<li><a href="#whats-next" title="What’s Next">7 What’s Next</a><ul></ul></li>
|
||
<li><a href="#notes" title="Notes">8 Notes</a><ul></ul></li>
|
||
<li><a href="#appendix-build-and-run-cbor-firmware" title="Appendix: Build and Run CBOR Firmware">9 Appendix: Build and Run CBOR Firmware</a><ul>
|
||
<li><a href="#build-cbor-firmware" title="Build CBOR Firmware">9.1 Build CBOR Firmware</a><ul></ul></li>
|
||
<li><a href="#flash-cbor-firmware" title="Flash CBOR Firmware">9.2 Flash CBOR Firmware</a><ul></ul></li>
|
||
<li><a href="#run-cbor-firmware" title="Run CBOR Firmware">9.3 Run CBOR Firmware</a><ul></ul></li></ul></li>
|
||
<li><a href="#appendix-add-tinycbor-to-your-project" title="Appendix: Add TinyCBOR to Your Project">10 Appendix: Add TinyCBOR to Your Project</a><ul></ul></li>
|
||
<li><a href="#appendix-build-and-run-lorawan-firmware" title="Appendix: Build and Run LoRaWAN Firmware">11 Appendix: Build and Run LoRaWAN Firmware</a><ul>
|
||
<li><a href="#build-lorawan-firmware" title="Build LoRaWAN Firmware">11.1 Build LoRaWAN Firmware</a><ul></ul></li>
|
||
<li><a href="#flash-lorawan-firmware" title="Flash LoRaWAN Firmware">11.2 Flash LoRaWAN Firmware</a><ul></ul></li>
|
||
<li><a href="#run-lorawan-firmware" title="Run LoRaWAN Firmware">11.3 Run LoRaWAN Firmware</a><ul></ul></li>
|
||
<li><a href="#enter-lorawan-commands" title="Enter LoRaWAN Commands">11.4 Enter LoRaWAN Commands</a><ul></ul></li></ul></li>
|
||
<li><a href="#appendix-porting-tinycbor-to-bl602" title="Appendix: Porting TinyCBOR to BL602">12 Appendix: Porting TinyCBOR to BL602</a><ul></ul></li></ul></nav><p>📝 <em>5 Oct 2021</em></p>
|
||
<p>Suppose we’re creating an IoT Gadget that transmits <strong>Sensor Data</strong> from a <strong>Temperature Sensor</strong> and a <strong>Light Sensor</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-json"><code>{
|
||
"t": 1234,
|
||
"l": 2345
|
||
}</code></pre></div>
|
||
<p>(Located in a Greenhouse perhaps)</p>
|
||
<p>And we’re transmitting over a <strong>low-power wireless network</strong> like LoRa, Zigbee or Bluetooth LE.</p>
|
||
<p>We could transmit <strong>19 bytes of JSON</strong>. But there’s a more compact way to do it….</p>
|
||
<p><a href="https://en.wikipedia.org/wiki/CBOR"><strong>Concise Binary Object Representation (CBOR)</strong></a>, which works like a binary, compressed form of JSON.</p>
|
||
<p>And we need only <strong>11 bytes of CBOR</strong>!</p>
|
||
<p><img src="https://lupyuen.github.io/images/cbor-title.jpg" alt="Encoding Sensor Data with CBOR on BL602" /></p>
|
||
<p>Today we’ll learn to encode Sensor Data with the <strong>TinyCBOR Library</strong> that we have ported to the <a href="https://lupyuen.github.io/articles/pinecone"><strong>BL602</strong></a> and <a href="https://lupyuen.github.io/articles/pinedio2"><strong>BL604</strong></a> RISC-V SoCs…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/tinycbor-bl602"><strong>lupyuen/tinycbor-bl602</strong></a></li>
|
||
</ul>
|
||
<p>The library has been tested on <a href="https://lupyuen.github.io/articles/pinedio2"><strong>PineDio Stack BL604</strong></a>, but it should work on <strong>any BL602 or BL604 Board</strong>: <a href="https://docs.ai-thinker.com/en/wb2"><strong>Ai-Thinker Ai-WB2</strong></a>, PineCone BL602, Pinenut, DT-BL10, MagicHome BL602, …</p>
|
||
<p><em>Must we scrimp and save every single byte?</em></p>
|
||
<p>Yes, <strong>every single byte matters</strong> for low-power wireless networks!</p>
|
||
<ol>
|
||
<li>
|
||
<p>Low-power wireless networks operate on Radio Frequency Bands that are <strong>shared with many other gadgets</strong>.</p>
|
||
<p>They are prone to <strong>collisions and interference</strong>.</p>
|
||
<p>The <strong>smaller the data packet</strong>, the higher the chance that it will be <strong>transmitted successfully</strong>!</p>
|
||
</li>
|
||
<li>
|
||
<p>When we transmit LoRa packets to <strong>The Things Network</strong> (the free public global LoRa network), we’re limited by their <a href="https://lupyuen.github.io/articles/ttn#fair-use-of-the-things-network"><strong>Fair Use Policy</strong></a>.</p>
|
||
<p><a href="https://lupyuen.github.io/articles/ttn#fair-use-of-the-things-network">(Roughly <strong>12 bytes</strong> per message, assuming 10 messages per hour)</a></p>
|
||
<p>JSON is too big for this. But CBOR works well!</p>
|
||
<p>In a while we’ll watch the TinyCBOR Library in action for encoding Sensor Data in The Things Network.</p>
|
||
</li>
|
||
</ol>
|
||
<h1 id="encode-sensor-data-with-tinycbor"><a class="doc-anchor" href="#encode-sensor-data-with-tinycbor">§</a>1 Encode Sensor Data with TinyCBOR</h1>
|
||
<p>We begin by encoding one data field into CBOR…</p>
|
||
<div class="example-wrap"><pre class="language-json"><code>{
|
||
"t": 1234
|
||
}</code></pre></div>
|
||
<p>We call this a <strong>CBOR Map</strong> that maps a <strong>Key</strong> (“<code>t</code>”) to a <strong>Value</strong> (<code>1234</code>)…</p>
|
||
<blockquote>
|
||
<p><img src="https://lupyuen.github.io/images/cbor-map.png" alt="CBOR Map with 1 Key-Value Pair" /></p>
|
||
</blockquote>
|
||
<p>Let’s look at the code from our firmware that encodes the above into CBOR…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/tree/master/customer_app/pinedio_cbor"><strong>pinedio_cbor Firmware</strong></a></li>
|
||
</ul>
|
||
<h2 id="output-buffer-and-cbor-encoder"><a class="doc-anchor" href="#output-buffer-and-cbor-encoder">§</a>1.1 Output Buffer and CBOR Encoder</h2>
|
||
<p>First we create an <strong>Output Buffer</strong> that will hold the encoded CBOR data: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/customer_app/pinedio_cbor/pinedio_cbor/demo.c#L9-L66">pinedio_cbor/demo.c</a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>/// Test CBOR Encoding for { "t": 1234 }
|
||
static void test_cbor(char *buf, int len, int argc, char **argv) {
|
||
|
||
// Max output size is 50 bytes (which fits in a LoRa packet)
|
||
uint8_t output[50];</code></pre></div>
|
||
<p><a href="https://lupyuen.github.io/articles/ttn#fair-use-of-the-things-network">(50 bytes is the max packet size for The Things Network AS923 DR2)</a></p>
|
||
<p><strong>Output Buffer Size</strong> is important: Calls to the <strong>TinyCBOR library will fail</strong> if we run out of buffer space!</p>
|
||
<p>Next we define the <strong>CBOR Encoder</strong> (from TinyCBOR) that will encode our data…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Our CBOR Encoder and Map Encoder
|
||
CborEncoder encoder, mapEncoder;</code></pre></div>
|
||
<p>As well as the <strong>Map Encoder</strong> that will encode our CBOR Map.</p>
|
||
<p>We <strong>initialise the CBOR Encoder</strong> like so…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Init our CBOR Encoder
|
||
cbor_encoder_init(
|
||
&encoder, // CBOR Encoder
|
||
output, // Output Buffer
|
||
sizeof(output), // Output Buffer Size
|
||
0 // Options (always 0)
|
||
);</code></pre></div><h2 id="create-map-encoder"><a class="doc-anchor" href="#create-map-encoder">§</a>1.2 Create Map Encoder</h2>
|
||
<p>Now we create the <strong>Map Encoder</strong> that will encode our CBOR Map…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Create a Map Encoder that maps keys to values
|
||
CborError res = cbor_encoder_create_map(
|
||
&encoder, // CBOR Encoder
|
||
&mapEncoder, // Map Encoder
|
||
1 // Number of Key-Value Pairs
|
||
);
|
||
assert(res == CborNoError);</code></pre></div>
|
||
<p>The last parameter (<code>1</code>) is important: It must match the <strong>Number of Key-Value Pairs</strong> (like <code>"t": 1234</code>) that we shall encode.</p>
|
||
<h2 id="encode-key-and-value"><a class="doc-anchor" href="#encode-key-and-value">§</a>1.3 Encode Key and Value</h2>
|
||
<p>We encode the <strong>Key</strong> (“<code>t</code>”) into the CBOR Map…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // First Key-Value Pair: Map the Key
|
||
res = cbor_encode_text_stringz(
|
||
&mapEncoder, // Map Encoder
|
||
"t" // Key
|
||
);
|
||
assert(res == CborNoError);</code></pre></div>
|
||
<p>Followed by the <strong>Value</strong> (<code>1234</code>)…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // First Key-Value Pair: Map the Value
|
||
res = cbor_encode_int(
|
||
&mapEncoder, // Map Encoder
|
||
1234 // Value
|
||
);
|
||
assert(res == CborNoError);</code></pre></div>
|
||
<p><strong>cbor_encode_int</strong> encodes <strong>64-bit Signed Integers</strong>.</p>
|
||
<p>(We’ll look at other data types in a while)</p>
|
||
<h2 id="close-map-encoder"><a class="doc-anchor" href="#close-map-encoder">§</a>1.4 Close Map Encoder</h2>
|
||
<p>We’re done with our CBOR Map, so we <strong>close the Map Encoder</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Close the Map Encoder
|
||
res = cbor_encoder_close_container(
|
||
&encoder, // CBOR Encoder
|
||
&mapEncoder // Map Encoder
|
||
);
|
||
assert(res == CborNoError);</code></pre></div>
|
||
<p>Our CBOR Encoding is complete!</p>
|
||
<h2 id="get-encoded-output"><a class="doc-anchor" href="#get-encoded-output">§</a>1.5 Get Encoded Output</h2>
|
||
<p>To work with the Encoded CBOR Output, we need to know <strong>how many bytes</strong> have been encoded…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // How many bytes were encoded
|
||
size_t output_len = cbor_encoder_get_buffer_size(
|
||
&encoder, // CBOR Encoder
|
||
output // Output Buffer
|
||
);
|
||
printf("CBOR Output: %d bytes\r\n", output_len);</code></pre></div>
|
||
<p>For the demo we <strong>dump the encoded CBOR data</strong> to the console…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Dump the encoded CBOR output (6 bytes):
|
||
// 0xa1 0x61 0x74 0x19 0x04 0xd2
|
||
for (int i = 0; i < output_len; i++) {
|
||
printf(" 0x%02x\r\n", output[i]);
|
||
}
|
||
}</code></pre></div>
|
||
<p>And that’s how we call the TinyCBOR Library to work with CBOR data!</p>
|
||
<p>Let’s watch what happens when we run the firmware…</p>
|
||
<blockquote>
|
||
<p><img src="https://lupyuen.github.io/images/cbor-code.png" alt="Calling the TinyCBOR Library" /></p>
|
||
</blockquote>
|
||
<h2 id="magic-happens"><a class="doc-anchor" href="#magic-happens">§</a>1.6 Magic Happens</h2>
|
||
<p>Follow the steps in the Appendix to <strong>build, flash and run</strong> the CBOR Firmware…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/cbor#appendix-build-and-run-cbor-firmware"><strong>“Build and Run CBOR Firmware”</strong></a></li>
|
||
</ul>
|
||
<p>At the BL602 / BL604 Command Prompt, enter…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>test_cbor</code></pre></div>
|
||
<p>We’ll see 6 bytes of <strong>Encoded CBOR Output</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>CBOR Output: 6 bytes
|
||
0xa1
|
||
0x61
|
||
0x74
|
||
0x19
|
||
0x04
|
||
0xd2</code></pre></div>
|
||
<p>We have just compressed <strong>10 bytes of JSON</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-json"><code>{
|
||
"t": 1234
|
||
}</code></pre></div>
|
||
<p>Into <strong>6 bytes of CBOR</strong>.</p>
|
||
<p>We have scrimped and saved <strong>4 bytes</strong>!</p>
|
||
<p><img src="https://lupyuen.github.io/images/cbor-output2.png" alt="Encoded CBOR Output" /></p>
|
||
<h1 id="add-another-field"><a class="doc-anchor" href="#add-another-field">§</a>2 Add Another Field</h1>
|
||
<p>Now we <strong>add another field</strong> to our CBOR Encoding…</p>
|
||
<div class="example-wrap"><pre class="language-json"><code>{
|
||
"t": 1234,
|
||
"l": 2345
|
||
}</code></pre></div>
|
||
<p>And watch how our program changes to accommodate the second field.</p>
|
||
<blockquote>
|
||
<p><img src="https://lupyuen.github.io/images/cbor-map2.png" alt="CBOR Map with 2 Key-Value Pairs" /></p>
|
||
</blockquote>
|
||
<h2 id="modify-map-encoder"><a class="doc-anchor" href="#modify-map-encoder">§</a>2.1 Modify Map Encoder</h2>
|
||
<p>We begin the same way as before: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/customer_app/pinedio_cbor/pinedio_cbor/demo.c#L68-L139">pinedio_cbor/demo.c</a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>/// Test CBOR Encoding for { "t": 1234, "l": 2345 }
|
||
static void test_cbor2( ... ) {
|
||
|
||
// Max output size is 50 bytes (which fits in a LoRa packet)
|
||
uint8_t output[50];
|
||
|
||
// Our CBOR Encoder and Map Encoder
|
||
CborEncoder encoder, mapEncoder;
|
||
|
||
// Init our CBOR Encoder
|
||
cbor_encoder_init( ... );</code></pre></div>
|
||
<p>Now we <strong>create the Map Encoder</strong> with a tiny modification…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Create a Map Encoder that maps keys to values
|
||
CborError res = cbor_encoder_create_map(
|
||
&encoder, // CBOR Encoder
|
||
&mapEncoder, // Map Encoder
|
||
2 // Number of Key-Value Pairs
|
||
);
|
||
assert(res == CborNoError);</code></pre></div>
|
||
<p>We changed the <strong>Number of Key-Value Pairs</strong> to <code>2</code>.</p>
|
||
<p>(Previously it was <code>1</code>)</p>
|
||
<h2 id="encode-first-key-and-value"><a class="doc-anchor" href="#encode-first-key-and-value">§</a>2.2 Encode First Key and Value</h2>
|
||
<p>We encode the <strong>First Key and Value</strong> the same way as before…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // First Key-Value Pair: Map the Key
|
||
res = cbor_encode_text_stringz(
|
||
&mapEncoder, // Map Encoder
|
||
"t" // Key
|
||
);
|
||
assert(res == CborNoError);
|
||
|
||
// First Key-Value Pair: Map the Value
|
||
res = cbor_encode_int(
|
||
&mapEncoder, // Map Encoder
|
||
1234 // Value
|
||
);
|
||
assert(res == CborNoError);</code></pre></div>
|
||
<p>(Yep no changes above)</p>
|
||
<h2 id="encode-second-key-and-value"><a class="doc-anchor" href="#encode-second-key-and-value">§</a>2.3 Encode Second Key and Value</h2>
|
||
<p>This part is new: We encode the <strong>Second Key and Value</strong> (“<code>l</code>” and <code>2345</code>)…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Second Key-Value Pair: Map the Key
|
||
res = cbor_encode_text_stringz(
|
||
&mapEncoder, // Map Encoder
|
||
"l" // Key
|
||
);
|
||
assert(res == CborNoError);
|
||
|
||
// Second Key-Value Pair: Map the Value
|
||
res = cbor_encode_int(
|
||
&mapEncoder, // Map Encoder
|
||
2345 // Value
|
||
);
|
||
assert(res == CborNoError);</code></pre></div>
|
||
<p>And the rest of the code is the same…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Close the Map Encoder
|
||
res = cbor_encoder_close_container( ... );
|
||
|
||
// How many bytes were encoded
|
||
size_t output_len = cbor_encoder_get_buffer_size( ... );
|
||
|
||
// Dump the encoded CBOR output (11 bytes):
|
||
// 0xa2 0x61 0x74 0x19 0x04 0xd2 0x61 0x6c 0x19 0x09 0x29
|
||
for (int i = 0; i < output_len; i++) {
|
||
printf(" 0x%02x\r\n", output[i]);
|
||
}
|
||
}</code></pre></div>
|
||
<p>Recap: To add a data field to our CBOR Encoding, we…</p>
|
||
<ol>
|
||
<li>
|
||
<p>Modify the call to <strong>cbor_encoder_create_map</strong> and update the <strong>Number of Key-Value Pairs</strong> (<code>2</code>)</p>
|
||
</li>
|
||
<li>
|
||
<p>Add the new <strong>Key and Value</strong> (“<code>l</code>” and <code>2345</code>) to the CBOR Map</p>
|
||
</li>
|
||
</ol>
|
||
<p>Everything else stays the same.</p>
|
||
<blockquote>
|
||
<p><img src="https://lupyuen.github.io/images/cbor-code2.png" alt="Add a second field" /></p>
|
||
</blockquote>
|
||
<h2 id="watch-the-magic"><a class="doc-anchor" href="#watch-the-magic">§</a>2.4 Watch the Magic</h2>
|
||
<p>Follow the steps in the Appendix to <strong>build, flash and run</strong> the CBOR Firmware…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/cbor#appendix-build-and-run-cbor-firmware"><strong>“Build and Run CBOR Firmware”</strong></a></li>
|
||
</ul>
|
||
<p>At the BL602 / BL604 Command Prompt, enter…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>test_cbor2</code></pre></div>
|
||
<p>This time we’ll see 11 bytes of <strong>Encoded CBOR Output</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>CBOR Output: 11 bytes
|
||
0xa2
|
||
0x61
|
||
0x74
|
||
0x19
|
||
0x04
|
||
0xd2
|
||
0x61
|
||
0x6c
|
||
0x19
|
||
0x09
|
||
0x29</code></pre></div>
|
||
<p>We have just compressed <strong>19 bytes of JSON</strong> into <strong>11 bytes of CBOR</strong>.</p>
|
||
<p><strong>8 bytes</strong> saved!</p>
|
||
<p>If we wish to call TinyCBOR from an existing BL602 / BL604 project, check the Appendix…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/cbor#appendix-add-tinycbor-to-your-project"><strong>“Add TinyCBOR to Your Project”</strong></a></li>
|
||
</ul>
|
||
<p><img src="https://lupyuen.github.io/images/cbor-title.jpg" alt="Encoding Sensor Data with CBOR on BL602" /></p>
|
||
<h1 id="cbor-data-types"><a class="doc-anchor" href="#cbor-data-types">§</a>3 CBOR Data Types</h1>
|
||
<p><em>We’ve been encoding 64-bit Signed Integers. What other Data Types can we encode?</em></p>
|
||
<p>Below are the <strong>CBOR Data Types</strong> and their respective <strong>Encoder Functions</strong> from the TinyCBOR Library…</p>
|
||
<h2 id="numbers"><a class="doc-anchor" href="#numbers">§</a>3.1 Numbers</h2>
|
||
<ul>
|
||
<li>
|
||
<p><strong>Signed Integer</strong> (64 bits): <a href="https://intel.github.io/tinycbor/current/a00046.html#gabbf6e10fd963d673f5ad293dff4a67a9">cbor_encode_int</a></p>
|
||
<p>(We called this earlier. Works for positive and negative integers)</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Unsigned Integer</strong> (64 bits): <a href="https://intel.github.io/tinycbor/current/a00046.html#ga2b898ce6f5821c5aba8b6f0020c4b5ba">cbor_encode_uint</a></p>
|
||
<p>(Positive integers only)</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Negative Integer</strong> (64 bits): <a href="https://intel.github.io/tinycbor/current/a00046.html#ga0e84daa854e0480f4a3758bcb46b9b60">cbor_encode_negative_int</a></p>
|
||
<p>(Negative integers only)</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Floating-Point Number</strong> (16, 32 or 64 bits):</p>
|
||
<p>(See the next chapter)</p>
|
||
</li>
|
||
</ul>
|
||
<h2 id="strings"><a class="doc-anchor" href="#strings">§</a>3.2 Strings</h2>
|
||
<ul>
|
||
<li>
|
||
<p><strong>Null-Terminated String</strong>: <a href="https://intel.github.io/tinycbor/current/a00046.html#ga6df3eff486535322f66584dc5431f9e9">cbor_encode_text_stringz</a></p>
|
||
<p>(We called this earlier to encode our Keys)</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Text String</strong>: <a href="https://intel.github.io/tinycbor/current/a00046.html#ga4fa673c63e85b1fd6f8067aca4ccdde4">cbor_encode_text_string</a></p>
|
||
<p>(For strings that are not null-terminated)</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Byte String</strong>: <a href="https://intel.github.io/tinycbor/current/a00046.html#ga1260b72bb0f067fd3c68d49a6b5f58d0">cbor_encode_byte_string</a></p>
|
||
<p>(For strings containing binary data)</p>
|
||
</li>
|
||
</ul>
|
||
<h2 id="other-types"><a class="doc-anchor" href="#other-types">§</a>3.3 Other Types</h2>
|
||
<ul>
|
||
<li>
|
||
<p><strong>Boolean</strong>: <a href="https://intel.github.io/tinycbor/current/a00046.html#ga857154b97cad978f4afb3e2f809051bd">cbor_encode_boolean</a></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Null</strong>: <a href="https://intel.github.io/tinycbor/current/a00046.html#ga30b769ff1da73ed8b4536f551347c5ed">cbor_encode_null</a></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Undefined</strong>: <a href="https://intel.github.io/tinycbor/current/a00046.html#ga9d9f0668e2cf69352a45095006efab4f">cbor_encode_undefined</a></p>
|
||
</li>
|
||
</ul>
|
||
<p>For the complete list of CBOR Encoder Functions, refer to the TinyCBOR docs…</p>
|
||
<ul>
|
||
<li><a href="https://intel.github.io/tinycbor/current/a00046.html"><strong>TinyCBOR: Encoding To CBOR</strong></a></li>
|
||
</ul>
|
||
<p>CBOR Data Types are explained in the CBOR Specification…</p>
|
||
<ul>
|
||
<li><a href="https://www.rfc-editor.org/rfc/rfc8949.html#name-cbor-data-models"><strong>CBOR Data Models</strong></a></li>
|
||
</ul>
|
||
<p>To experiment with CBOR Encoding and Decoding, try the <a href="http://cbor.me/"><strong>CBOR Playground</strong></a>…</p>
|
||
<p><img src="https://lupyuen.github.io/images/grafana-cbor5.png" alt="CBOR Playground" /></p>
|
||
<h1 id="floating-point-numbers"><a class="doc-anchor" href="#floating-point-numbers">§</a>4 Floating-Point Numbers</h1>
|
||
<p>The CBOR spec says that there are <a href="https://www.rfc-editor.org/rfc/rfc8949.html#name-floating-point-numbers-and-"><strong>3 ways to encode floats</strong></a>…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://en.m.wikipedia.org/wiki/Half-precision_floating-point_format"><strong>Half-Precision Float</strong></a> (16 bits): <a href="https://intel.github.io/tinycbor/current/a00046.html#gad8e5a125cfaceb9a32528e620e003bc6">cbor_encode_half_float</a></p>
|
||
<p>(<strong>3.3</strong> significant decimal digits. <a href="https://en.m.wikipedia.org/wiki/Half-precision_floating-point_format#IEEE_754_half-precision_binary_floating-point_format:_binary16">See this</a>)</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://en.m.wikipedia.org/wiki/Single-precision_floating-point_format"><strong>Single-Precision Float</strong></a> (32 bits): <a href="https://intel.github.io/tinycbor/current/a00046.html#gae981ee934ef22ce4c5b52f8069e1b15c">cbor_encode_float</a></p>
|
||
<p>(<strong>6 to 9</strong> significant decimal digits. <a href="https://en.m.wikipedia.org/wiki/Single-precision_floating-point_format#IEEE_754_single-precision_binary_floating-point_format:_binary32">See this</a>)</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://en.m.wikipedia.org/wiki/Double-precision_floating-point_format"><strong>Double-Precision Float</strong></a> (64 bits): <a href="https://intel.github.io/tinycbor/current/a00046.html#ga211aa80dc5b793ee8dd74d24cb9e7ca6">cbor_encode_double</a></p>
|
||
<p>(<strong>15 to 17</strong> significant decimal digits. <a href="https://en.m.wikipedia.org/wiki/Double-precision_floating-point_format#IEEE_754_double-precision_binary_floating-point_format:_binary64">See this</a>)</p>
|
||
</li>
|
||
</ul>
|
||
<p><em>How do we select the proper float encoding?</em></p>
|
||
<p>Suppose we’re encoding Temperature Data (like <code>12.34</code> ºC) that could range from <strong><code>0.00</code> ºC to <code>99.99</code> ºC</strong>.</p>
|
||
<p>This means that we need <strong>4 significant decimal digits</strong>.</p>
|
||
<p>Which is too many for a Half-Precision Float (16 bits), but OK for a <strong>Single-Precision Float</strong> (32 bits).</p>
|
||
<p>Thus we need <strong>5 bytes</strong> to encode the Temperature Data. (Including the CBOR Initial Byte)</p>
|
||
<h2 id="encode-floats-as-integers"><a class="doc-anchor" href="#encode-floats-as-integers">§</a>4.1 Encode Floats as Integers</h2>
|
||
<p><em>Huh? If we encode an integer like <code>1234</code>, we need only <strong>3 bytes</strong>!</em></p>
|
||
<p>That’s why in this article we <strong>scale up 100 times</strong> for the Temperature Data and <strong>encode as an integer</strong> instead.</p>
|
||
<p>(So <code>1234</code> actually means <code>12.34</code> ºC)</p>
|
||
<p><strong>2 bytes</strong> saved!</p>
|
||
<p>(Our scaling of Sensor Data is similar to <a href="https://en.wikipedia.org/wiki/Fixed-point_arithmetic#Fixed-point_representation">Fixed-Point Representation</a>)</p>
|
||
<h2 id="accuracy-and-precision"><a class="doc-anchor" href="#accuracy-and-precision">§</a>4.2 Accuracy and Precision</h2>
|
||
<p><em>Is it meaningful to record temperatures that are accurate to 0.01 ºC?</em></p>
|
||
<p><em>How much accuracy do we need for Sensor Data anyway?</em></p>
|
||
<p>The accuracy for our Sensor Data depends on…</p>
|
||
<ol>
|
||
<li>
|
||
<p>Our monitoring requirements, and</p>
|
||
</li>
|
||
<li>
|
||
<p>Accuracy of our sensors</p>
|
||
</li>
|
||
</ol>
|
||
<p>Learn more about Accuracy and Precision of Sensor Data…</p>
|
||
<ul>
|
||
<li><a href="https://kotahi.net/iots-lesser-known-power-good-enough-data-accuracy/">IoT’s Lesser Known Power: “Good Enough” Data Accuracy</a></li>
|
||
</ul>
|
||
<p><img src="https://lupyuen.github.io/images/ttn-title.jpg" alt="PineDio Stack BL604 RISC-V Board (foreground) talking to The Things Network via RAKWireless RAK7248 LoRaWAN Gateway (background)" /></p>
|
||
<p><em>PineDio Stack BL604 RISC-V Board (foreground) talking to The Things Network via RAKWireless RAK7248 LoRaWAN Gateway (background)</em></p>
|
||
<h1 id="lorawan-with-cbor"><a class="doc-anchor" href="#lorawan-with-cbor">§</a>5 LoRaWAN With CBOR</h1>
|
||
<p>Let’s watch CBOR in action on a real wireless network… As <a href="https://lupyuen.github.io/articles/lorawan2"><strong>PineDio Stack BL604</strong></a> talks to <a href="https://lupyuen.github.io/articles/ttn"><strong>The Things Network over LoRaWAN</strong></a>!</p>
|
||
<p>In a while we shall run this LoRaWAN Command…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>las_app_tx_cbor 2 0 1234 2345</code></pre></div>
|
||
<p>This means…</p>
|
||
<ul>
|
||
<li>
|
||
<p>Transmit a LoRaWAN Packet to <strong>Port 2</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>That contains the values <strong><code>t=1234</code></strong> (Temperature), <strong><code>l=2345</code></strong> (Light Level)</p>
|
||
</li>
|
||
<li>
|
||
<p><code>0</code> means that this is an <strong>Unconfirmed Message</strong></p>
|
||
<p>(Because we’re not expecting an acknowledgement)</p>
|
||
</li>
|
||
</ul>
|
||
<p>Our CBOR Encoding happens inside the <strong>las_app_tx_cbor</strong> function: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/customer_app/pinedio_lorawan/pinedio_lorawan/lorawan.c#L893-L1050">pinedio_lorawan/lorawan.c</a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>/// Transmit CBOR payload to LoRaWAN. The command
|
||
/// las_app_tx_cbor 2 0 1234 2345
|
||
/// Will transmit the CBOR payload
|
||
/// { "t": 1234, "l": 2345 }
|
||
/// To port 2, unconfirmed (0).
|
||
void las_cmd_app_tx_cbor( ... ) {
|
||
...
|
||
// Get the "t" value from command args
|
||
uint16_t t = parse_ull_bounds(argv[3], 0, 65535, &rc);
|
||
|
||
// Get the "l" value from command args
|
||
uint16_t l = parse_ull_bounds(argv[4], 0, 65535, &rc);</code></pre></div>
|
||
<p>In the code above we get the values of <strong>“<code>t</code>”</strong> (Temperature Sensor) and <strong>“<code>l</code>”</strong> (Light Sensor) from the command line arguments.</p>
|
||
<p>(Our sensors are simulated for now)</p>
|
||
<p>Watch how we encode “<code>t</code>” and “<code>l</code>” and transmit them…</p>
|
||
<h2 id="encode-sensor-data"><a class="doc-anchor" href="#encode-sensor-data">§</a>5.1 Encode Sensor Data</h2>
|
||
<p>This part looks super familiar: We initialise our <strong>CBOR Encoder and Map Encoder</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Encode into CBOR for { "t": ????, "l": ???? }
|
||
// Max output size is 50 bytes (which fits in a LoRa packet)
|
||
uint8_t output[50];
|
||
|
||
// Our CBOR Encoder and Map Encoder
|
||
CborEncoder encoder, mapEncoder;
|
||
|
||
// Init our CBOR Encoder
|
||
cbor_encoder_init( ... );
|
||
|
||
// Create a Map Encoder that maps keys to values (2 pairs)
|
||
CborError res = cbor_encoder_create_map( ... );</code></pre></div>
|
||
<p>Next we encode the <strong>Key and Value for “<code>t</code>”</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // First Key-Value Pair: Map the Key ("t")
|
||
res = cbor_encode_text_stringz(
|
||
&mapEncoder, // Map Encoder
|
||
"t" // Key
|
||
);
|
||
assert(res == CborNoError);
|
||
|
||
// First Key-Value Pair: Map the Value
|
||
res = cbor_encode_int(
|
||
&mapEncoder, // Map Encoder
|
||
t // Value
|
||
);
|
||
assert(res == CborNoError);</code></pre></div>
|
||
<p>Then we encode the <strong>Key and Value for “<code>l</code>”</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Second Key-Value Pair: Map the Key ("l")
|
||
res = cbor_encode_text_stringz(
|
||
&mapEncoder, // Map Encoder
|
||
"l" // Key
|
||
);
|
||
assert(res == CborNoError);
|
||
|
||
// Second Key-Value Pair: Map the Value
|
||
res = cbor_encode_int(
|
||
&mapEncoder, // Map Encoder
|
||
l // Value
|
||
);
|
||
assert(res == CborNoError);</code></pre></div>
|
||
<p>And we <strong>close the Map Encoder</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Close the Map Encoder
|
||
res = cbor_encoder_close_container( ... );
|
||
|
||
// How many bytes were encoded
|
||
size_t output_len = cbor_encoder_get_buffer_size( ... );</code></pre></div><h2 id="send-lorawan-packet"><a class="doc-anchor" href="#send-lorawan-packet">§</a>5.2 Send LoRaWAN Packet</h2>
|
||
<p>We’re ready to transmit our encoded Sensor Data!</p>
|
||
<p>First we <strong>allocate a Packet Buffer</strong> for our LoRaWAN Packet…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Validate the output size
|
||
if (lora_app_mtu() < output_len) { return; } // Output too big
|
||
|
||
// Attempt to allocate a Packet Buffer
|
||
struct pbuf *om = lora_pkt_alloc(output_len);
|
||
if (!om) { return; } // Unable to allocate Packet Buffer</code></pre></div>
|
||
<p>Next we <strong>copy our encoded Sensor Data</strong> into the Packet Buffer…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Copy the encoded CBOR into the Packet Buffer
|
||
rc = pbuf_copyinto(om, 0, output, output_len);
|
||
assert(rc == 0);</code></pre></div>
|
||
<p>Finally we <strong>transmit the Packet Buffer</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code> // Send the Packet Buffer
|
||
rc = lora_app_port_send(port, mcps_type, om);
|
||
|
||
// Omitted: Check the return code</code></pre></div>
|
||
<p>That’s how we encode Sensor Data and transmit over LoRaWAN!</p>
|
||
<p><img src="https://lupyuen.github.io/images/cbor-code3.png" alt="Encoding Sensor Data and transmitting over LoRaWAN" /></p>
|
||
<h2 id="cbor-in-action"><a class="doc-anchor" href="#cbor-in-action">§</a>5.3 CBOR In Action</h2>
|
||
<p>Follow the instructions in the Appendix to <strong>build, flash and run</strong> the LoRaWAN Firmware…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/cbor#appendix-build-and-run-lorawan-firmware"><strong>“Build and Run LoRaWAN Firmware”</strong></a></li>
|
||
</ul>
|
||
<p>At the BL602 / BL604 Command Prompt, enter this command…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>las_app_tx_cbor 2 0 1234 2345</code></pre></div>
|
||
<p>This means…</p>
|
||
<ul>
|
||
<li>
|
||
<p>Transmit a LoRaWAN Packet to <strong>Port 2</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>That contains the values <strong><code>t=1234</code></strong> (Temperature), <strong><code>l=2345</code></strong> (Light Level)</p>
|
||
</li>
|
||
<li>
|
||
<p><code>0</code> means that this is an <strong>Unconfirmed Message</strong></p>
|
||
<p>(Because we’re not expecting an acknowledgement)</p>
|
||
</li>
|
||
</ul>
|
||
<p>Our Sensor Data has been transmitted via LoRaWAN to The Things Network!</p>
|
||
<p><em>How do we see the Sensor Data in The Things Network?</em></p>
|
||
<p>We could use <strong>Grafana</strong>, the open source tool for data visualisation…</p>
|
||
<p><img src="https://lupyuen.github.io/images/cbor-grafana.jpg" alt="Sensor Data visualised with Grafana" /></p>
|
||
<p>Check out this article for the details…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/grafana"><strong>“Grafana Data Source for The Things Network”</strong></a></li>
|
||
</ul>
|
||
<p>See also this demo of PineDio Stack with Roblox and The Things Network…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/roblox#digital-twin-demo"><strong>“IoT Digital Twin with Roblox and The Things Network”</strong></a></li>
|
||
</ul>
|
||
<h1 id="decode-cbor"><a class="doc-anchor" href="#decode-cbor">§</a>6 Decode CBOR</h1>
|
||
<p><em>For decoding CBOR packets, can we call the TinyCBOR Library?</em></p>
|
||
<p>Sure, we can call the <strong>Decoder Functions</strong> in the TinyCBOR Library…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://intel.github.io/tinycbor/current/a00047.html"><strong>TinyCBOR: Parsing CBOR streams</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://intel.github.io/tinycbor/current/a00048.html"><strong>TinyCBOR: Converting CBOR to text</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://intel.github.io/tinycbor/current/a00049.html"><strong>TinyCBOR: Converting CBOR to JSON</strong></a></p>
|
||
</li>
|
||
</ul>
|
||
<p>If we’re transmitting CBOR packets to a server (or cloud), we can decode them with a <strong>CBOR Library for Node.js, Go, Rust,</strong> …</p>
|
||
<ul>
|
||
<li><a href="https://cbor.io/impls.html"><strong>CBOR Implementations</strong></a></li>
|
||
</ul>
|
||
<p>We can decode CBOR Payloads in <strong>The Things Network</strong> with a CBOR Payload Formatter…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/payload"><strong>“CBOR Payload Formatter for The Things Network”</strong></a></li>
|
||
</ul>
|
||
<p>For Grafana we used a <strong>Go Library for CBOR</strong>…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/grafana#decode-cbor-in-go"><strong>“Decode CBOR in Go”</strong></a></li>
|
||
</ul>
|
||
<p>There’s even a CBOR Library for <strong>Roblox and Lua Scripting</strong>…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/roblox-the-things-network#decode-base64-and-cbor-in-roblox"><strong>“Decode Base64 and CBOR in Roblox”</strong></a></li>
|
||
</ul>
|
||
<p>TinyCBOR is available on various <strong>Embedded Operating Systems</strong>…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/apache/mynewt-core/tree/master/encoding/tinycbor"><strong>Apache Mynewt</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://doc.riot-os.org/group__pkg__tinycbor.html"><strong>RIOT</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://docs.zephyrproject.org/latest/reference/kconfig/CONFIG_TINYCBOR.html"><strong>Zephyr</strong></a></p>
|
||
</li>
|
||
</ul>
|
||
<h1 id="whats-next"><a class="doc-anchor" href="#whats-next">§</a>7 What’s Next</h1>
|
||
<p>For the next article we shall take a quick detour and explore PineDio Stack transmitting Sensor Data to <a href="https://github.com/lupyuen/roblox-the-things-network"><strong>Roblox via The Things Network</strong></a>.</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/roblox"><strong>“IoT Digital Twin with Roblox and The Things Network”</strong></a></li>
|
||
</ul>
|
||
<p>Then we shall head back and transmit BL602 / BL604’s <strong>Internal Temperature Sensor Data</strong> to The Things Network.</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/tsen"><strong>“Internal Temperature Sensor on BL602”</strong></a></li>
|
||
</ul>
|
||
<p>Many Thanks to my <a href="https://lupyuen.github.io/articles/sponsor"><strong>GitHub Sponsors</strong></a> for supporting my work! This article wouldn’t have been possible without your support.</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/sponsor">Sponsor me a coffee</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://www.reddit.com/r/RISCV/comments/q1ir5x/encode_sensor_data_with_cbor_on_bl602/">Discuss this article on Reddit</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/book">Read “The RISC-V BL602 / BL604 Book”</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io">Check out my articles</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/rss.xml">RSS Feed</a></p>
|
||
</li>
|
||
</ul>
|
||
<p><em>Got a question, comment or suggestion? Create an Issue or submit a Pull Request here…</em></p>
|
||
<p><a href="https://github.com/lupyuen/lupyuen.github.io/blob/master/src/cbor.md"><code>lupyuen.github.io/src/cbor.md</code></a></p>
|
||
<h1 id="notes"><a class="doc-anchor" href="#notes">§</a>8 Notes</h1>
|
||
<ol>
|
||
<li>This article is the expanded version of <a href="https://twitter.com/MisterTechBlog/status/1441626008931602433">this Twitter Thread</a></li>
|
||
</ol>
|
||
<h1 id="appendix-build-and-run-cbor-firmware"><a class="doc-anchor" href="#appendix-build-and-run-cbor-firmware">§</a>9 Appendix: Build and Run CBOR Firmware</h1>
|
||
<p>Here are the steps to build, flash and run the <strong>CBOR Firmware for BL602 and BL604</strong>…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/tree/master/customer_app/pinedio_cbor"><strong>bl_iot_sdk/customer_app/pinedio_cbor</strong></a></li>
|
||
</ul>
|
||
<p>(If we wish to add the TinyCBOR Library to an existing BL602 / BL604 project, check the next chapter)</p>
|
||
<h2 id="build-cbor-firmware"><a class="doc-anchor" href="#build-cbor-firmware">§</a>9.1 Build CBOR Firmware</h2>
|
||
<p>Download the firmware…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Download the master branch of lupyuen's bl_iot_sdk
|
||
git clone --recursive --branch master https://github.com/lupyuen/bl_iot_sdk</code></pre></div>
|
||
<p>Build the Firmware Binary File <code>pinedio_cbor.bin</code>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## TODO: Change this to the full path of bl_iot_sdk
|
||
export BL60X_SDK_PATH=$HOME/bl_iot_sdk
|
||
export CONFIG_CHIP_NAME=BL602
|
||
|
||
cd bl_iot_sdk/customer_app/pinedio_cbor
|
||
make
|
||
|
||
## For WSL: Copy the firmware to /mnt/c/blflash, which refers to c:\blflash in Windows
|
||
mkdir /mnt/c/blflash
|
||
cp build_out/pinedio_cbor.bin /mnt/c/blflash</code></pre></div>
|
||
<p><a href="https://lupyuen.github.io/articles/pinecone#building-firmware">More details on building bl_iot_sdk</a></p>
|
||
<h2 id="flash-cbor-firmware"><a class="doc-anchor" href="#flash-cbor-firmware">§</a>9.2 Flash CBOR Firmware</h2>
|
||
<p>Follow these steps to install <code>blflash</code>…</p>
|
||
<ol>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/flash#install-rustup"><strong>“Install rustup”</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/flash#download-and-build-blflash"><strong>“Download and build blflash”</strong></a></p>
|
||
</li>
|
||
</ol>
|
||
<p>We assume that our Firmware Binary File <code>pinedio_cbor.bin</code> has been copied to the <code>blflash</code> folder.</p>
|
||
<p>Set BL602 / BL604 to <strong>Flashing Mode</strong> and restart the board…</p>
|
||
<p><strong>For PineDio Stack BL604:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Set the <strong>GPIO 8 Jumper</strong> to <strong>High</strong> <a href="https://lupyuen.github.io/images/pinedio-high.jpg">(Like this)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Disconnect the USB cable and reconnect</p>
|
||
<p>Or use the Improvised Reset Button <a href="https://lupyuen.github.io/articles/pinedio#appendix-improvised-reset-button-for-pinedio-stack">(Here’s how)</a></p>
|
||
</li>
|
||
</ol>
|
||
<p><strong>For PineCone BL602:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Set the <strong>PineCone Jumper (IO 8)</strong> to the <strong><code>H</code> Position</strong> <a href="https://lupyuen.github.io/images/pinecone-jumperh.jpg">(Like this)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Press the Reset Button</p>
|
||
</li>
|
||
</ol>
|
||
<p><strong>For BL10:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Connect BL10 to the USB port</p>
|
||
</li>
|
||
<li>
|
||
<p>Press and hold the <strong>D8 Button (GPIO 8)</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Press and release the <strong>EN Button (Reset)</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Release the D8 Button</p>
|
||
</li>
|
||
</ol>
|
||
<p><strong>For <a href="https://docs.ai-thinker.com/en/wb2">Ai-Thinker Ai-WB2</a>, Pinenut and MagicHome BL602:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Disconnect the board from the USB Port</p>
|
||
</li>
|
||
<li>
|
||
<p>Connect <strong>GPIO 8</strong> to <strong>3.3V</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Reconnect the board to the USB port</p>
|
||
</li>
|
||
</ol>
|
||
<p>Enter these commands to flash <code>pinedio_cbor.bin</code> to BL602 / BL604 over UART…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## For Linux:
|
||
blflash flash build_out/pinedio_cbor.bin \
|
||
--port /dev/ttyUSB0
|
||
|
||
## For macOS:
|
||
blflash flash build_out/pinedio_cbor.bin \
|
||
--port /dev/tty.usbserial-1420 \
|
||
--initial-baud-rate 230400 \
|
||
--baud-rate 230400
|
||
|
||
## For Windows: Change COM5 to the BL602 / BL604 Serial Port
|
||
blflash flash c:\blflash\pinedio_cbor.bin --port COM5</code></pre></div>
|
||
<p>(For WSL: Do this under plain old Windows CMD, not WSL, because blflash needs to access the COM port)</p>
|
||
<p><a href="https://lupyuen.github.io/articles/flash#flash-the-firmware">More details on flashing firmware</a></p>
|
||
<h2 id="run-cbor-firmware"><a class="doc-anchor" href="#run-cbor-firmware">§</a>9.3 Run CBOR Firmware</h2>
|
||
<p>Set BL602 / BL604 to <strong>Normal Mode</strong> (Non-Flashing) and restart the board…</p>
|
||
<p><strong>For PineDio Stack BL604:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Set the <strong>GPIO 8 Jumper</strong> to <strong>Low</strong> <a href="https://lupyuen.github.io/images/pinedio-low.jpg">(Like this)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Disconnect the USB cable and reconnect</p>
|
||
<p>Or use the Improvised Reset Button <a href="https://lupyuen.github.io/articles/pinedio#appendix-improvised-reset-button-for-pinedio-stack">(Here’s how)</a></p>
|
||
</li>
|
||
</ol>
|
||
<p><strong>For PineCone BL602:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Set the <strong>PineCone Jumper (IO 8)</strong> to the <strong><code>L</code> Position</strong> <a href="https://lupyuen.github.io/images/pinecone-jumperl.jpg">(Like this)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Press the Reset Button</p>
|
||
</li>
|
||
</ol>
|
||
<p><strong>For BL10:</strong></p>
|
||
<ol>
|
||
<li>Press and release the <strong>EN Button (Reset)</strong></li>
|
||
</ol>
|
||
<p><strong>For <a href="https://docs.ai-thinker.com/en/wb2">Ai-Thinker Ai-WB2</a>, Pinenut and MagicHome BL602:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Disconnect the board from the USB Port</p>
|
||
</li>
|
||
<li>
|
||
<p>Connect <strong>GPIO 8</strong> to <strong>GND</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Reconnect the board to the USB port</p>
|
||
</li>
|
||
</ol>
|
||
<p>After restarting, connect to BL602 / BL604’s UART Port at 2 Mbps like so…</p>
|
||
<p><strong>For Linux:</strong></p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>screen /dev/ttyUSB0 2000000</code></pre></div>
|
||
<p><strong>For macOS:</strong> Use CoolTerm (<a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
|
||
<p><strong>For Windows:</strong> Use <code>putty</code> (<a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
|
||
<p><strong>Alternatively:</strong> Use the Web Serial Terminal (<a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
|
||
<p><a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">More details on connecting to BL602 / BL604</a></p>
|
||
<h1 id="appendix-add-tinycbor-to-your-project"><a class="doc-anchor" href="#appendix-add-tinycbor-to-your-project">§</a>10 Appendix: Add TinyCBOR to Your Project</h1>
|
||
<p>Here are the steps for <strong>adding the TinyCBOR Library</strong> to an existing BL602 or BL604 project…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/tinycbor-bl602"><strong>lupyuen/tinycbor-bl602</strong></a></li>
|
||
</ul>
|
||
<p>We assume there’s an existing <strong>bl_iot_sdk</strong> folder.</p>
|
||
<p>Add <strong>tinycbor-bl602</strong> as a submodule under <strong>bl_iot_sdk/components/3rdparty</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>cd bl_iot_sdk/components/3rdparty
|
||
git submodule add https://github.com/lupyuen/tinycbor-bl602</code></pre></div>
|
||
<p>Edit the <strong>Makefile</strong> for our project…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>## Insert this line into the COMPONENTS block
|
||
COMPONENTS_TINYCBOR := tinycbor-bl602
|
||
...
|
||
|
||
## Insert this line into INCLUDE_COMPONENTS block
|
||
INCLUDE_COMPONENTS += $(COMPONENTS_TINYCBOR)
|
||
...
|
||
|
||
## This should appear after INCLUDE_COMPONENTS block
|
||
include $(BL60X_SDK_PATH)/make_scripts_riscv/project.mk</code></pre></div>
|
||
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/customer_app/pinedio_cbor/Makefile#L21-L36">(See a sample Makefile)</a></p>
|
||
<p>Include <strong>“cbor.h”</strong> in our source file…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code>##include "cbor.h" // For Tiny CBOR Library</code></pre></div>
|
||
<p>And start coding with TinyCBOR!</p>
|
||
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/customer_app/pinedio_cbor/pinedio_cbor/demo.c">(See a sample source file)</a></p>
|
||
<h1 id="appendix-build-and-run-lorawan-firmware"><a class="doc-anchor" href="#appendix-build-and-run-lorawan-firmware">§</a>11 Appendix: Build and Run LoRaWAN Firmware</h1>
|
||
<p>Here are the steps to build, flash and run the <strong>LoRaWAN Firmware for PineDio Stack BL604</strong>…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/tree/master/customer_app/pinedio_lorawan"><strong>bl_iot_sdk/customer_app/pinedio_lorawan</strong></a></li>
|
||
</ul>
|
||
<h2 id="build-lorawan-firmware"><a class="doc-anchor" href="#build-lorawan-firmware">§</a>11.1 Build LoRaWAN Firmware</h2>
|
||
<p>Download the <a href="https://github.com/lupyuen/bl_iot_sdk/tree/master/customer_app/pinedio_lorawan"><strong>LoRaWAN firmware and driver source code</strong></a>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Download the master branch of lupyuen's bl_iot_sdk
|
||
git clone --recursive --branch master https://github.com/lupyuen/bl_iot_sdk</code></pre></div>
|
||
<p>In the <code>customer_app/pinedio_lorawan</code> folder, edit <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/customer_app/pinedio_lorawan/Makefile"><code>Makefile</code></a> and find this setting…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>CFLAGS += -DCONFIG_LORA_NODE_REGION=1</code></pre></div>
|
||
<p>Change “<code>1</code>” to your LoRa Region…</p>
|
||
<div><table><thead><tr><th style="text-align: left">Value</th><th style="text-align: left">Region</th></tr></thead><tbody>
|
||
<tr><td style="text-align: left">0</td><td style="text-align: left">No region</td></tr>
|
||
<tr><td style="text-align: left">1</td><td style="text-align: left">AS band on 923MHz</td></tr>
|
||
<tr><td style="text-align: left">2</td><td style="text-align: left">Australian band on 915MHz</td></tr>
|
||
<tr><td style="text-align: left">3</td><td style="text-align: left">Chinese band on 470MHz</td></tr>
|
||
<tr><td style="text-align: left">4</td><td style="text-align: left">Chinese band on 779MHz</td></tr>
|
||
<tr><td style="text-align: left">5</td><td style="text-align: left">European band on 433MHz</td></tr>
|
||
<tr><td style="text-align: left">6</td><td style="text-align: left">European band on 868MHz</td></tr>
|
||
<tr><td style="text-align: left">7</td><td style="text-align: left">South Korean band on 920MHz</td></tr>
|
||
<tr><td style="text-align: left">8</td><td style="text-align: left">India band on 865MHz</td></tr>
|
||
<tr><td style="text-align: left">9</td><td style="text-align: left">North American band on 915MHz</td></tr>
|
||
<tr><td style="text-align: left">10</td><td style="text-align: left">North American band on 915MHz with a maximum of 16 channels</td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<p>The <strong>GPIO Pin Numbers</strong> for LoRa SX1262 are defined in…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>components/3rdparty/lora-sx1262/include/sx126x-board.h</code></pre></div>
|
||
<p>They have been configured for PineDio Stack. (So no changes needed)</p>
|
||
<p>Build the Firmware Binary File <code>pinedio_lorawan.bin</code>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## TODO: Change this to the full path of bl_iot_sdk
|
||
export BL60X_SDK_PATH=$HOME/bl_iot_sdk
|
||
export CONFIG_CHIP_NAME=BL602
|
||
|
||
cd bl_iot_sdk/customer_app/pinedio_lorawan
|
||
make
|
||
|
||
## For WSL: Copy the firmware to /mnt/c/blflash, which refers to c:\blflash in Windows
|
||
mkdir /mnt/c/blflash
|
||
cp build_out/pinedio_lorawan.bin /mnt/c/blflash</code></pre></div>
|
||
<p><a href="https://lupyuen.github.io/articles/pinecone#building-firmware">More details on building bl_iot_sdk</a></p>
|
||
<h2 id="flash-lorawan-firmware"><a class="doc-anchor" href="#flash-lorawan-firmware">§</a>11.2 Flash LoRaWAN Firmware</h2>
|
||
<p>Follow these steps to install <code>blflash</code>…</p>
|
||
<ol>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/flash#install-rustup"><strong>“Install rustup”</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/flash#download-and-build-blflash"><strong>“Download and build blflash”</strong></a></p>
|
||
</li>
|
||
</ol>
|
||
<p>We assume that our Firmware Binary File <code>pinedio_lorawan.bin</code> has been copied to the <code>blflash</code> folder.</p>
|
||
<p>Set BL602 / BL604 to <strong>Flashing Mode</strong> and restart the board…</p>
|
||
<p><strong>For PineDio Stack BL604:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Set the <strong>GPIO 8 Jumper</strong> to <strong>High</strong> <a href="https://lupyuen.github.io/images/pinedio-high.jpg">(Like this)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Disconnect the USB cable and reconnect</p>
|
||
<p>Or use the Improvised Reset Button <a href="https://lupyuen.github.io/articles/pinedio#appendix-improvised-reset-button-for-pinedio-stack">(Here’s how)</a></p>
|
||
</li>
|
||
</ol>
|
||
<p><strong>For PineCone BL602:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Set the <strong>PineCone Jumper (IO 8)</strong> to the <strong><code>H</code> Position</strong> <a href="https://lupyuen.github.io/images/pinecone-jumperh.jpg">(Like this)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Press the Reset Button</p>
|
||
</li>
|
||
</ol>
|
||
<p><strong>For BL10:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Connect BL10 to the USB port</p>
|
||
</li>
|
||
<li>
|
||
<p>Press and hold the <strong>D8 Button (GPIO 8)</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Press and release the <strong>EN Button (Reset)</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Release the D8 Button</p>
|
||
</li>
|
||
</ol>
|
||
<p><strong>For <a href="https://docs.ai-thinker.com/en/wb2">Ai-Thinker Ai-WB2</a>, Pinenut and MagicHome BL602:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Disconnect the board from the USB Port</p>
|
||
</li>
|
||
<li>
|
||
<p>Connect <strong>GPIO 8</strong> to <strong>3.3V</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Reconnect the board to the USB port</p>
|
||
</li>
|
||
</ol>
|
||
<p>Enter these commands to flash <code>pinedio_lorawan.bin</code> to BL602 / BL604 over UART…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## For Linux:
|
||
blflash flash build_out/pinedio_lorawan.bin \
|
||
--port /dev/ttyUSB0
|
||
|
||
## For macOS:
|
||
blflash flash build_out/pinedio_lorawan.bin \
|
||
--port /dev/tty.usbserial-1420 \
|
||
--initial-baud-rate 230400 \
|
||
--baud-rate 230400
|
||
|
||
## For Windows: Change COM5 to the BL602 / BL604 Serial Port
|
||
blflash flash c:\blflash\pinedio_lorawan.bin --port COM5</code></pre></div>
|
||
<p>(For WSL: Do this under plain old Windows CMD, not WSL, because blflash needs to access the COM port)</p>
|
||
<p><a href="https://lupyuen.github.io/articles/flash#flash-the-firmware">More details on flashing firmware</a></p>
|
||
<h2 id="run-lorawan-firmware"><a class="doc-anchor" href="#run-lorawan-firmware">§</a>11.3 Run LoRaWAN Firmware</h2>
|
||
<p>Set BL602 / BL604 to <strong>Normal Mode</strong> (Non-Flashing) and restart the board…</p>
|
||
<p><strong>For PineDio Stack BL604:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Set the <strong>GPIO 8 Jumper</strong> to <strong>Low</strong> <a href="https://lupyuen.github.io/images/pinedio-low.jpg">(Like this)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Disconnect the USB cable and reconnect</p>
|
||
<p>Or use the Improvised Reset Button <a href="https://lupyuen.github.io/articles/pinedio#appendix-improvised-reset-button-for-pinedio-stack">(Here’s how)</a></p>
|
||
</li>
|
||
</ol>
|
||
<p><strong>For PineCone BL602:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Set the <strong>PineCone Jumper (IO 8)</strong> to the <strong><code>L</code> Position</strong> <a href="https://lupyuen.github.io/images/pinecone-jumperl.jpg">(Like this)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Press the Reset Button</p>
|
||
</li>
|
||
</ol>
|
||
<p><strong>For BL10:</strong></p>
|
||
<ol>
|
||
<li>Press and release the <strong>EN Button (Reset)</strong></li>
|
||
</ol>
|
||
<p><strong>For <a href="https://docs.ai-thinker.com/en/wb2">Ai-Thinker Ai-WB2</a>, Pinenut and MagicHome BL602:</strong></p>
|
||
<ol>
|
||
<li>
|
||
<p>Disconnect the board from the USB Port</p>
|
||
</li>
|
||
<li>
|
||
<p>Connect <strong>GPIO 8</strong> to <strong>GND</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Reconnect the board to the USB port</p>
|
||
</li>
|
||
</ol>
|
||
<p>After restarting, connect to BL602 / BL604’s UART Port at 2 Mbps like so…</p>
|
||
<p><strong>For Linux:</strong></p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>screen /dev/ttyUSB0 2000000</code></pre></div>
|
||
<p><strong>For macOS:</strong> Use CoolTerm (<a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
|
||
<p><strong>For Windows:</strong> Use <code>putty</code> (<a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
|
||
<p><strong>Alternatively:</strong> Use the Web Serial Terminal (<a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
|
||
<p><a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">More details on connecting to BL602 / BL604</a></p>
|
||
<h2 id="enter-lorawan-commands"><a class="doc-anchor" href="#enter-lorawan-commands">§</a>11.4 Enter LoRaWAN Commands</h2>
|
||
<p>Let’s enter the LoRaWAN Commands to join The Things Network and transmit a Data Packet!</p>
|
||
<ol>
|
||
<li>
|
||
<p>Log on to <strong>The Things Network</strong>. Browse to our Device and copy these values…</p>
|
||
<p><strong>JoinEUI</strong> (Join Extended Unique Identifier)</p>
|
||
<p><strong>DevEUI</strong> (Device Extended Unique Identifier)</p>
|
||
<p><strong>AppKey</strong> (Application Key)</p>
|
||
<p><a href="https://lupyuen.github.io/articles/ttn#join-device-to-the-things-network">(Instructions here)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>In the BL602 / BL604 terminal, press Enter to reveal the command prompt.</p>
|
||
</li>
|
||
<li>
|
||
<p>First we start the <strong>Background Task</strong> that will handle LoRa packets…</p>
|
||
<p>Enter this command…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>create_task</code></pre></div>
|
||
<p><a href="https://lupyuen.github.io/articles/lora2#event-queue">(<code>create_task</code> is explained here)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Next we initialise the <strong>LoRa SX1262 and LoRaWAN Drivers</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>init_lorawan</code></pre></div>
|
||
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/customer_app/pinedio_lorawan/pinedio_lorawan/lorawan.c#L168-L174">(<code>init_lorawan</code> is defined here)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Set the <strong>DevEUI</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>las_wr_dev_eui 0xAB:0xBA:0xDA:0xBA:0xAB:0xBA:0xDA:0xBA</code></pre></div>
|
||
<p>Change “<code>0xAB:0xBA:...</code>” to your <strong>DevEUI</strong></p>
|
||
<p>(Remember to change the <strong>“<code>,</code>”</strong> delimiter to <strong>“<code>:</code>”</strong>)</p>
|
||
</li>
|
||
<li>
|
||
<p>Set the <strong>JoinEUI</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>las_wr_app_eui 0x00:0x00:0x00:0x00:0x00:0x00:0x00:0x00</code></pre></div>
|
||
<p>Change “<code>0x00:0x00:...</code>” to your <strong>JoinEUI</strong></p>
|
||
<p>(Yep change the <strong>“<code>,</code>”</strong> delimiter to <strong>“<code>:</code>”</strong>)</p>
|
||
</li>
|
||
<li>
|
||
<p>Set the <strong>AppKey</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>las_wr_app_key 0xAB:0xBA:0xDA:0xBA:0xAB:0xBA:0xDA:0xBA0xAB:0xBA:0xDA:0xBA:0xAB:0xBA:0xDA:0xBA</code></pre></div>
|
||
<p>Change “<code>0xAB:0xBA:...</code>” to your <strong>AppKey</strong></p>
|
||
<p>(Again change <strong>“<code>,</code>”</strong> to <strong>“<code>:</code>”</strong>)</p>
|
||
</li>
|
||
<li>
|
||
<p>We send a request to <strong>join The Things Network</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>las_join 1</code></pre></div>
|
||
<p>“<code>1</code>” means try only once.</p>
|
||
<p><a href="https://lupyuen.github.io/articles/lorawan#join-network-request">(<code>las_join</code> is explained here)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>We open an <strong>Application Port</strong> that will connect to The Things Network…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>las_app_port open 2</code></pre></div>
|
||
<p>“<code>2</code>” is the Application Port Number</p>
|
||
<p><a href="https://lupyuen.github.io/articles/lorawan#open-lorawan-port">(<code>las_app_port</code> is explained here)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Finally we <strong>send a data packet to The Things Network</strong> over LoRaWAN…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>las_app_tx_cbor 2 0 1234 2345</code></pre></div>
|
||
<p>This means…</p>
|
||
<ul>
|
||
<li>
|
||
<p>Transmit a LoRaWAN Packet to <strong>Port 2</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>That contains the values <strong><code>t=1234</code></strong> (Temperature), <strong><code>l=2345</code></strong> (Light Level)</p>
|
||
</li>
|
||
<li>
|
||
<p><code>0</code> means that this is an <strong>Unconfirmed Message</strong></p>
|
||
<p>(Because we’re not expecting an acknowledgement)</p>
|
||
</li>
|
||
</ul>
|
||
<p>Our Sensor Data has been transmitted via LoRaWAN to The Things Network!</p>
|
||
<p><a href="https://youtu.be/BMMIIiZG6G0"><strong>Watch the demo video on YouTube</strong></a></p>
|
||
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/customer_app/sdk_app_lorawan/README.md#output-log"><strong>See the output log</strong></a></p>
|
||
</li>
|
||
</ol>
|
||
<p>Check out this demo of PineDio Stack with Roblox and The Things Network…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/roblox#digital-twin-demo"><strong>“IoT Digital Twin with Roblox and The Things Network”</strong></a></li>
|
||
</ul>
|
||
<h1 id="appendix-porting-tinycbor-to-bl602"><a class="doc-anchor" href="#appendix-porting-tinycbor-to-bl602">§</a>12 Appendix: Porting TinyCBOR to BL602</h1>
|
||
<p>Below are the fixes we made while porting the TinyCBOR library to BL602 / BL604…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/tinycbor-bl602/commit/971dca84b0b036a4ed44aa808e6eb18033161170">“Fix fall through”</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/tinycbor-bl602/commit/c32bbc7696a54578f050467f1e182f4fd0f9bb9a">“Fix RetType, LenType”</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/tinycbor-bl602/commit/65f857a3f2c8f0169ff215047fbcf7cd956eb55a">“Fix open_memstream”</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/tinycbor-bl602/commit/0594d2f29646f65db22a60102d25c7aa675e9cae">“Don’t use memstream”</a></p>
|
||
</li>
|
||
</ul>
|
||
|
||
|
||
<!-- Begin scripts/rustdoc-after.html: Post-HTML for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
|
||
<!-- Begin Theme Picker and Prism Theme -->
|
||
<script src="../theme.js"></script>
|
||
<script src="../prism.js"></script>
|
||
<!-- Theme Picker and Prism Theme -->
|
||
|
||
<!-- End scripts/rustdoc-after.html -->
|
||
|
||
|
||
</body>
|
||
</html> |