mirror of
https://github.com/lupyuen/lupyuen.github.io.git
synced 2025-01-13 09:08:30 +08:00
1569 lines
No EOL
99 KiB
HTML
1569 lines
No EOL
99 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
|
||
<head>
|
||
<link rel="stylesheet" type="text/css" href="/_static/css/banner-styles.css?v=bsmaklHF" />
|
||
<link rel="stylesheet" type="text/css" href="/_static/css/iconochive.css?v=qtvMKcIJ" />
|
||
<link rel="canonical" href="https://lupyuen.org/articles/sneak-peek-of-pinetime-smart-watch-and-why-its-perfect-for-teaching-iot.html" />
|
||
<!-- End Wayback Rewrite JS Include -->
|
||
<title data-rh="true">Sneak Peek of PineTime Smart Watch… And why it’s perfect for teaching IoT | by Lup Yuen Lee 李立源
|
||
| The Startup | Medium</title>
|
||
<meta data-rh="true" charset="utf-8" />
|
||
<meta data-rh="true" name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
|
||
<meta data-rh="true" name="theme-color" content="#000000" />
|
||
<meta data-rh="true" property="og:type" content="article" />
|
||
<meta data-rh="true" property="article:published_time" content="2020-10-19T09:57:43.401Z" />
|
||
<meta data-rh="true" name="title"
|
||
content="Sneak Peek of PineTime Smart Watch… And why it’s perfect for teaching IoT | by Lup Yuen Lee 李立源 | The Startup | Medium" />
|
||
<meta data-rh="true" property="og:title"
|
||
content="Sneak Peek of PineTime Smart Watch… And why it’s perfect for teaching IoT" />
|
||
<meta data-rh="true" property="twitter:title"
|
||
content="Sneak Peek of PineTime Smart Watch… And why it’s perfect for teaching IoT" />
|
||
<meta data-rh="true" name="description"
|
||
content="UPDATE: This code in this article has been archived in the pre-lvgl branch of pinetime-rust-mynewt. The pinetime-rust-mynewt firmware has been revamped to support Rust Watch Faces on LVGL. Check out…" />
|
||
<meta data-rh="true" property="og:description"
|
||
content="I’m one of the lucky few who received the developer preview version of the PineTime Smart Watch by Pine64. (My official mission: Port…" />
|
||
<meta data-rh="true" property="twitter:description"
|
||
content="I’m one of the lucky few who received the developer preview version of the PineTime Smart Watch by Pine64. (My official mission: Port…" />
|
||
<meta data-rh="true" name="twitter:card" content="summary_large_image" />
|
||
<meta data-rh="true" name="twitter:creator" content="@MisterTechBlog" />
|
||
<meta data-rh="true" name="author" content="Lup Yuen Lee 李立源" />
|
||
<meta data-rh="true" name="robots" content="index,follow,max-image-preview:large" />
|
||
<meta data-rh="true" name="referrer" content="unsafe-url" />
|
||
<meta data-rh="true" name="twitter:label1" value="Reading time" />
|
||
<meta data-rh="true" name="twitter:data1" value="15 min read" />
|
||
<meta property="og:image"
|
||
content="https://lupyuen.github.io/images/legacy/j1.jpeg">
|
||
|
||
<!-- 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="../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");
|
||
}
|
||
a {
|
||
color: #77d;
|
||
}
|
||
</style>
|
||
<!-- End scripts/rustdoc-header.html -->
|
||
|
||
</head>
|
||
|
||
<body>
|
||
|
||
<div id="root">
|
||
<div class="a b c">
|
||
<div class="d e f g h i j k"></div>
|
||
<div class="s">
|
||
<article>
|
||
<section class="cx cy cz da aj db dc s"></section><span class="s"></span>
|
||
<div>
|
||
<div class="t v dd de df dg"></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="dm aj">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j1.jpeg" /></p>
|
||
<p><em>Pine64’s PineTime Smart Watch with charging
|
||
cradle</em></p>
|
||
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<div>
|
||
<h1 id="e69f"
|
||
class="el em en eo b ep eq er es et eu ev ew ex ey ez fa fb fc fd fe ff fg fh fi fj fk">Sneak Peek
|
||
of PineTime Smart Watch… And why it’s perfect for teaching IoT</h1>
|
||
<div class="fl">
|
||
<div class="n fm fn fo fp">
|
||
<div class="o n">
|
||
<div><a rel="noopener"
|
||
href="https://lupyuen.github.io">
|
||
<div class="dp fq fr">
|
||
<div class="fs n ft o p t fu fv fw fx fy dg"></div>
|
||
|
||
</div>
|
||
</a></div>
|
||
<div class="ga aj s">
|
||
<div class="n">
|
||
<div style="flex:1"><span class="cg b ei ci fk">
|
||
<div class="gb n o gc"><span class="cg b ei ci bm gd ge gf gg gh gi fk"><a
|
||
class="cm cn av aw ax ay az ba bb bc gj bf gk gl" rel="noopener"
|
||
href="https://lupyuen.github.io">Lup
|
||
Yuen Lee 李立源</a></span>
|
||
|
||
</div>
|
||
</span></div>
|
||
</div><span class="cg b ei ci ej"><span class="cg b ei ci bm gd ge gf gg gh gi ej">
|
||
<div><a class="cm cn av aw ax ay az ba bb bc gj bf gk gl" rel="noopener"
|
||
href="https://lupyuen.github.io">
|
||
15 Nov 2019</a> <!-- -->·
|
||
<!-- -->
|
||
<!-- -->15
|
||
<!-- --> min read<span style="padding-left:4px"></span>
|
||
</div>
|
||
</span></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p id="14da"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip"><em class="iq">UPDATE: This code in this article has been archived in the
|
||
</em></strong><a
|
||
href="https://github.com/lupyuen/pinetime-rust-mynewt/tree/pre-lvgl"
|
||
class="cm ir" rel="noopener nofollow"><strong class="ht ip"><em class="iq">pre-lvgl branch of
|
||
pinetime-rust-mynewt</em></strong></a><strong class="ht ip"><em class="iq">. The
|
||
</em></strong><a
|
||
href="https://github.com/lupyuen/pinetime-rust-mynewt"
|
||
class="cm ir" rel="noopener nofollow"><strong class="ht ip"><em class="iq">pinetime-rust-mynewt
|
||
firmware</em></strong></a><strong class="ht ip"><em class="iq"> has been revamped to support
|
||
</em></strong><a
|
||
href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/watchface"
|
||
class="cm ir" rel="noopener nofollow"><strong class="ht ip"><em class="iq">Rust Watch Faces on
|
||
LVGL</em></strong></a><strong class="ht ip"><em class="iq">. </em></strong><a
|
||
href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/watchface"
|
||
class="cm ir" rel="noopener nofollow"><strong class="ht ip"><em class="iq">Check out the
|
||
updates</em></strong></a></p>
|
||
<p id="bb8f"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">I’m one
|
||
of the lucky few who received the developer preview version of the <a
|
||
href="https://wiki.pine64.org/index.php/PineTime"
|
||
class="cm ir" rel="noopener nofollow"><strong class="ht ip">PineTime Smart Watch by
|
||
Pine64</strong></a>. <em class="iq">(My official mission: Port </em><a
|
||
href="https://mynewt.apache.org/" class="cm ir"
|
||
rel="noopener nofollow"><em class="iq">Apache Mynewt OS</em></a><em class="iq"> and </em><a
|
||
href="https://rust-embedded.github.io/book/"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">Embedded Rust</em></a><em class="iq"> to
|
||
PineTime… </em><a
|
||
href="https://store.pine64.org/?product=pinetime-dev-kit"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">Check out the Pine64 Store</em></a><em
|
||
class="iq">)</em></p>
|
||
<p id="8d44"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">After
|
||
coding on PineTime for a few days (in Rust), it suddenly struck me…</p>
|
||
<ul class="">
|
||
<li id="f3c4"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io is it iu fk">I
|
||
felt really <strong class="ht ip">comfortable and productive</strong> coding the new gadget. Even
|
||
though I have never coded a smart watch.</li>
|
||
<li id="669b"
|
||
class="hr hs en ht b hu iv hw hx hy iw ia ib ic ix ie if ig iy ii ij ik iz im in io is it iu fk">
|
||
PineTime is a <strong class="ht ip">terrific tool for teaching IoT</strong>! And I have taught IoT
|
||
with so many different gadgets.</li>
|
||
</ul>
|
||
<p id="49e3"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Lemme
|
||
elaborate…</p>
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j2.jpeg" /></p>
|
||
<p><em>Nordic nRF52832 Microcontroller inside
|
||
PineTime (the big black square at top)</em></p>
|
||
|
||
<p id="bcd7"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">1️⃣
|
||
<strong class="ht ip">PineTime is the spiritual successor to BBC micro:bit (the educational
|
||
gadget)!</strong></p>
|
||
<p id="2a80"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Yes it’s
|
||
blasphemy but if you think about it… BBC micro:bit is really a <strong class="ht ip">Nordic
|
||
nRF51</strong> in an oversized form factor that runs an odd 2.4 GHz wireless protocol. With
|
||
PineTime we get a supercharged <strong class="ht ip">nRF52 and proper Bluetooth support</strong>,
|
||
including Bluetooth Mesh! <em class="iq">Imagine a classroom full of meshed PineTime gadgets…</em>
|
||
</p>
|
||
<p id="2e9c"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">2️⃣
|
||
<strong class="ht ip">PineTime has a touchscreen!</strong></p>
|
||
<p id="220f"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">
|
||
Millennials expect no less than a touchscreen for learning IoT, since they are used to touchy feely
|
||
gadgets like Apple Watch and FitBit. How would you explain to a millennial how a touch controller
|
||
works? <a class="cm ir" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/building-a-rust-driver-for-pinetimes-touch-controller">Show
|
||
them a PineTime</a>! <em class="iq">(Few of us have actually programmed a touch controller…
|
||
</em><a class="cm ir" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/building-a-rust-driver-for-pinetimes-touch-controller"><em
|
||
class="iq">Here’s the perfect opportunity</em></a><em class="iq">!)</em></p>
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j3.jpeg" /></p>
|
||
<p><em>PineTime powered by its built-in lithium
|
||
battery (ST-Link USB Programmer at the right)</em></p>
|
||
|
||
<p id="62c0"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">3️⃣
|
||
<strong class="ht ip">PineTime has realistic battery life constraints!</strong></p>
|
||
<p id="eb74"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">I would
|
||
give every IoT student a PineTime gadget…<em class="iq"> “Build me a watch face that has the longest
|
||
battery life!”</em> For the first time ever, we have a simple way to teach the real-world impact
|
||
of firmware programming on battery life. And there are many options to explore: polling vs
|
||
callbacks, coroutines vs multitasking, RTOS vs no RTOS, Deep Sleep vs Light Nap, WFI vs WFE,
|
||
point-to-point vs mesh networks, …</p>
|
||
<p id="1b4b"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">4️⃣
|
||
<strong class="ht ip">PineTime reminds us that IoT can save lives!</strong></p>
|
||
<p id="b99d"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">I suffer
|
||
from Severe Hypertension… <em class="iq">I can really drop dead at any moment (probably because of
|
||
Rust!)</em> I discovered this by chance… I really wished my watch could tell me much earlier.
|
||
PineTime has a simple Heart Rate Sensor, but it’s a good way to remind our future makers that they
|
||
have the power to create a gadget that saves our lives.</p>
|
||
|
||
|
||
<p><a href="https://youtu.be/VAveAwHAg1Q">[Watch the video on YouTube]</a></p>
|
||
|
||
<p><em>Coding and debugging PineTime with
|
||
open-source Visual Studio Code</em></p>
|
||
|
||
<p id="a779"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">5️⃣
|
||
<strong class="ht ip">PineTime is powered by open source!</strong></p>
|
||
<p id="cbf1"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Coding
|
||
with PineTime feels exactly like coding on <a class="cm ir" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/rust-rocks-nb-iot-stm32-blue-pill-with-quectel-bc95-g-on-apache-mynewt">STM32
|
||
Blue Pill</a>… Just grab the $20 watch, build a simple <a
|
||
href="https://www.linkedin.com/posts/lupyuen_pinetime-daiso-activity-6599825203679854592-dbAB"
|
||
class="cm ir" rel="noopener nofollow">SWD cradle</a> <em class="iq">(fun creativity
|
||
exercise!)</em>, connect a <a
|
||
href="https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20180924134644&SearchText=st-link+v2&switch_new_app=y"
|
||
class="cm ir" rel="noopener nofollow">$2 ST-Link dongle</a> and hack away with the <em
|
||
class="iq">exact same stack</em> of open source tools I used for STM32! VSCode, Cortex Debugger,
|
||
GCC for Arm, <a
|
||
href="https://rust-embedded.github.io/book/"
|
||
class="cm ir" rel="noopener nofollow">Embedded Rust</a>, OpenOCD, <a
|
||
href="https://mynewt.apache.org/" class="cm ir"
|
||
rel="noopener nofollow">Apache Mynewt OS</a>, NimBLE Bluetooth stack, … <em class="iq">No better
|
||
way to immerse our future makers into the world of Open Source Collaboration!</em></p>
|
||
<p id="2f58"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">🛈 <a
|
||
href="https://gist.github.com/lupyuen/08e383845d68d3337747e8eb59d0f624"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">What is VSCode? Is it related to Visual
|
||
Studio? How is Microsoft involved? Read this</em></a></p>
|
||
</div>
|
||
</div>
|
||
<div class="dm">
|
||
<div class="n p">
|
||
<div class="jk jl jm jn jo jp af jq ag jr ai aj">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j4.png" /></p>
|
||
<p><em>Rendering text and graphics on PineTime
|
||
with a few lines of Rust code. From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/display.rs"
|
||
class="cm ir"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/display.rs</a>
|
||
</em></p>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<p id="f1d4"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">6️⃣
|
||
<strong class="ht ip">PineTime was created for Embedded Rust!</strong></p>
|
||
<p id="723c"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">With 512
|
||
KB of Flash ROM (built-in) and 64 KB of RAM, PineTime will handle most Rust Embedded crates just
|
||
fine. (MicroPython and Embedded JavaScript may be tough to squeeze in.) Just watch how the <code
|
||
class="dy jw jx jy jz b">embedded-graphics</code> crate renders text and graphics so easily on
|
||
PineTime! Rust on PineTime will create the same educational impact that graphical <a
|
||
href="https://en.wikipedia.org/wiki/Logo_(programming_language)"
|
||
class="cm ir" rel="noopener nofollow">Logo programming</a> gave us so many years ago. More about
|
||
Rust in a while…</p>
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j5.jpeg" /></p>
|
||
<p><em>Gently prying open the PineTime Smart Watch
|
||
with tweezers… Or “forceps” if you’re medically trained like me</em></p>
|
||
|
||
<p id="2545"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">7️⃣
|
||
<strong class="ht ip">PineTime was designed for millennials!</strong></p>
|
||
<p id="ba91"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Some
|
||
parts inside PineTime are so tiny that they hurt my eyes… But I bet the millennials will love it.
|
||
It’s a gadget that fits naturally into delicate millennial hands… And begs to be pried open (gently)
|
||
for deeper inspection. <em class="iq">(Compare PineTime with the geriatric Arduino Uno and oversized
|
||
BBC micro:bit)</em></p>
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j6.png" /></p>
|
||
<p><em>EBYTE E73-TBB Development Boards with onboard
|
||
Nordic nRF52 Microcontroller. From <a class="cm ir" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/bluetooth-mesh-with-nrf52-and-apache-mynewt">https://lupyuen.github.io/articles/bluetooth-mesh-with-nrf52-and-apache-mynewt</a>
|
||
</em></p>
|
||
|
||
<p id="99a9"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">8️⃣
|
||
<strong class="ht ip">PineTime begins a lifelong IoT learning journey…</strong></p>
|
||
<p id="a119"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">PineTime
|
||
has a number of interesting built-in sensors and actuators (on I2C and SPI) to keep learners busy
|
||
for a while: Colour Touchscreen, Heart Rate Sensor, Accelerometer, Vibrator, Power Management,
|
||
Bluetooth, … <em class="iq">But what if they wish to explore more?</em></p>
|
||
<p id="0602"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Then just
|
||
pick up one of the many affordable nRF52 development boards! They will be so happy to see the same
|
||
code and the same suite of open source tools running on any nRF52 board. <em class="iq">(Unlike the
|
||
Arduino Uno and BBC micro:bit, which turned out to be disappointing deadends)</em></p>
|
||
<p id="fc4a"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Here’s my
|
||
plea to Pine64 (I hope others will join me)… <strong class="ht ip"><em class="iq">Please keep
|
||
PineTime open and hackable… For the sake of IoT Education!</em></strong></p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<div class="n p fl ke kf kg" role="separator"><span class="kh fz hb ki kj kk"></span><span
|
||
class="kh fz hb ki kj kk"></span><span class="kh fz hb ki kj"></span></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<h1 id="f101"
|
||
class="kl km en cg kn ko kp hw kq kr ks ia kt ku kv kw kx ky kz la lb lc ld le lf lg fk">Proposed
|
||
PineTime Smart Watch Firmware</h1>
|
||
<p id="01c5"
|
||
class="hr hs en ht b hu lh hw hx hy li ia ib ic lj ie if ig lk ii ij ik ll im in io dh fk">PineTime
|
||
is extremely hackable (in its current raw form), so you’re free to run any RTOS (FreeRTOS, Zephyr,
|
||
Mynewt, mbed)… Or none at all (Bare Metal Embedded Rust)!</p>
|
||
<p id="ec83"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">But as an
|
||
uptight, severely hypertensive former enterprise architect… I expect no less than this firmware
|
||
stack (even if it means stacking the <a
|
||
href="http://mysingaporefood.com/story/9-layer-kueh-%E4%B9%9D%E5%B1%82%E7%B3%95/"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">kueh lapis</em></a> by myself!) Because it
|
||
makes teaching IoT more modular and less crash-prone…</p>
|
||
</div>
|
||
</div>
|
||
<div class="dm aj">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j7.png" /></p>
|
||
<p><em>Proposed Firmware Stack for PineTime Smart
|
||
Watch. Rust components are coloured brown.</em></p>
|
||
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<p id="a61b"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">The
|
||
<strong class="ht ip">PineTime Smart Watch Application</strong> is coded in Rust… Because Rust has
|
||
memory safety features that prevent the application from crashing due to bad pointers. And yet it
|
||
compiles into Arm machine code, running as efficiently as C. <em class="iq">(Given a choice to teach
|
||
Embedded C or Embedded Rust, I would most certainly choose Rust, because it’s modern and
|
||
friendlier!)</em></p>
|
||
<p id="c603"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">The Rust
|
||
Application has three jobs…</p>
|
||
<p id="f4fc"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">1️⃣
|
||
<strong class="ht ip">Render the user interface</strong> text and graphics to the LCD display</p>
|
||
<p id="c4d3"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">2️⃣
|
||
<strong class="ht ip">Respond to touch events</strong> that are generated whenever we touch the
|
||
touchscreen</p>
|
||
<p id="5fe9"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">3️⃣
|
||
<strong class="ht ip">Receive and transmit sensor data</strong> over Bluetooth</p>
|
||
<p id="152e"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Here’s
|
||
the <code class="dy jw jx jy jz b">main()</code> function implemented in the Rust Application…</p>
|
||
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/e3428d1f7520aa2580a7b6fc91ea87e8.js"></script></p>
|
||
|
||
<p><em>PineTime’s main() function in Rust. From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/lib.rs#L52-L94"
|
||
class="cm ir"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/lib.rs#L52-L94</a>
|
||
</em></p>
|
||
|
||
<p id="9489"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><em
|
||
class="iq">Some of the blocks are still missing (like the touchscreen driver), so if you’re keen
|
||
to help out, drop me a note!</em></p>
|
||
<p id="c8d9"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Let’s
|
||
inspect the three flows in detail…</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<div class="n p fl ke kf kg" role="separator"><span class="kh fz hb ki kj kk"></span><span
|
||
class="kh fz hb ki kj kk"></span><span class="kh fz hb ki kj"></span></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<h1 id="98d9"
|
||
class="kl km en cg kn ko kp hw kq kr ks ia kt ku kv kw kx ky kz la lb lc ld le lf lg fk">Render User
|
||
Interface on PineTime Smart Watch</h1>
|
||
</div>
|
||
</div>
|
||
<div class="dm">
|
||
<div class="n p">
|
||
<div class="jk jl jm jn jo jp af jq ag jr ai aj">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j8.png" /></p>
|
||
|
||
<p><em>Render User Interface Flow. Rust components
|
||
are coloured brown.</em></p>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<p id="a953"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">A Smart
|
||
Watch Application needs a decent user interface with text and graphics. Coding that in low-level C
|
||
would be tedious. Fortunately we got Rust and the <code
|
||
class="dy jw jx jy jz b">embedded-graphics</code> crate to help us. The <code
|
||
class="dy jw jx jy jz b"><a href="https://github.com/jamwaffles/embedded-graphics" class="cm ir" rel="noopener nofollow">embedded-graphics</a></code>
|
||
crate makes it really easy to render raster fonts and various shapes with a few simple lines of Rust
|
||
code.</p>
|
||
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/3b3c12e788d55b5a83a7c696e21f09da.js"></script></p>
|
||
|
||
<p><em>Render text and graphics to PineTime display
|
||
with Rust. From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/display.rs#L33-L80"
|
||
class="cm ir"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/display.rs#L33-L80</a>
|
||
</em></p>
|
||
|
||
<p id="9d0e"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">The <code
|
||
class="dy jw jx jy jz b">embedded-graphics</code> crate is designed to render its bitmap directly
|
||
into a Display Controller Driver that complies with the Rust Embedded Framework (which uses specific
|
||
types and constructs to access bare-metal hardware on a microcontroller).</p>
|
||
</div>
|
||
</div>
|
||
<div class="dm">
|
||
<div class="n p">
|
||
<div class="jk jl jm jn jo jp af jq ag jr ai aj">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j9.png" /></p>
|
||
|
||
<p><em>The Rust code above renders a circle and a
|
||
line of text: “I AM A RUSTY BEACON”</em></p>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<p id="fb96"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">We’re now
|
||
using the standard <code
|
||
class="dy jw jx jy jz b"><a href="https://docs.rs/st7735-lcd/0.6.1/st7735_lcd/" class="cm ir" rel="noopener nofollow">st7735_lcd</a></code>
|
||
Rust Embedded Driver. It needs some tweaking to make it 100% compatible with PineTime’s ST7789
|
||
display controller… But for now it seems to be rendering the display fairly well without any
|
||
modification.</p>
|
||
<p id="69f3"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">The <code
|
||
class="dy jw jx jy jz b">st7735_lcd</code> driver assumes that the <a
|
||
href="https://docs.rs/embedded-hal/0.2.3/embedded_hal/"
|
||
class="cm ir" rel="noopener nofollow"><strong class="ht ip">Rust Embedded HAL</strong></a>
|
||
(Hardware Adaptation Layer) is available for our microcontroller… That’s how the driver accesses the
|
||
SPI port and GPIO pins connected to the display controller. But we can’t allow Rust to access our
|
||
hardware directly… <em class="iq">Everything must go through Mynewt OS!</em></p>
|
||
<p id="2b9b"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">The
|
||
solution is simple… We created a thin <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/mynewt_hal.rs"
|
||
class="cm ir" rel="noopener nofollow">Rust Embedded HAL</a> that maps to the Mynewt APIs for SPI
|
||
and GPIO. <em class="iq">And it works!</em></p>
|
||
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/47dd94495d58aa5017f7dfde47b8dc20.js"></script></p>
|
||
|
||
<p><em>Rust Embedded HAL for PineTime on Mynewt OS.
|
||
From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/mynewt_hal.rs"
|
||
class="cm ir"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/mynewt_hal.rs</a>
|
||
</em></p>
|
||
|
||
<p id="9ac6"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Now we
|
||
have a working demo of the screen rendering controlled by Rust. The colours seem OK even though we
|
||
are using a ST7735 driver for PineTime’s ST7789 display controller.</p>
|
||
</div>
|
||
</div>
|
||
<div class="dm">
|
||
<div class="n p">
|
||
<div class="jk jl jm jn jo jp af jq ag jr ai aj">
|
||
|
||
|
||
<p><a href="https://youtu.be/enoZVIg-6Fg">[Watch on YouTube]</a></p>
|
||
|
||
<p><em>PineTime booting and rendering the display
|
||
in real time</em></p>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<div class="n p fl ke kf kg" role="separator"><span class="kh fz hb ki kj kk"></span><span
|
||
class="kh fz hb ki kj kk"></span><span class="kh fz hb ki kj"></span></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<h1 id="d364"
|
||
class="kl km en cg kn ko kp hw kq kr ks ia kt ku kv kw kx ky kz la lb lc ld le lf lg fk">Respond to
|
||
Touch Events on PineTime Smart Watch</h1>
|
||
</div>
|
||
</div>
|
||
<div class="dm">
|
||
<div class="n p">
|
||
<div class="jk jl jm jn jo jp af jq ag jr ai aj">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j10.png" /></p>
|
||
|
||
<p><em>Respond to Touch Events Flow. Rust
|
||
components are coloured brown.</em></p>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<p id="b617"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">We now
|
||
have a simple way to render watch faces in Rust… <em class="iq">Yay! </em>But a Smart Watch isn’t
|
||
really Smart unless it can respond to our tapping and prodding on the touchscreen. And it gets
|
||
complicated because of <strong class="ht ip">“Interrupts” or “中断”</strong> in Chinese (learnt that
|
||
from the <a
|
||
href="http://files.pine64.org/doc/datasheet/pinetime/CST816S%E6%95%B0%E6%8D%AE%E6%89%8B%E5%86%8CV1.1.pdf"
|
||
class="cm ir" rel="noopener nofollow">Hynitron docs</a>).</p>
|
||
<p id="f2ff"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><em
|
||
class="iq">How do we check if the screen has been touched?</em> We could poll the Touch Controller
|
||
over I2C every second. But that would consume too much power. And it would feel laggy.</p>
|
||
<p id="a01e"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">The right
|
||
solution is to monitor for Interrupts generated by the Touch Controller. The Touch Controller
|
||
switches the Interrupt Pin (just a regular GPIO Pin) into the Low state whenever a touch is
|
||
detected.</p>
|
||
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j11.png" /></p>
|
||
|
||
<p><em>Interrupt Pin (IRQ) goes low on just one
|
||
touch. From <a
|
||
href="http://www.hynitron.com/upload/1408075960.pdf"
|
||
class="cm ir" rel="noopener nofollow">http://www.hynitron.com/upload/1408075960.pdf</a>
|
||
</em></p>
|
||
|
||
<p id="834d"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Mynewt OS
|
||
provides a <a
|
||
href="https://mynewt.apache.org/latest/os/modules/hal/hal_gpio/hal_gpio.html#c.hal_gpio_irq_init"
|
||
class="cm ir" rel="noopener nofollow">GPIO API</a> that transforms this Hardware Interrupt into a
|
||
Software Event that we may handle in our C code. That’s how we create a Touch Controller Driver that
|
||
responds to touch.</p>
|
||
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/3d3e9dbfc47e0788795ae8a8ffafc16b.js"></script></p>
|
||
|
||
<p><em>Calling the Mynewt API to transform a
|
||
Hardware Interrupt into a Software Event. From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/touch_sensor.rs"
|
||
class="cm ir"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/touch_sensor.rs</a>
|
||
</em></p>
|
||
|
||
<p id="191a"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><em
|
||
class="iq">How shall we escalate the Touch Event up through the firmware layers to the Rust
|
||
Application (so that it can update the display)?</em></p>
|
||
<p id="3a82"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Mynewt OS
|
||
provides a <a
|
||
href="https://mynewt.apache.org/latest/os/modules/sensor_framework/sensor_framework.html"
|
||
class="cm ir" rel="noopener nofollow"><strong class="ht ip">Sensor Framework</strong></a> enables
|
||
sensors to raise events to the application. So a Temperature Sensor could use this Sensor Framework
|
||
to alert the application of any variations in temperature. We shall use Mynewt’s Sensor Framework to
|
||
escalate Touch Events the same way.</p>
|
||
<p id="1474"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">This
|
||
works only when we have a Mynewt Sensor Driver for our Touch Controller… Which I’m still coding in
|
||
C. I have coded similar drivers previously… Here’s my Mynewt Sensor Driver for the Nordic low-power
|
||
transceiver nRF24L01 that watches for the Incoming Packet Interrupt and transforms it into a Sensor
|
||
Data Event for the application: <code
|
||
class="dy jw jx jy jz b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/master/libs/nrf24l01" class="cm ir" rel="noopener nofollow">github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/master/libs/nrf24l01</a></code>
|
||
</p>
|
||
<p id="adf2"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Handling
|
||
a Touch Sensor Event with Mynewt and Rust should look like this: <code
|
||
class="dy jw jx jy jz b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/app_sensor.rs" class="cm ir" rel="noopener nofollow">github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/app_sensor.rs</a></code>
|
||
</p>
|
||
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/7cee54bf3b5d4b8a0f5f8f01098d50b1.js"></script></p>
|
||
|
||
<p><em>Handling a Touch Sensor Event with Mynewt and
|
||
Rust should be similar to this Sensor Listener code. From <code
|
||
class="dy jw jx jy jz b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/app_sensor.rs" class="cm ir" rel="noopener nofollow">github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/app_sensor.rs</a></code>
|
||
</em></p>
|
||
|
||
<p id="a714"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">The Touch
|
||
Sensor Driver is now being implemented… As I figure out how the Hynitron CST816S I2C commands work.
|
||
Find out more in this article…</p>
|
||
<div class="ls lt lu lv lw lx"><a target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/building-a-rust-driver-for-pinetimes-touch-controller">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">Building a Rust Driver for PineTime’s Touch
|
||
Controller</h2>
|
||
<div class="mk s">
|
||
<h4 class="cg b ch ci bm mj ge gf mg gh gi ej">medium.com</h4>
|
||
</div>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="mm s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
</div>
|
||
</div>
|
||
<div class="dm">
|
||
<div class="n p">
|
||
<div class="jk jl jm jn jo jp af jq ag jr ai aj">
|
||
|
||
|
||
<p><a href="https://youtu.be/4_93mUkK--U">[Watch on YouTube]</a></p>
|
||
|
||
<p><em>Rust Driver for PineTime Touch Controller
|
||
in action. Code from <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/touch_sensor.rs"
|
||
class="cm ir"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/rust/app/src/touch_sensor.rs</a>
|
||
</em></p>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<div class="n p fl ke kf kg" role="separator"><span class="kh fz hb ki kj kk"></span><span
|
||
class="kh fz hb ki kj kk"></span><span class="kh fz hb ki kj"></span></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<h1 id="2f3d"
|
||
class="kl km en cg kn ko kp hw kq kr ks ia kt ku kv kw kx ky kz la lb lc ld le lf lg fk">Receive and
|
||
Transmit Sensor Data on PineTime Smart Watch</h1>
|
||
</div>
|
||
</div>
|
||
<div class="dm">
|
||
<div class="n p">
|
||
<div class="jk jl jm jn jo jp af jq ag jr ai aj">
|
||
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j12.png" /></p>
|
||
|
||
<p><em>Receive and Transmit Sensor Data Flow. Rust
|
||
components are coloured brown.</em></p>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<p id="2079"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><em
|
||
class="iq">What about other sensors on the PineTime… the Accelerometer and the Heart Rate
|
||
Sensor?</em></p>
|
||
<p id="5be0"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Our Rust
|
||
Application can poll them via the Mynewt Sensor Framework. Mynewt provides a Sensor Driver in C for
|
||
the <a
|
||
href="https://github.com/apache/mynewt-core/tree/master/hw/drivers/sensors/bma2xx"
|
||
class="cm ir" rel="noopener nofollow">BMA2xx Accelerometers</a> that we may customise to derive
|
||
the BMA421 Sensor Driver for PineTime. Mynewt doesn’t have a Heart Rate Sensor Driver but it should
|
||
be straightforward to create a new one, like the GPS Sensor Driver that I have created: <code
|
||
class="dy jw jx jy jz b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/pinetime/libs/gps_l70r" class="cm ir" rel="noopener nofollow">github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/pinetime/libs/gps_l70r</a></code>
|
||
</p>
|
||
<p id="0186"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><em
|
||
class="iq">What shall we do with the polled Sensor Data?</em></p>
|
||
<p id="51af"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">For some
|
||
types of Sensor Data we may choose to <strong class="ht ip">transmit them over the Bluetooth
|
||
network</strong> that’s supported by the PineTime hardware. The Nordic nRF52 microcontroller
|
||
includes a <strong class="ht ip">2.4 GHz transceiver radio</strong> that may be <strong
|
||
class="ht ip">programmed with a Bluetooth software stack</strong> so that the PineTime behaves
|
||
like a standard Bluetooth gadget.</p>
|
||
<p id="4d0d"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Most
|
||
nRF52 developers would probably use <a
|
||
href="https://infocenter.nordicsemi.com/pdf/S112_SDS_v3.1.pdf"
|
||
class="cm ir" rel="noopener nofollow">Nordic SoftDevice</a>. This is the standard firmware
|
||
provided by Nordic Semiconductor that implements the Bluetooth LE functions.</p>
|
||
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j13.png" /></p>
|
||
|
||
<p><em>Nordic SoftDevice Architecture. From <a
|
||
href="https://infocenter.nordicsemi.com/topic/struct_nrf52/struct/nrf52_softdevices.html"
|
||
class="cm ir"
|
||
rel="noopener nofollow">https://infocenter.nordicsemi.com/topic/struct_nrf52/struct/nrf52_softdevices.html</a>
|
||
</em></p>
|
||
|
||
<p id="3ffc"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">The
|
||
firmware runs as a base system layer underneath our application code and RTOS.</p>
|
||
<p id="bd36"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">
|
||
SoftDevice reserves some hardware resources for itself, like the radio transceiver, some timers and
|
||
some ROM+RAM.</p>
|
||
<p id="9935"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">The
|
||
remaining resources would be available for our application, which would call the <a
|
||
href="https://infocenter.nordicsemi.com/pdf/S112_SDS_v3.1.pdf"
|
||
class="cm ir" rel="noopener nofollow">SoftDevice API</a> to perform Bluetooth LE functions and
|
||
receive notifications.</p>
|
||
<p id="b48a"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><em
|
||
class="iq">What if we wish to experiment with the Bluetooth LE implementation… Trace it to see how
|
||
it works, tweak it to improve it, or even roll out a new Bluetooth LE protocol?</em></p>
|
||
<p id="a39d"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">
|
||
SoftDevice is clearly not meant for experimentation… Apache NimBLE is perfect for that! <a
|
||
href="https://mynewt.apache.org/latest/network/docs/index.html"
|
||
class="cm ir" rel="noopener nofollow"><strong class="ht ip">Apache NimBLE</strong></a> is an
|
||
open-source Bluetooth LE stack that <strong class="ht ip">completely replaces SoftDevice</strong>.
|
||
It’s designed to run with the Apache Mynewt embedded OS, so NimBLE feels like a typical Mynewt task.
|
||
</p>
|
||
<p id="3ed9"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><em
|
||
class="iq">Apache NimBLE is the Bluetooth LE implementation that we’re adopting for PineTime Smart
|
||
Watch.</em></p>
|
||
<p id="e58d"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Our
|
||
PineTime code now includes a fully-functional iBeacon Transmitter, to verify that our PineTime works
|
||
wirelessly indeed. Let’s probe deeper to uncover the full power of PineTime wireless networking…</p>
|
||
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j14.jpeg" /></p>
|
||
|
||
<p><em>PineTime running as an iBeacon. Check this
|
||
article for iBeacon testing instructions: <a class="cm ir" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/coding-nrf52-with-rust-and-apache-mynewt-on-visual-studio-code">https://lupyuen.github.io/articles/coding-nrf52-with-rust-and-apache-mynewt-on-visual-studio-code</a>
|
||
</em></p>
|
||
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<div class="n p fl ke kf kg" role="separator"><span class="kh fz hb ki kj kk"></span><span
|
||
class="kh fz hb ki kj kk"></span><span class="kh fz hb ki kj"></span></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<h1 id="ccf0"
|
||
class="kl km en cg kn ko kp hw kq kr ks ia kt ku kv kw kx ky kz la lb lc ld le lf lg fk">Bluetooth
|
||
Mesh and other networking options for PineTime Smart Watch</h1>
|
||
<p id="b697"
|
||
class="hr hs en ht b hu lh hw hx hy li ia ib ic lj ie if ig lk ii ij ik ll im in io dh fk">I’m
|
||
particularly excited that PineTime supports Bluetooth Mesh networking. Suppose I’m out at Taipei’s
|
||
crowded <a
|
||
href="https://en.wikipedia.org/wiki/Shilin_Night_Market"
|
||
class="cm ir" rel="noopener nofollow">Shihlin Night Market</a> <strong class="ht ip">士林夜市
|
||
</strong>with my family (and my dog)… I need to make sure that we all stay close. My son may not
|
||
always be close to me, but as long as he’s near Grandma or his siblings, I’m happy.</p>
|
||
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j15.png" /></p>
|
||
|
||
<p><em>Bluetooth Mesh of PineTime Smart Watches to
|
||
make sure that the family stays together (even the dog)</em></p>
|
||
|
||
<p id="628b"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Assuming
|
||
everyone wears a PineTime Smart Watch (even my dog), all we need to implement this proximity safety
|
||
app is a <strong class="ht ip">Bluetooth Mesh</strong>. It allows messages to be forwarded from
|
||
gadget to gadget, peer to peer. And if one of the gadgets has internet access, the messages may be
|
||
transmitted to the cloud as well. <em class="iq">Here’s an example of a </em><a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/pinetime/libs/remote_sensor"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">Mynewt network driver</em></a><em class="iq">
|
||
that routes local network messages (from nRF24L01) to the cloud (via ESP8266)</em></p>
|
||
<p id="8b19"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">I have
|
||
written a tutorial on <a class="cm ir" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/bluetooth-mesh-with-nrf52-and-apache-mynewt">Bluetooth
|
||
Mesh networking</a> with nRF52 and the NimBLE stack. It’s easy to port this to the PineTime Smart
|
||
Watch. Here’s my question for you…</p>
|
||
<p id="61c7"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><em
|
||
class="iq">What kind of networking would you need on the PineTime Smart Watch? Would you need
|
||
</em><strong class="ht ip"><em class="iq">Localised Messaging, Cloud Messaging, or
|
||
both</em></strong><em class="iq">?</em></p>
|
||
<p id="c837"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">I’ll
|
||
design the NimBLE stack and the Rust messaging API accordingly when I hear from you!</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<div class="n p fl ke kf kg" role="separator"><span class="kh fz hb ki kj kk"></span><span
|
||
class="kh fz hb ki kj kk"></span><span class="kh fz hb ki kj"></span></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<h1 id="fc84"
|
||
class="kl km en cg kn ko kp hw kq kr ks ia kt ku kv kw kx ky kz la lb lc ld le lf lg fk">Programming
|
||
the PineTime Smart Watch</h1>
|
||
<p id="5330"
|
||
class="hr hs en ht b hu lh hw hx hy li ia ib ic lj ie if ig lk ii ij ik ll im in io dh fk"><a
|
||
href="https://store.pine64.org/?product=pinetime-dev-kit"
|
||
class="cm ir" rel="noopener nofollow">PineTime is now available for purchase by general
|
||
public</a>! The source code may be found in this repository, which includes prebuilt firmware
|
||
image for PineTime…</p>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://github.com/lupyuen/pinetime-rust-mynewt"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">lupyuen/pinetime-rust-mynewt</h2>
|
||
<div class="mh s">
|
||
</div>
|
||
<div class="mk s">
|
||
<h4 class="cg b ch ci bm mj ge gf mg gh gi ej">github.com</h4>
|
||
</div>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="nk s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<p id="829d"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Check
|
||
this article for updated instructions to build and flash PineTime firmware…</p>
|
||
<div class="ls lt lu lv lw lx"><a target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/build-and-flash-rust-mynewt-firmware-for-pinetime-smart-watch">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">Build and Flash Rust+Mynewt Firmware for
|
||
PineTime Smart Watch</h2>
|
||
<div class="mh s">
|
||
</div>
|
||
<div class="mk s">
|
||
<h4 class="cg b ch ci bm mj ge gf mg gh gi ej">medium.com</h4>
|
||
</div>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="nl s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<div class="n p fl ke kf kg" role="separator"><span class="kh fz hb ki kj kk"></span><span
|
||
class="kh fz hb ki kj kk"></span><span class="kh fz hb ki kj"></span></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<h1 id="4d1e"
|
||
class="kl km en cg kn ko kp hw kq kr ks ia kt ku kv kw kx ky kz la lb lc ld le lf lg fk">Build SWD
|
||
Cradle</h1>
|
||
<p id="b87a"
|
||
class="hr hs en ht b hu lh hw hx hy li ia ib ic lj ie if ig lk ii ij ik ll im in io dh fk">To
|
||
program the PineTime Smart Watch via SWD (Serial Wire Debug), we need to construct a sturdy cradle
|
||
that exposes the four pins of the SWD port. Make sure that the watch button and the touchscreen are
|
||
accessible.</p>
|
||
<p id="408f"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">I created
|
||
my SWD cradle with Single Core Wire (22 AWG), <a
|
||
href="https://www.daisojapan.com/p-30955-clear-box-28-x-47-x-19-x-in-12pks.aspx"
|
||
class="cm ir" rel="noopener nofollow">$2 clear box cover from Daiso</a>, Blu Tack and sticky tape.
|
||
</p>
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j16.jpeg" /></p>
|
||
|
||
<p><em>SWD Cradle constructed from Single Core Wire
|
||
(22 AWG), <a
|
||
href="https://www.daisojapan.com/p-30955-clear-box-28-x-47-x-19-x-in-12pks.aspx"
|
||
class="cm ir" rel="noopener nofollow">$2 clear box cover from Daiso</a>, Blu Tack and sticky
|
||
tape</em></p>
|
||
|
||
<p id="dace"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Also
|
||
connect the 5V Charging Pad on PineTime to the 5V Pin of ST-Link. This ensures sufficient power to
|
||
all components on PineTime. And the battery gets charged properly too.</p>
|
||
<p id="7583"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">I used a
|
||
folded loop of Single Core Wire (22 AWG) like this…</p>
|
||
</div>
|
||
</div>
|
||
<div class="dm aj">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j17.jpeg" /></p>
|
||
|
||
<p><em>Connecting the 5V Charging Pad on PineTime to
|
||
the 5V Pin of ST-Link with a folded loop of Single Core Wire (22 AWG)</em></p>
|
||
|
||
</div>
|
||
</section>
|
||
<div class="n p fl ke kf kg" role="separator"><span class="kh fz hb ki kj kk"></span><span
|
||
class="kh fz hb ki kj kk"></span><span class="kh fz hb ki kj"></span></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<h1 id="7511"
|
||
class="kl km en cg kn ko kp hw kq kr ks ia kt ku kv kw kx ky kz la lb lc ld le lf lg fk">Remove
|
||
nRF52 Flash Protection</h1>
|
||
<p id="ca54"
|
||
class="hr hs en ht b hu lh hw hx hy li ia ib ic lj ie if ig lk ii ij ik ll im in io dh fk">We’ll be
|
||
flashing and debugging PineTime with a <a
|
||
href="https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20180924134644&SearchText=st-link+v2&switch_new_app=y"
|
||
class="cm ir" rel="noopener nofollow">$2 generic ST-Link V2 USB dongle</a>. ST-Link doesn’t
|
||
implement all SWD functions, just the <em class="iq">minimal set of high-level functions needed for
|
||
flashing and debugging. </em>PineTime is shipped with its flash ROM protected against tampering,
|
||
and the ST-Link can’t be used to remove the nRF52 Flash Protection.</p>
|
||
<p id="5503"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">
|
||
Fortunately there’s a way to remove the flash protection with a Raspberry Pi. (This only needs to be
|
||
done once.) Just follow the instructions in the section “<em class="iq">Advanced Topic: Remove nRF52
|
||
Flash Protection</em>” at the end of the article <em class="iq">“</em><a class="cm ir"
|
||
rel="noopener"
|
||
href="https://lupyuen.github.io/articles/coding-nrf52-with-rust-and-apache-mynewt-on-visual-studio-code"><em
|
||
class="iq">Coding nRF52 with Rust and Apache Mynewt on Visual Studio Code</em></a><em
|
||
class="iq">”</em></p>
|
||
<p id="c18b"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">The <code
|
||
class="dy jw jx jy jz b">RESET</code> pin is not needed when connecting PineTime to Raspberry Pi.
|
||
</p>
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j18.jpeg" /></p>
|
||
|
||
<p><em>Removing PineTime flash protection with a
|
||
Raspberry Pi</em></p>
|
||
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<div class="n p fl ke kf kg" role="separator"><span class="kh fz hb ki kj kk"></span><span
|
||
class="kh fz hb ki kj kk"></span><span class="kh fz hb ki kj"></span></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<h1 id="4380"
|
||
class="kl km en cg kn ko kp hw kq kr ks ia kt ku kv kw kx ky kz la lb lc ld le lf lg fk">Install
|
||
Source Code and Development Tools</h1>
|
||
<p id="a258"
|
||
class="hr hs en ht b hu lh hw hx hy li ia ib ic lj ie if ig lk ii ij ik ll im in io dh fk">Follow
|
||
the instructions in the article <em class="iq">“</em><a class="cm ir" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/install-apache-mynewt-and-embedded-rust-for-nrf52-and-visual-studio-code-on-windows-and-macos"><em
|
||
class="iq">Install Apache Mynewt and Embedded Rust for nRF52 and Visual Studio Code on Windows
|
||
and macOS</em></a><em class="iq">”.</em></p>
|
||
<p id="0dba"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Stop just
|
||
before the section <em class="iq">“Build The Firmware”</em></p>
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j19.png" /></p>
|
||
|
||
|
||
<p id="f03b"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">At the
|
||
lower left corner of Visual Studio Code, click the name of the branch and checkout the branch <code
|
||
class="dy jw jx jy jz b">origin/pinetime</code>.</p>
|
||
<p id="8997"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">This
|
||
upgrades the downloaded code to the new PineTime source code.</p>
|
||
<p id="453e"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">In the
|
||
PineTime branch, the Mynewt OS <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/hw/bsp/nrf52/syscfg.yml#L36-L50"
|
||
class="cm ir" rel="noopener nofollow">Board Support Package</a> has been updated with the correct
|
||
pins used for the SPI and I2C ports.</p>
|
||
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/7c595a6b4f6d6a4b8b50fff4faef9473.js"></script></p>
|
||
|
||
<p><em>Pins used for SPI and I2C ports on PineTime.
|
||
From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/hw/bsp/nrf52/syscfg.yml#L36-L50"
|
||
class="cm ir"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/pinetime/hw/bsp/nrf52/syscfg.yml#L36-L50</a>
|
||
</em></p>
|
||
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<div class="n p fl ke kf kg" role="separator"><span class="kh fz hb ki kj kk"></span><span
|
||
class="kh fz hb ki kj kk"></span><span class="kh fz hb ki kj"></span></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<h1 id="1f56"
|
||
class="kl km en cg kn ko kp hw kq kr ks ia kt ku kv kw kx ky kz la lb lc ld le lf lg fk">Connect
|
||
ST-Link to SWD Port</h1>
|
||
<p id="78bf"
|
||
class="hr hs en ht b hu lh hw hx hy li ia ib ic lj ie if ig lk ii ij ik ll im in io dh fk">Connect
|
||
the four pins of the PineTime SWD Port to <a
|
||
href="https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20180924134644&SearchText=st-link+v2&switch_new_app=y"
|
||
class="cm ir" rel="noopener nofollow">ST-Link</a>:<br /><code
|
||
class="dy jw jx jy jz b">SWCLK, SWDIO, 3.3V, GND</code></p>
|
||
<p id="fc6b"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Connect
|
||
ST-Link to the USB port of your computer.</p>
|
||
<p id="685d"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip"><em class="iq">UPDATE</em></strong>: <a
|
||
href="https://www.linkedin.com/posts/lupyuen_pinetime-activity-6601543125301334016-Xu57"
|
||
class="cm ir" rel="noopener nofollow">Connect the 5V pin to charge the battery as well</a></p>
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j20.jpeg" /></p>
|
||
|
||
<p><em>ST-Link connected to PineTime’s SWD Port
|
||
</em></p>
|
||
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<div class="n p fl ke kf kg" role="separator"><span class="kh fz hb ki kj kk"></span><span
|
||
class="kh fz hb ki kj kk"></span><span class="kh fz hb ki kj"></span></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<h1 id="ace9"
|
||
class="kl km en cg kn ko kp hw kq kr ks ia kt ku kv kw kx ky kz la lb lc ld le lf lg fk">Build,
|
||
Flash and Debug Firmware</h1>
|
||
<p id="9017"
|
||
class="hr hs en ht b hu lh hw hx hy li ia ib ic lj ie if ig lk ii ij ik ll im in io dh fk">Refer to
|
||
the instructions in the article <em class="iq">“</em><a class="cm ir" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/install-apache-mynewt-and-embedded-rust-for-nrf52-and-visual-studio-code-on-windows-and-macos"><em
|
||
class="iq">Install Apache Mynewt and Embedded Rust for nRF52 and Visual Studio Code on Windows
|
||
and macOS</em></a><em class="iq">”</em></p>
|
||
<p id="6dbc"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Continue
|
||
from the section <em class="iq">“Build The Firmware” </em>till the end of the article.</p>
|
||
<p id="6c9a"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">We should
|
||
be able to build, flash and debug the PineTime firmware like this…</p>
|
||
</div>
|
||
</div>
|
||
<div class="dm aj">
|
||
|
||
|
||
<p><a href="https://youtu.be/VAveAwHAg1Q">[Watch on YouTube]</a></p>
|
||
|
||
<p><em>Build, flash and debug PineTime firmware with
|
||
Visual Studio Code</em></p>
|
||
|
||
</div>
|
||
</section>
|
||
<div class="n p fl ke kf kg" role="separator"><span class="kh fz hb ki kj kk"></span><span
|
||
class="kh fz hb ki kj kk"></span><span class="kh fz hb ki kj"></span></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<h1 id="642d"
|
||
class="kl km en cg kn ko kp hw kq kr ks ia kt ku kv kw kx ky kz la lb lc ld le lf lg fk">What’s
|
||
Next?</h1>
|
||
<p id="5d16"
|
||
class="hr hs en ht b hu lh hw hx hy li ia ib ic lj ie if ig lk ii ij ik ll im in io dh fk">PineTime
|
||
firmware is still in active development by the open-source community (myself included). I’ll keep
|
||
this article updated. Here are the other articles in the PineTime series…</p>
|
||
<div class="ls lt lu lv lw lx"><a target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/building-a-rust-driver-for-pinetimes-touch-controller">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">Building a Rust Driver for PineTime’s Touch
|
||
Controller</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="mm s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/porting-druid-rust-widgets-to-pinetime-smart-watch">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">Porting [druid] Rust Widgets to PineTime
|
||
Smart Watch</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="nv s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/optimising-pinetimes-display-driver-with-rust-and-mynewt">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">Optimising PineTime’s Display Driver with
|
||
Rust and Mynewt</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="nw s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/build-and-flash-rust-mynewt-firmware-for-pinetime-smart-watch">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">Build and Flash Rust+Mynewt Firmware for
|
||
PineTime Smart Watch</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="nl s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/debug-rust-mynewt-firmware-for-pinetime-on-raspberry-pi">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">Debug Rust+Mynewt Firmware for PineTime on
|
||
Raspberry Pi</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="nx s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/my-first-week-as-embedded-foss-advocate">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">My First Week As Embedded FOSS Advocate</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="ny s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://marketplace.visualstudio.com/items?itemName=LeeLupYuen.visual-embedded-rust"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">Visual Embedded Rust</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="nz s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/chip8"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">chip8.rs: CHIP-8 Game Emulator in Rust for
|
||
PineTime Smart Watch</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="oa s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/dfu"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">Firmware Update over Bluetooth Low Energy on
|
||
PineTime Smart Watch</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="ob s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/spiflash"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">Configure Mynewt for SPI Flash on PineTime
|
||
Smart Watch (nRF52)</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="oc s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/mcuboot"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">MCUBoot Bootloader for PineTime Smart Watch
|
||
(nRF52)</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="od s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/dfutest"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">Wireless Firmware Update In Action on
|
||
PineTime Smart Watch (nRF52)</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="oe s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<p id="53d9"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">If you
|
||
have ideas how we can make PineTime more newbie-friendly for teaching and learning IoT, drop me a
|
||
note!</p>
|
||
<p id="b58f"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Also
|
||
check out my article… Do you think Visual Rust is suitable for PineTime? <em class="iq">“</em><a
|
||
href="https://lupyuen.github.io/articles/visual-embedded-rust-programming-with-visual-studio-code"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">Visual Embedded Rust Programming with Visual
|
||
Studio Code</em></a><em class="iq">”</em></p>
|
||
</div>
|
||
</div>
|
||
<div class="dm">
|
||
<div class="n p">
|
||
<div class="jk jl jm jn jo jp af jq ag jr ai aj">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/j21.jpeg" /></p>
|
||
|
||
<p><em>PineTime posing on <a
|
||
href="https://en.wikipedia.org/wiki/Domo_(NHK)"
|
||
class="cm ir" rel="noopener nofollow">Domo’s</a> furry back</em></p>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<div class="n p fl ke kf kg" role="separator"><span class="kh fz hb ki kj kk"></span><span
|
||
class="kh fz hb ki kj kk"></span><span class="kh fz hb ki kj"></span></div>
|
||
<section class="dh di dj dk dl">
|
||
<div class="n p">
|
||
<div class="ab ac ae af ag ek ai aj">
|
||
<h1 id="353a"
|
||
class="kl km en cg kn ko kp hw kq kr ks ia kt ku kv kw kx ky kz la lb lc ld le lf lg fk">References
|
||
</h1>
|
||
<p id="ddff"
|
||
class="hr hs en ht b hu lh hw hx hy li ia ib ic lj ie if ig lk ii ij ik ll im in io dh fk"><a
|
||
href="https://discordapp.com/invite/DgB7kzr"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">Chat with the PineTime Community and me
|
||
(lupyuen#4063) on Discord</em></a><em class="iq">!</em></p>
|
||
<p id="929f"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip">Mynewt + Rust</strong> port of PineTime firmware (work in progress) may be found in
|
||
this repository…</p>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://github.com/lupyuen/pinetime-rust-mynewt"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">lupyuen/pinetime-rust-mynewt</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="of s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<p id="b6ac"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip">TinyGo</strong> version of PineTime firmware…</p>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://github.com/aykevl/go-smartwatch"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">aykevl/go-smartwatch</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="og s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<p id="ba80"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip">Zephyr OS</strong> version…</p>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://github.com/najnesnaj/pinetime-zephyr"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">najnesnaj/pinetime-zephyr</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="oh s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://github.com/Dejvino/pinetime-hermes-firmware.git"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">Dejvino/pinetime-hermes-firmware</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="oi s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://github.com/endian-albin/pinetime-hypnos"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">endian-albin/pinetime-hypnos</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="oj s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<p id="82fb"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip">FreeRTOS</strong> version…</p>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://github.com/JF002/Pinetime"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">JF002/Pinetime</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="ok s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<p id="9fe9"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip">RIOT-OS</strong> version…</p>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://github.com/bosmoment/PineTime-apps"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">bosmoment/PineTime-apps</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="ol s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<p id="7e45"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><em
|
||
class="iq">I streamed a Live Debugging session for RIOT-OS on PineTime, without any prior
|
||
knowledge of RIOT-OS. Here are my findings…</em></p>
|
||
<div class="ls lt lu lv lw lx"><a target="_blank" rel="noopener"
|
||
href="https://web.archive.org/https://medium.com/@ly.lee/debug-riot-os-on-pinetime-with-vscode-12f00c69c120">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">Debug RIOT-OS on PineTime with VSCode</h2>
|
||
</div>
|
||
</a></div>
|
||
<p id="9bf5"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip">RIOT-OS</strong> with Rust…</p>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://github.com/lupyuen/PineTime-apps"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">lupyuen/PineTime-apps</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="on s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<p id="0cd9"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip">MicroPython</strong> version…</p>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://github.com/daniel-thompson/wasp-os"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">daniel-thompson/wasp-os</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="oo s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<p id="0bd0"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip">Rust RTFM</strong> versions…</p>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://github.com/wose/xochron" target="_blank"
|
||
rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">wose/xochron</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="op s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://github.com/dbrgn/pinetime-rtfm"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">dbrgn/pinetime-rtfm</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="oq s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<p id="f7bc"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk">Arduino
|
||
version…</p>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://github.com/atc1441/ATCwatch"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">atc1441/ATCwatch</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="or s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://wiki.pine64.org/index.php/PineTime"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">PineTime Wiki</h2>
|
||
</div>
|
||
<div class="ml s">
|
||
<div class="os s mn mo mp ml mq mr lx"></div>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<div class="ls lt lu lv lw lx"><a
|
||
href="https://forum.pine64.org/forumdisplay.php?fid=134"
|
||
target="_blank" rel="noopener nofollow">
|
||
<div class="ly n aq">
|
||
<div class="lz n ma p mb mc">
|
||
<h2 class="eo b md me bm mf ge gf mg gh gi em fk">PineTime Forum</h2>
|
||
</div>
|
||
</div>
|
||
</a></div>
|
||
<p id="e106"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip">Nordic nRF52 Microcontroller</strong></p>
|
||
<ul class="">
|
||
<li id="5675"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io is it iu fk">
|
||
<a href="https://infocenter.nordicsemi.com/pdf/nRF52832_PS_v1.0.pdf"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">Nordic Semiconductor nRF52832 Product
|
||
Specification v1.0</em></a></li>
|
||
</ul>
|
||
<p id="a038"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip">Hynitron CST816S Touch Controller</strong></p>
|
||
<ul class="">
|
||
<li id="aca7"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io is it iu fk">
|
||
<a href="https://github.com/lupyuen/hynitron_i2c_cst0xxse"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">Reference Code for Hynitron CST816S Touch
|
||
Controller</em></a></li>
|
||
</ul>
|
||
<p id="d38b"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip">TianYiHeXin HRS3300 PPG Heart Rate Sensor</strong></p>
|
||
<ul class="">
|
||
<li id="b8b6"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io is it iu fk">
|
||
<a href="http://www.tianyihexin.com/pic/file/20170627/20170627154837943794.pdf"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">HRS3300 PPG Heart Rate Sensor Design Guide
|
||
in Chinese</em></a></li>
|
||
<li id="ca83"
|
||
class="hr hs en ht b hu iv hw hx hy iw ia ib ic ix ie if ig iy ii ij ik iz im in io is it iu fk">
|
||
<a href="https://github.com/lupyuen/hrs3300_sprd"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">Reference Code for HRS3300 PPG Heart Rate
|
||
Sensor</em></a></li>
|
||
<li id="7a03"
|
||
class="hr hs en ht b hu iv hw hx hy iw ia ib ic ix ie if ig iy ii ij ik iz im in io is it iu fk">
|
||
<a href="https://github.com/atc1441/HRS3300-Arduino-Library"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">Arduino Driver for HRS3300 PPG Heart Rate
|
||
Sensor</em></a></li>
|
||
</ul>
|
||
<p id="50ae"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip">Bosch BMA421 Accelerometer</strong></p>
|
||
<ul class="">
|
||
<li id="a2c1"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io is it iu fk">
|
||
<a href="https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMA423-DS000.pdf"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">Datasheet for Bosch BMA423
|
||
Accelerometer</em></a><em class="iq"> (should be similar to BMA421)</em></li>
|
||
</ul>
|
||
<p id="a474"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io dh fk"><strong
|
||
class="ht ip">Sitronix ST7789 LCD Display Controller</strong></p>
|
||
<ul class="">
|
||
<li id="314c"
|
||
class="hr hs en ht b hu hv hw hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io is it iu fk">
|
||
<a href="https://github.com/adafruit/Adafruit-ST7735-Library"
|
||
class="cm ir" rel="noopener nofollow"><em class="iq">Arduino Driver for ST7735 and ST7789 by
|
||
Adafruit</em></a><em class="iq"> (to identify differences between ST7735 and ST7789)</em></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/sponsors/lupyuen">Sponsor me a coffee</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>
|
||
|
||
</body>
|
||
|
||
</html>
|
||
<!--
|
||
FILE ARCHIVED ON 13:09:33 Nov 24, 2020 AND RETRIEVED FROM THE
|
||
INTERNET ARCHIVE ON 10:34:12 Feb 21, 2021.
|
||
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
|
||
|
||
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
|
||
SECTION 108(a)(3)).
|
||
-->
|
||
<!--
|
||
playback timings (ms):
|
||
exclusion.robots: 0.244
|
||
esindex: 0.01
|
||
load_resource: 90.018
|
||
captures_list: 185.621
|
||
PetaboxLoader3.resolve: 58.86
|
||
exclusion.robots.policy: 0.233
|
||
PetaboxLoader3.datanode: 123.366 (4)
|
||
RedisCDXSource: 3.975
|
||
LoadShardBlock: 146.938 (3)
|
||
CDXLines.iter: 29.585 (3)
|
||
--> |