-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.xml
3175 lines (2333 loc) · 294 KB
/
index.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Ashwin Narayan</title>
<link>https://www.ashwinnarayan.com/</link>
<atom:link href="https://www.ashwinnarayan.com/index.xml" rel="self" type="application/rss+xml" />
<description>Ashwin Narayan</description>
<generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>en-us</language><copyright>© 2020 Ashwin Narayan</copyright><lastBuildDate>Sun, 06 Oct 2024 20:04:51 +0800</lastBuildDate>
<image>
<url>https://www.ashwinnarayan.com/images/icon_hu0b7a4cb9992c9ac0e91bd28ffd38dd00_9727_512x512_fill_lanczos_center_3.png</url>
<title>Ashwin Narayan</title>
<link>https://www.ashwinnarayan.com/</link>
</image>
<item>
<title>Writing a small async runtime for Cortex-M micro-controllers with Rust</title>
<link>https://www.ashwinnarayan.com/post/embedded-async-with-rust/</link>
<pubDate>Sun, 06 Oct 2024 20:04:51 +0800</pubDate>
<guid>https://www.ashwinnarayan.com/post/embedded-async-with-rust/</guid>
<description><h2 id="introduction">Introduction</h2>
<p>I&rsquo;ve been working with Rust on microcontrollers for a while now, and I&rsquo;ve been using the excellent embassy crate for async programming. However, I recently started using a processor for which embassy does not have Hardware Abstraction Layer (HAL) support, and I wanted to experiment with building my own async runtime. This was also a great opportunity to learn more about the processor and understand the implementation details of async/await in Rust.</p>
<p>In this article, we&rsquo;ll create an async runtime for ARM Cortex-M microcontrollers. We&rsquo;ll build on Philipp Oppermann&rsquo;s work for x86 bare-metal systems here and adapt the approach for Cortex-M, which presents unique challenges like limited memory and often lacking a Memory Management Unit (MMU). These constraints require different design choices for async primitives, executors, and interrupt handling.</p>
<p>Note that this is an experimental project focused on learning and exploration. It is not production-ready, but it serves as a good starting point for building your own async runtime for embedded systems. If you&rsquo;re looking for mature libraries for running real-time code on embedded systems, consider using
<a href="https://embassy.dev" target="_blank" rel="noopener">embassy</a> or
<a href="https://rtic.rs" target="_blank" rel="noopener">rtic</a>.</p>
<p>We will cover:</p>
<ol>
<li>Building a lightweight executor for embedded systems</li>
<li>Implementing tasks in an async context</li>
<li>Utilizing power-saving features to sleep the microcontroller when no tasks are active</li>
</ol>
<p>By the end of this article, you&rsquo;ll understand the basics of creating a custom async runtime and how it can be adapted to a resource-constrained environment like Cortex-M microcontrollers.</p>
<h2 id="why-build-your-own-async-runtime">Why Build Your Own Async Runtime?</h2>
<p>Building an async runtime from scratch is not just a fun exercise but a useful way to understand how embedded systems handle concurrent tasks. This is particularly important for real-time systems that need to manage limited resources, such as processing power and memory. You&rsquo;ll also be forced to become familiar with the inner workings the underlying hardware peripherals on the microcontroller and how they interact with the runtime. In a world where abstractions are stacked liberally and the typical developer is separated from the hardware by multiple layers of abstraction, this exercise can be a refreshing change of pace.</p>
<p>With existing libraries like Embassy, you can quickly get started with async programming on supported hardware. However, there might be scenarios where support for specific hardware is not available, or you need more control over how tasks are managed. This article aims to bridge that gap by helping you understand what it takes to write a custom runtime for such cases.</p>
<h2 id="what-is-async-programming">What is Async Programming?</h2>
<p>In Rust, async/await allows you to write asynchronous code that looks very similar to synchronous code. It allows you to write code that can pause and resume execution without blocking the entire system, which is particularly useful for handling tasks like I/O operations, waiting for timers, or running multiple concurrent tasks.</p>
<p>The async model in Rust uses cooperative multitasking, where tasks yield control back to the executor when they are waiting for something to happen. This is different from preemptive multitasking, where an operating system controls task switching. Cooperative multitasking has the advantage of being predictable and having lower overhead, but it requires each task to explicitly yield control and be well-behaved.</p>
<p>For embedded systems, cooperative multitasking often works well because it keeps the system simple and avoids the overhead of complex task switching, which is critical when working with constrained environments like microcontrollers.</p>
<h2 id="how-async-works-in-rust">How Async Works in Rust</h2>
<p>In Rust, async functions implement the Future trait. Futures can be polled using the poll() method. If a future is ready to produce a value, it returns Poll::Ready(T); otherwise, it returns Poll::Pending. The executor is responsible for polling these futures and managing the lifecycle of tasks.</p>
<p>The executor works by polling each task until it completes. It acts as the &ldquo;runtime&rdquo; that runs the tasks concurrently and keeps them progressing. For more details on how this works, I recommend checking out
<a href="https://os.phil-opp.com/async-await" target="_blank" rel="noopener">Phil Oppermann&rsquo;s blog</a>.</p>
<h2 id="async-execution-workflow">Async Execution Workflow</h2>
<p>Below is a visual representation of how an async executor manages tasks and keeps polling them until completion.</p>
<pre><code class="language-mermaid">graph TD
subgraph Executor
A[Task Queue] --&gt; B[Task Polling]
end
subgraph Task
D[Future] --&gt; E[Poll Function]
end
A --&gt; F[Task Scheduler]
F --&gt; E
E --&gt; G{Poll Result}
G --&gt;|Pending| F
G --&gt;|Ready| H[Complete Task]
M[Sleep if Idle] --&gt; F
</code></pre>
<p>This diagram shows how the executor maintains a queue of tasks, polls them to determine their state, and schedules them accordingly. If there are no tasks to execute, the executor can put the processor to sleep to save power.</p>
<h2 id="defining-a-task">Defining a Task</h2>
<p>Each task in our runtime is represented as a <code>Future</code> pinned in memory, ensuring it can be polled without being moved. This is crucial because futures created by <code>async</code>/<code>await</code> may be self-referential, and moving them in memory would invalidate references to their internal fields.</p>
<p>Embedded environments typically don&rsquo;t have access to standard memory allocators, so we need to initialize a custom heap allocator. We&rsquo;ll use the <code>embedded_alloc</code> crate, which is designed for embedded systems. Below is the implementation of our task and how it uses atomic counters for task IDs.</p>
<pre><code class="language-rust">// Import the 'alloc' crate, which provides memory allocation utilities.
// Necessary for dynamic memory allocation in a no_std environment.
extern crate alloc;
// Importing 'Box' from the 'alloc' crate. Box is a smart pointer for heap-allocated memory.
use alloc::boxed::Box;
// Importing 'addr_of_mut' from core::ptr to get the mutable pointer to the heap memory.
use core::ptr::addr_of_mut;
// Importing 'AtomicU32' and 'Ordering' to manage atomic operations in a multi-threaded or interrupt context.
use core::sync::atomic::{AtomicU32, Ordering};
// Importing essential types for async and future handling from core: Future, Pin, Context, and Poll.
use core::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
// Importing LlffHeap as Heap from 'embedded_alloc' crate, which provides a memory allocator suitable for embedded systems.
use embedded_alloc::LlffHeap as Heap;
// Define a global allocator for heap memory. We use a static instance of Heap here.
#[global_allocator]
static HEAP: Heap = Heap::empty(); // The heap is initially empty and needs to be initialized.
/// Initialize the heap.
pub fn init_heap() {
use core::mem::MaybeUninit; // Use 'MaybeUninit' to represent uninitialized memory safely.
const HEAP_SIZE: usize = 1024; // Define the size of the heap in bytes.
// Allocate an uninitialized array of bytes (of type MaybeUninit&lt;u8&gt;), which will serve as the heap.
static mut HEAP_MEM: [MaybeUninit&lt;u8&gt;; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
// Initialize the heap using the starting address and size of the memory array. 'unsafe' is required
// because we are using raw pointers and modifying static mutable data.
unsafe { HEAP.init(addr_of_mut!(HEAP_MEM) as usize, HEAP_SIZE) }
}
/// Task ID type. We use a 32-bit unsigned integer to represent a task ID.
/// Cortex-M architecture is 32-bit, and it doesn't support atomic 64-bit integers.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct TaskId(u32); // TaskId is a wrapper around a 32-bit unsigned integer.
impl TaskId {
/// Generate a new unique task ID.
fn new() -&gt; Self {
static NEXT_ID: AtomicU32 = AtomicU32::new(0); // Static AtomicU32 that stores the next available task ID.
TaskId(NEXT_ID.fetch_add(1, Ordering::Relaxed)) // Increment and return the current ID.
}
}
/// Base struct to represent a task.
pub struct Task {
/// A unique identifier for the task.
id: TaskId, // Each task has a unique TaskId.
/// The future representing the task. The Pin&lt;Box&lt;&gt;&gt; wrapper ensures that the
/// future is not moved in memory. The Output type of the future is (), indicating
/// that the future does not return a value - it just runs to completion.
future: Pin&lt;Box&lt;dyn Future&lt;Output = ()&gt;&gt;&gt;, // The 'Pin' ensures that the future is pinned in memory and cannot be moved.
}
impl Task {
/// Create a new task from a future.
pub fn new(future: impl Future&lt;Output = ()&gt; + 'static) -&gt; Task {
Task {
id: TaskId::new(), // Assign a new unique TaskId to the task.
future: Box::pin(future), // Pin the future to ensure it is not moved in memory and store it in a Box.
}
}
/// Poll the task. This checks whether the future is ready to make progress or has completed.
/// 'poll' uses a mutable reference to the task's future and a context to manage async execution.
fn poll(&amp;mut self, context: &amp;mut Context) -&gt; Poll&lt;()&gt; {
self.future.as_mut().poll(context) // Poll the pinned future and pass the provided Context.
}
}
// A module declaration for 'executor', the runtime that manages task execution.
pub mod executor;
</code></pre>
<p>In this implementation, <code>TaskId</code> is used to uniquely identify each task, and we use a 32-bit atomic counter to generate these IDs. This approach avoids the overhead of locking and works well in a 32-bit environment like Cortex-M.</p>
<h2 id="implementing-the-executor">Implementing the Executor</h2>
<p>The executor is responsible for managing tasks and running them to completion. It uses a task queue to determine which tasks are ready to run, and a custom <code>TaskWaker</code> to wake up tasks when they are ready to make progress.</p>
<p>Below is an implementation of the executor that runs tasks in a loop, polling each until they are complete.</p>
<pre><code class="language-rust">extern crate alloc;
use super::*;
use alloc::collections::{BTreeMap, VecDeque};
use alloc::sync::Arc;
use alloc::task::Wake;
use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use cortex_m::asm;
use crossbeam_queue::ArrayQueue;
// The custom waker struct for waking tasks.
struct TaskWaker {
task_id: TaskId, // Unique identifier for the task.
task_queue: Arc&lt;ArrayQueue&lt;TaskId&gt;&gt;, // Shared queue used to store task IDs ready to be executed.
}
impl TaskWaker {
// Create a new waker instance for a given task.
fn new(task_id: TaskId, task_queue: Arc&lt;ArrayQueue&lt;TaskId&gt;&gt;) -&gt; Waker {
Waker::from(Arc::new(TaskWaker {
task_id,
task_queue,
}))
}
// Add the task to the task queue, making it ready to be polled again.
fn wake_task(&amp;self) {
self.task_queue
.push(self.task_id)
.expect(&quot;Task queue is full!&quot;);
}
}
impl Wake for TaskWaker {
// Wakes the task by adding it back to the task queue.
fn wake(self: Arc&lt;Self&gt;) {
self.wake_task();
}
// Wake the task by reference, allowing it to be added to the task queue without consuming the waker.
fn wake_by_ref(self: &amp;Arc&lt;Self&gt;) {
self.wake_task();
}
}
/// Task executor that runs tasks to completion.
pub struct Executor {
/// Map of tasks to be run, indexed by task ID.
tasks: BTreeMap&lt;TaskId, Task&gt;,
/// Queue holding task IDs that are ready to be executed.
task_queue: Arc&lt;ArrayQueue&lt;TaskId&gt;&gt;,
/// Cache for storing wakers for tasks that are currently running.
waker_cache: BTreeMap&lt;TaskId, Waker&gt;,
}
impl Executor {
/// Create a new executor with an empty task queue.
pub fn new&lt;const N: usize&gt;() -&gt; Executor {
Executor {
tasks: BTreeMap::new(),
task_queue: Arc::new(ArrayQueue::new(N)), // Initialize task queue with a capacity of N.
waker_cache: BTreeMap::new(),
}
}
/// Add a new task to the executor.
pub fn spawn(&amp;mut self, task: Task) {
let task_id = task.id;
if self.tasks.insert(task_id, task).is_some() {
panic!(&quot;task with same ID already in tasks&quot;);
}
self.task_queue.push(task_id).expect(&quot;Task queue is full.&quot;); // Add the task ID to the task queue.
}
/// Run all tasks that are ready to execute.
fn run_ready_tasks(&amp;mut self) {
// Continuously pop task IDs from the task queue and run them.
while let Some(task_id) = self.task_queue.pop() {
// Retrieve the task using its task ID.
let task = match self.tasks.get_mut(&amp;task_id) {
Some(task) =&gt; task,
None =&gt; continue, // If the task doesn't exist, skip it.
};
// Retrieve or create a waker for the task.
let waker = self
.waker_cache
.entry(task_id)
.or_insert_with(|| TaskWaker::new(task_id, self.task_queue.clone()));
// Create a new context from the waker.
let mut context = Context::from_waker(waker);
// Poll the task to determine if it is ready to make progress.
match task.poll(&amp;mut context) {
Poll::Ready(()) =&gt; {
// If the task is complete, remove it and its waker from the cache.
self.tasks.remove(&amp;task_id);
self.waker_cache.remove(&amp;task_id);
}
Poll::Pending =&gt; {} // If the task is not complete, leave it in the task list.
}
}
}
/// Put the processor to sleep if there are no tasks to run.
fn sleep_if_idle(&amp;self) {
cortex_m::interrupt::free(|_| {
// If the task queue is empty, put the processor to sleep.
if self.task_queue.is_empty() {
asm::wfi(); // Wait for interrupt to wake up the processor.
}
});
}
/// Run the executor to completion, continuously executing tasks until none are left.
pub fn run(&amp;mut self) {
loop {
self.run_ready_tasks();
self.sleep_if_idle();
}
}
}
</code></pre>
<p>The Executor structure maintains a map of tasks, a task queue, and cached wakers for tasks that are currently running. The run method continuously runs tasks until none are left, and the <code>sleep_if_idle</code> method puts the processor to sleep when there are no tasks to execute. As mentioned
<a href="https://github.com/phil-opp/blog_os/discussions/1018#discussioncomment-863025" target="_blank" rel="noopener">here</a> the <code>wfi</code> instruction can be used to wait for an event or interrupt.</p>
<h2 id="putting-it-all-together">Putting it all together</h2>
<p>Below is an example of how to put everything together to run a simple async task on a Cortex-M microcontroller.</p>
<pre><code class="language-rust">#![no_std]
#![no_main]
use cortex_m_asyncrt::os::{self, executor, init_heap, Task};
use cortex_m_rt::entry;
use cortex_m_semihosting::{dbg, hprintln};
// use panic_probe as _;
use panic_semihosting as _;
#[entry]
fn main() -&gt; ! {
init_heap();
hprintln!(&quot;Hello, worlds!&quot;);
// New executor that can run up to 32 tasks
let mut executor = executor::Executor:: new::&lt;64&gt;();
// Spawn a task
executor.spawn(Task::new(example_task()));
// Run the executor
executor.run();
// This code is unreachable because the executor.run() function runs tasks to completion.
loop {}
}
async fn example_task() {
// your code goes here
let r = example_fn().await;
hprintln!(&quot;r = {}&quot;, r);
}
async fn example_fn() -&gt; u32 {
42
}
</code></pre>
<p>If you run this code on QEMU you should see the following output:</p>
<pre><code class="language-shell">Timer with period zero, disabling
Hello, worlds!
r = 42
</code></pre>
<p>If you want to try this out yourself, you can use the <code>cortex-m-asyncrt</code> crate on
<a href="https://crates.io/crates/cortex-m-asyncrt" target="_blank" rel="noopener">crates.io</a>. Version 0.1.0 of the crate is exactly as described in this article.</p>
<h2 id="real-world-use-cases-and-future-work">Real-World Use Cases and Future Work</h2>
<p>This async runtime could be applied to scenarios where you need a lightweight scheduler for real-time tasks, such as sensor data collection, motor control, or communication handling in resource-constrained embedded systems.</p>
<p>Future improvements could include adding task priority, enhancing the scheduler with time measurements for scheduling tasks at regular intervals and for asynchronously <code>await</code>ing delays.</p>
<h2 id="references">References</h2>
<ol>
<li>
<a href="https://os.phil-opp.com/async-await" target="_blank" rel="noopener">Philipp Oppermann&rsquo;s blog on async/await</a></li>
<li>
<a href="https://embassy.dev" target="_blank" rel="noopener">embassy</a></li>
<li>
<a href="https://rtic.rs" target="_blank" rel="noopener">rtic</a></li>
<li>
<a href="https://crates.io/crates/cortex-m-asyncrt" target="_blank" rel="noopener">cortex-m-asyncrt crate</a></li>
</ol>
</description>
</item>
<item>
<title>Blinking LEDs with Rust</title>
<link>https://www.ashwinnarayan.com/post/embedded-rust-blinking-led/</link>
<pubDate>Thu, 02 May 2024 15:38:20 +0800</pubDate>
<guid>https://www.ashwinnarayan.com/post/embedded-rust-blinking-led/</guid>
<description><p>Rust is a modern programming language focused on safety, speed, and concurrency. It&rsquo;s a go-to for system-level tasks, offering strong guarantees against common bugs like null pointer dereferences. Embedded systems, with their resource constraints and real-time demands, could really benefit from more Rust. Rust&rsquo;s zero-cost abstractions maintain performance while keeping code size small. Real-time requirements are met through precise hardware interaction, aided by Rust&rsquo;s features like immutable variables and robust type systems. With cross-compilation capabilities and a growing library ecosystem, Rust has recently become (in my opinion) a viable choice for embedded development.</p>
<p>Rust is also the first new programming language that I&rsquo;ve learned since Haskell and I really like how it combines the best of functional programming with the best of systems programming. I&rsquo;ve been playing around with Rust for a while now and I wanted to try my hand at embedded development with Rust. In this post, I&rsquo;ll show you how to blink an LED on an STM32F407 Discovery board using Rust.</p>
<h2 id="the-stm32f407-discovery-board">The STM32F407 Discovery Board</h2>
<p>The
<a href="https://www.st.com/en/evaluation-tools/stm32f4discovery.html" target="_blank" rel="noopener">STM32F407 Discovery</a> board is a development board based on the STM32F407VG microcontroller. The board uses an STM32F407 micro-controller and has plenty of LEDs, some push buttons, an accelerometer, a microphone and an audio DAC. Plenty of peripherals to play around with. The
<a href="https://www.st.com/resource/en/user_manual/um1472-discovery-kit-with-stm32f407vg-mcu-stmicroelectronics.pdf" target="_blank" rel="noopener">user manual</a> has the pinouts and list of peripherals.</p>
<h2 id="setting-up-rust-for-embedded-development">Setting Up Rust for Embedded Development</h2>
<p>First follow the instructions from
<a href="https://rustup.rs" target="_blank" rel="noopener">rustup.rs</a> to install rust.</p>
<pre><code class="language-bash">curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
</code></pre>
<p>To compile rust for our micro-controller, we need to let it know what target to compile for. Microcontrollers like the STM32 use the thumb instruction set, which is a subset of the ARM instruction set. Rust has a target for the thumb instruction set, so we need to install it.</p>
<pre><code class="language-bash">rustup target add thumbv7em-none-eabihf
</code></pre>
<p>Next, we need to create a new empty project using cargo.</p>
<pre><code class="language-bash">cargo new --bin blinky
</code></pre>
<p>Cargo needs some more information to build for a microcontroller. So we need a <code>.cargo/config.toml</code> file in the project directory with the following contents:</p>
<pre><code class="language-toml">[target.'cfg(all(target_arch = &quot;arm&quot;, target_os = &quot;none&quot;))']
# replace STM32F407VG with your chip as listed in `probe-rs chip list`
runner = &quot;probe-rs run --chip STM32F407VG&quot;
[target.thumbv7em-none-eabihf]
rustflags = [&quot;-C&quot;, &quot;link-arg=-Tlink.x&quot;]
[build]
target = &quot;thumbv7em-none-eabihf&quot;
[env]
DEFMT_LOG = &quot;trace&quot;
</code></pre>
<p>Also useful are some tools that can be used to prepare the binary for flashing onto the microcontroller. We can install these tools using cargo.</p>
<pre><code class="language-bash">cargo install cargo-binutils
rustup component add llvm-tools-preview
</code></pre>
<h2 id="libraries">Libraries</h2>
<p>Rust has a lot of libraries already that support the hardware of the STM32, which makes things very convenient for us. Rust also has an excellent library called
<a href="https://embassy.dev" target="_blank" rel="noopener">embassy</a> - a lightweight async/await runtime that is designed to work on embedded devices. It is built on top of the <code>cortex-m</code> crate, which provides low-level access to the ARM Cortex-M processors. In traditional C++ based embedded development, you would use an embedded RTOS like FreeRTOS or MBED OS to manage tasks and interrupts. However, with embasst, you can use the async/await syntax to write concurrent code that is (in my opinion) much easier to reason about and debug.</p>
<p>To use embassy, add the following dependencies to your <code>Cargo.toml</code> file:</p>
<pre><code class="language-toml">[package]
name = &quot;stm32f407_tests&quot;
authors = [&quot;Ashwin Narayan &lt; [email protected] &gt;&quot;]
version = &quot;0.1.0&quot;
edition = &quot;2021&quot;
[[bin]]
name = &quot;blinky&quot;
path = &quot;src/bin/blinky.rs&quot;
test = false
bench = false
# Set up the release profile to optimize our binaries
[profile.release]
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations
opt-level = &quot;s&quot; # Optimize for size
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
embassy-stm32 = { version = &quot;0.1.0&quot;, features = [
&quot;stm32f407vg&quot;,
&quot;unstable-pac&quot;,
&quot;memory-x&quot;,
&quot;time-driver-any&quot;,
&quot;exti&quot;,
&quot;chrono&quot;,
] }
embassy-executor = { version = &quot;0.5.0&quot;, features = [
&quot;integrated-timers&quot;,
&quot;arch-cortex-m&quot;,
&quot;executor-thread&quot;,
] }
embassy-time = { version = &quot;0.3.0&quot; }
embassy-sync = { version = &quot;0.5.0&quot; }
cortex-m = { version = &quot;0.7&quot;, features = [&quot;critical-section-single-core&quot;] }
cortex-m-rt = &quot;0.7&quot;
panic-probe = { version = &quot;0.3&quot; }
</code></pre>
<p>We will then delete the <code>src/main.rs</code> file and create a new file <code>src/bin/blinky.rs</code> that will contain our code to blink our LEDs.</p>
<h2 id="blinking-an-led">Blinking an LED</h2>
<p>First, the code:</p>
<pre><code class="language-rust">#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_time::{Duration, Ticker};
use panic_probe as _;
fn clock_config() -&gt; embassy_stm32::Config {
let mut config = embassy_stm32::Config::default();
// Configure to use the high speed internal oscillator (HSI).
config.rcc.hsi = true;
config
}
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
// Initialize embassy
let peripherals = embassy_stm32::init(clock_config());
// Create a new output pin - PA9 is the green led on the Discovery board
let mut green_led = Output::new(peripherals.PA9, Level::High, Speed::VeryHigh);
let mut red_led = Output::new(peripherals.PD5, Level::High, Speed::VeryHigh);
let mut green_led2 = Output::new(peripherals.PD12, Level::High, Speed::VeryHigh);
let mut orange_led = Output::new(peripherals.PD13, Level::High, Speed::VeryHigh);
let mut red_led2 = Output::new(peripherals.PD14, Level::High, Speed::VeryHigh);
let mut blue_led = Output::new(peripherals.PD15, Level::High, Speed::VeryHigh);
// Create a new Ticker for the delay
let mut ticker = Ticker::every(Duration::from_millis(100));
loop {
// Wait for the ticker to expire
ticker.next().await;
// Toggle the leds
green_led.toggle();
red_led.toggle();
green_led2.toggle();
orange_led.toggle();
red_led2.toggle();
blue_led.toggle();
}
}
</code></pre>
<p>Now let&rsquo;s go through the code step by step and understand what each part does.</p>
<h3 id="no-standard-library-and-no-main">No Standard Library and No Main</h3>
<pre><code class="language-rust">#![no_std]
#![no_main]
</code></pre>
<p><code>#![no_std]</code> tells the rust compiler that we are building a binary without the standard library and <code>#![no_main]</code> tells the Rust compiler that this program does not use the conventional main function as its entry point. This is typical in embedded applications where the entry point needs to conform to specific requirements or where the startup is handled by the hardware or a framework.</p>
<h3 id="importing-libraries">Importing Libraries</h3>
<p>Next, the library imports.</p>
<ul>
<li>Spawner from embassy_executor is used to handle task spawning in an async environment.</li>
<li>From embassy_stm32::gpio, we import Level, Output, and Speed to configure GPIO pins.</li>
<li>Duration and Ticker from embassy_time are used to handle time-related functions like delays.</li>
<li>panic_probe is a library used for better panic messages in embedded systems; the as _ means it&rsquo;s used for its side effects (setting up panic handling) and not for its symbols.</li>
</ul>
<pre><code class="language-rust">use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_time::{Duration, Ticker};
use panic_probe as _;
</code></pre>
<h3 id="clock-configuration">Clock Configuration</h3>
<p>This function sets up the clock configuration for the STM32 microcontroller. It enables the High-Speed Internal oscillator (HSI) which is one of the clock sources that can drive the system clock.</p>
<pre><code class="language-rust">fn clock_config() -&gt; embassy_stm32::Config {
let mut config = embassy_stm32::Config::default();
config.rcc.hsi = true; // Configure to use the high speed internal oscillator (HSI).
config
}
</code></pre>
<h3 id="main-function">Main Function</h3>
<p>The <code>#[embassy_executor::main]</code> attribute macro marks this asynchronous function as the entry point of the program. The function takes a Spawner argument for potentially spawning new asynchronous tasks. It initializes the STM32 peripherals according to our configuration.</p>
<pre><code class="language-rust">#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let peripherals = embassy_stm32::init(clock_config());
</code></pre>
<h3 id="gpio-pins">GPIO Pins</h3>
<p>Next, we set up our GPIO pins according to the discovery board&rsquo;s pinout. We create Output instances for each LED pin, specifying the pin number, initial level, and speed. The pins are configured as outputs, and the initial level is set to High. The speed is set to VeryHigh, which is the fastest speed available. The speed specifies the maximum frequency at which the pin can be toggled.</p>
<pre><code class="language-rust">let mut green_led = Output::new(peripherals.PA9, Level::High, Speed::VeryHigh);
...
let mut blue_led = Output::new(peripherals.PD15, Level::High, Speed::VeryHigh);
</code></pre>
<h3 id="ticker-for-delays">Ticker for Delays</h3>
<pre><code class="language-rust">let mut ticker = Ticker::every(Duration::from_millis(100));
</code></pre>
<p>Ticker is an <code>embassy_time</code> construct. The <code>embassy_time</code> crate provides time-related functionality for embedded systems. The <code>Ticker::every(Duration::from_millis(100))</code> creates a new Ticker that expires every 100 milliseconds.</p>
<h3 id="the-main-loop">The Main Loop</h3>
<pre><code class="language-rust">loop {
ticker.next().await;
green_led.toggle();
...
blue_led.toggle();
}
</code></pre>
<p>The main loop waits for the ticker to expire, toggles the LEDs, and repeats the process indefinitely. The <code>ticker.next().await</code> suspends the task until the ticker expires, allowing the LEDs to blink at regular intervals. The <code>toggle()</code> method changes the state of the LED from on to off and vice versa.</p>
<h2 id="the-result">The Result</h2>
<p><img src="blinky.gif" alt="Blinking LEDs"></p>
<p>If you want to take a look at the code, the full repository is available at my
<a href="https://github.com/RationalAsh/stm32f407-tests-rs" target="_blank" rel="noopener">github</a>.</p>
<h2 id="references">References</h2>
<ol>
<li>
<a href="https://www.rust-lang.org/" target="_blank" rel="noopener">Rust Programming Language</a></li>
<li>
<a href="https://rust-embedded.github.io/book/" target="_blank" rel="noopener">Rust Embedded</a></li>
<li>
<a href="https://embassy.dev" target="_blank" rel="noopener">Embassy</a></li>
<li>
<a href="https://rustup.rs" target="_blank" rel="noopener">Rustup</a></li>
<li>
<a href="https://www.st.com/en/evaluation-tools/stm32f4discovery.html" target="_blank" rel="noopener">STM32F407 Discovery</a></li>
<li>
<a href="https://www.st.com/resource/en/user_manual/um1472-discovery-kit-with-stm32f407vg-mcu-stmicroelectronics.pdf" target="_blank" rel="noopener">STM32F407VG User Manual</a></li>
</ol>
</description>
</item>
<item>
<title>Reusable Forms in Swiftui</title>
<link>https://www.ashwinnarayan.com/post/reusable-forms-swiftui/</link>
<pubDate>Sun, 19 Mar 2023 13:52:25 +0800</pubDate>
<guid>https://www.ashwinnarayan.com/post/reusable-forms-swiftui/</guid>
<description><p>I’ve been recently doing a lot of programming using Swift and I’m quite enjoying how intuitive it is to pick up. It also helps that SwiftUI generally produces good looking user interfaces with less effort than other things I’ve tried.</p>
<p>Forms play a crucial role in creating interactive user interfaces for collecting and managing user input. Developing reusable form components in SwiftUI not only streamlines the development process but also ensures a consistent user experience throughout the app. By creating modular, reusable form components, developers can reduce code duplication, enhance maintainability, and simplify the process of updating or extending the functionality of their applications. In this article, we&rsquo;ll explore the process of building a reusable login form component using SwiftUI.</p>
<p>At the end of the article you should have a login form that looks like this:</p>
<p><img src="screenshot.png" alt="screenshot-login"></p>
<h2 id="first-the-code">First, the code</h2>
<pre><code class="language-swift">import SwiftUI
struct LoginForm: View {
@State private var username: String = &quot;&quot;
@State private var password: String = &quot;&quot;
let onLoginButtonPress: ((String, String) -&gt; Void)?
let onResetPasswordPress: (() -&gt; Void)?
var body: some View {
VStack {
Text(&quot;Login to App&quot;)
.font(.title.bold())
.padding()
Spacer()
TextField(&quot;Username&quot;, text: $username)
.padding()
.autocapitalization(.none)
.disableAutocorrection(true)
.border(Color.gray, width: 1)
SecureField(&quot;Password&quot;, text: $password)
.padding()
.border(Color.gray, width: 1)
Button(action: {
onLoginButtonPress?(username, password)
}) {
Text(&quot;Login&quot;)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(5)
}
.padding()
Spacer()
Button {
onResetPasswordPress?()
} label: {
Text(&quot;Forgot your password? Click here to reset it.&quot;)
.font(.caption)
.padding()
}
}
.padding()
}
}
struct LoginForm_Previews: PreviewProvider {
static var previews: some View {
LoginForm(onLoginButtonPress: { userName, password in
print(&quot;Login button tapped&quot;)
print(&quot;Username is \(userName), password is \(password)&quot;)
},
onResetPasswordPress: {
print(&quot;Reset password requested.&quot;)
})
}
}
</code></pre>
<p>The code block above shows a login form where you can enter your username and password and has a button to login and a button to reset your password. Let’s take a look at how it works.</p>
<h2 id="storing-username-and-password-states">Storing Username and Password States</h2>
<p>We use private variables marked with <code>@State</code> to hold the username and password variables. In SwiftUI, <code>@State</code> is a property wrapper that manages the state of a value within a view. It provides local, mutable storage for simple values relevant to a specific view, allowing for mutability within an otherwise immutable view. <code>@State</code> also allows child views or controls to read and write the property&rsquo;s value using bindings, which is particularly useful for user input controls like TextField and Toggle. When a <code>@State</code> property value changes, SwiftUI automatically re-renders the affected parts of the view hierarchy, ensuring that the view always reflects the current state of the data. It is important to use <code>@State</code> only with value types, like structs, for proper change tracking, while other property wrappers like <code>@ObservedObject</code> or <code>@EnvironmentObject</code> are more suitable for reference types or complex data models.</p>
<pre><code class="language-swift">@State private var username: String = &quot;&quot;
@State private var password: String = &quot;&quot;
</code></pre>
<p>To bind these properties to the <code>TextField</code> and <code>SecureField</code>, respectively, you&rsquo;ll use the <code>$</code> symbol in front of the property names to create a binding:</p>
<pre><code class="language-swift">TextField(&quot;Username&quot;, text: $username)
SecureField(&quot;Password&quot;, text: $password)
</code></pre>
<p>By binding <code>@State</code> variables to <code>TextField</code> and <code>SecureField</code>, you ensure that your view always reflects the current state of the data, and changes made by the user in the input controls are automatically captured and stored in the corresponding <code>@State</code> properties.</p>
<h2 id="closures-for-form-actions">Closures for Form Actions</h2>
<p>In the LoginForm code, <code>onLoginButtonPress</code> and <code>onResetPasswordPress</code> are closure parameters that are passed to the LoginForm view. These closures define custom behavior that will be executed when the login button and reset password button are pressed, respectively.</p>
<ol>
<li><code>onLoginButtonPress</code>: This closure takes two input parameters, a String for the username and a String for the password. It gets called when the user taps the &ldquo;Login&rdquo; button. You can define custom login functionality within this closure, such as authentication and navigation to the next screen.</li>
<li><code>onResetPasswordPress</code>: This closure does not take any input parameters. It gets called when the user taps the &ldquo;Forgot your password? Click here to reset it.&rdquo; button. You can define custom reset password functionality within this closure, such as navigating to a password reset screen or showing a reset password prompt.</li>
</ol>
<p>By using these closure parameters, you can create a more flexible and reusable LoginForm component, as the specific functionality for handling login and password reset actions can be defined outside the LoginForm view, making it adaptable to various use cases within your app.</p>
<p>You may also have noticed that I’ve made the closure parameters optional by marking them with a <code>?</code> symbol. By marking them as optional, you indicate that these closures can have a value (a function) or be <code>nil</code>.</p>
<p>I prefer and recommend optional closures because it allows you to use the LoginForm component in cases where you might not need to provide both closures. For example, you might want to display a LoginForm that only requires a login action and not the reset password functionality, or vice versa. In such cases, you can simply pass <code>nil</code> for the closure you don&rsquo;t need, without having to modify the LoginForm component itself.</p>
<p>You might have scenarios where the behavior of the LoginForm component changes based on certain conditions. By making the closures optional, you can decide at runtime whether or not to provide a specific closure based on the current context or app state.</p>
<p>To safely call these optional closures, use the optional chaining syntax with the <code>?()</code> operator:</p>
<pre><code class="language-swift">onLoginButtonPress?(username, password)
onResetPasswordPress?()
</code></pre>
<p>This syntax ensures that the closure is only called if it has a non-nil value; otherwise, nothing happens, and the app continues to function without any issues.</p>
<h2 id="using-the-form-component-in-another-view">Using the Form Component in Another View</h2>
<p>Here’s how you’d use this form component in the main ContentView of your app as an example.</p>
<pre><code class="language-swift">import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
LoginForm(onLoginButtonPress: { username, password in
// Implement your custom login functionality here
print(&quot;Login button tapped&quot;)
print(&quot;Username: \(username), Password: \(password)&quot;)
// For example, you might perform authentication and navigate to the next screen
}, onResetPasswordPress: {
// Implement your custom reset password functionality here
print(&quot;Reset password requested.&quot;)
// For example, you might navigate to a password reset screen or show a reset password prompt
})
.navigationBarTitle(&quot;Your App&quot;, displayMode: .large)
}
}
}
</code></pre>
<p>For <code>onLoginButtonPress</code>, we print the username and password when the login button is tapped. In a real-world scenario, you&rsquo;d likely perform authentication here and navigate to the next screen upon successful login.</p>
<p>For <code>onResetPasswordPress</code>, we print a message indicating that a password reset has been requested. In practice, you might navigate to a password reset screen, show a password reset prompt, or perform any other relevant action.</p>
<h2 id="summary">Summary</h2>
<p>In this article, we explored the creation of a reusable LoginForm component using SwiftUI. We learned about using <code>@State</code> for local, mutable storage and two-way data binding with user interface controls, such as <code>TextField</code> and <code>SecureField</code>. We also discussed the flexibility and adaptability of the LoginForm component through optional closure parameters for handling login and password reset actions. SwiftUI&rsquo;s declarative approach and powerful features, such as property wrappers and bindings, make it easy and efficient to build modular and reusable components for user interfaces. As you continue to delve into SwiftUI, you&rsquo;ll find that it greatly simplifies app development and promotes consistent user experiences across your applications. Keep exploring and expanding your SwiftUI knowledge, and you&rsquo;ll be well-equipped to create fantastic apps that delight your users.</p>
</description>
</item>
<item>
<title>Blockchain</title>
<link>https://www.ashwinnarayan.com/project/blockchain/</link>
<pubDate>Thu, 04 Aug 2022 11:36:56 +0800</pubDate>
<guid>https://www.ashwinnarayan.com/project/blockchain/</guid>
<description><p>I recently got into blockchain development focused on the Solana blockchain. I&rsquo;ve been learning to build both Rust smart contracts and React based frontends. To see what I&rsquo;m working on, subscribe to me at
<a href="https://solanadevjournal.substack.com" target="_blank" rel="noopener">Solana Dev Journal</a>.</p>
<ol>
<li>
<a href="https://www.ashwinnarayan.com/dapps/solana-faucet/" target="_blank" rel="noopener">Solana Airdropper</a></li>
<li>
<a href="https://useless-nft-generator.space" target="_blank" rel="noopener">NFT Minter</a></li>
<li>
<a href="https://www.ashwinnarayan.com/dapps/kudos-program/" target="_blank" rel="noopener">Kudos Program</a></li>
</ol>
</description>
</item>
<item>
<title>Blockchains as I Understand It</title>
<link>https://www.ashwinnarayan.com/post/blockchains-as-i-understand-it/</link>
<pubDate>Tue, 02 Aug 2022 17:15:34 +0800</pubDate>
<guid>https://www.ashwinnarayan.com/post/blockchains-as-i-understand-it/</guid>
<description><h2 id="introduction">Introduction</h2>
<p>The first half of 2022 has not been kind to the world of crypto. Everyone expects a recession, cryptocurrency valuations are crashing; crypto firms file for bankruptcy every other week and many are predecting a &ldquo;crypto winter&rdquo;. As bad as things may seem, many would argue that the hype driven valuations crypto-currencies and associated projects were unsustainable, and had to come down eventually. Regardless, now that a lot of the hype and noise have faded, I feel that it is a good time to dive into the technical aspects of crypto currency technology with an academic mindset and learn about how it works.</p>
<h3 id="blockchains-and-smart-contracts">Blockchains and Smart Contracts</h3>
<p>The mathematics behind cryptocurrencies and blockchains have fascinated me since since 2012 - when I first heard about Bitcoin. Bitcoin pioneered the idea of a decentralized ledger of transactions of virtual tokens. However, modern blockchains have come a long way since then. In addition transactions of virtual tokens, blockchain today allow execution of arbitray logic on the blockchain - i.e., smart contracts. The mathematics of cryptography is what makes these features of blockchains possible.</p>
<h4 id="cyrptographic-hash-functions">Cyrptographic Hash Functions</h4>
<p>Cryptographic hash functions (CHFs) are mathematical functions take data as input and produce a &ldquo;fingerprint&rdquo; that is pre-image resistant - i.e. it is difficult to know what you put into the function given the output of the function.</p>
<p><img src="hash-functions.png" alt="hash_functions"></p>
<p>CHFs also have a few other properties. It&rsquo;s difficult to find two inputs that have the same hash value and small changes to the file results in large changes to the hash.</p>
<pre><code class="language-sh">~ % echo &quot;Hello&quot; | md5sum
09f7e02f1290be211da707a266f153b3 -
~ % echo &quot;Hellp&quot; | md5sum
a907206b6e6bf63124d4fa1e499eac8c -
</code></pre>
<h4 id="public-key-cryptography">Public Key Cryptography</h4>
<p>Public key cryptography lies at the foundation of how many blockchains work. These cryptographic systems uses two sets of numbers or &ldquo;keys&rdquo; for each person who wants to communicate. One key is kept a secret while the other is visible to everyone. If I want to send an encrypted message to Albert Einstein, I use a mathematical function that takes Einstein&rsquo;s public key and the message as input and produces an encrypted message. The encrypted message will look like random noise to anyone except Einstein (well his computer at least) who can use his secret key with a mathematical decryption function to decrypt the message.</p>
<p><img src="public-key-cryptography.png" alt="public_key_cryptography"></p>
<h4 id="digital-signatures">Digital Signatures</h4>
<p>Public / Private keypairs can also be used to produce what are called digital signatures that prove that the person who owns the private key has written (or at least has signed) a message. Digital signature schemes first generate a hash of a document using a cryptographic hash function and then encrypt the hash using your private key. Anyone else can then verify that it is indeed signed using your private key by decrypting the signature using your private key and comparing it to the hash of the document.</p>
<p><img src="digital-signatures.png" alt="digital_signatures"></p>
<h4 id="how-bitcoin-works-briefly">How Bitcoin Works, Briefly</h4>
<p>Each transaction on the Bitcoin network is written in a small
<a href="https://en.bitcoin.it/wiki/Script" target="_blank" rel="noopener">scripting language</a>. Bitcoin wallets - which are essentially a secret / public keypair - sign and send transactions to computers on the internet that are running code to verify blocks of tranasactions. These computers batch together transactions into blocks and try to find a number to add to a block of transactions (called a <em>nonce</em>) so that the cryptographic hash (SHA-256) of the block and the nonce has a specific number of leading zeroes. Finding the nonce is difficult to do because the brute-force method of searching through all possible combinations is the best way we know.</p>
<p>However, because of how cryptographic hashes work, it is easy to verify that the hash of the block with the nonce has the required number of leading zeroes. Therefore, the hash is <strong>proof</strong> that someone has done the <strong>work</strong> to verify the transaction. In the Bitcoin network, each block also contains the hash of the previous block so that we know the order in which the blocks were verified. The official ledger of transactions is the longest <strong>chain</strong> of <strong>blocks</strong> that have been verified by computers (miners) this way. In return for verifying transactions, the wallet that first verifies a block is rewarded with the fees of all the block&rsquo;s transactions and a small amount of newly minted Bitcoin.</p>
<p><img src="bitcoin-visualized.png" alt="bitcoin_blockchain"></p>
<h4 id="how-smart-contracts-work-briefly">How Smart Contracts Work, Briefly</h4>
<p>Smart contracts are an extension of the blockchain to transactions other than sending tokens between accounts. Bitcoin&rsquo;s scripting language is intentionally limited (i.e. it is not Turing Complete). Blockchains like Ethereum implement a Turing complete scripting language that allows the contract to store state and perform arbitrary calculations. This lets you make more complicated things on the blockchain. So a smart contract is essentially code which instead of executing on your computer is executed on other computers along with some cryptographic calculations to verify what the code did. This computation costs money (miners or validators need to pay for electricity) and gas fees are the reward that validators on the blockchain get for executing the smart contract logic.</p>
<h2 id="summary">Summary</h2>
<p>Blockchains essentially solve the problem of carrying out calculations and maintainings ledgers in a decentralized, trustless way. Rather than trusting a central authority (like a bank) to honestly keep track of your money, blockchains rely on mathematical rules which <strong>when correctly followed</strong> ensure that the probability of the ledger of transactions being honest is very high. However, the cost of a trustless system if a lack of recourse if you do not follow the rules. For instance, if your
<a href="https://www.coindesk.com/markets/2022/08/03/phantom-wallet-exploit-drains-millions-in-sol-tokens/" target="_blank" rel="noopener">private keys are leaked</a> you cannot retrieve your tokens from the thief because there is no &ldquo;central authority&rdquo; who can restore your wallet.</p>
<h2 id="references">References</h2>
<ol>
<li>
<a href="https://www.cbsnews.com/news/celsius-bankruptcy-filing-most-activity-still-paused/" target="_blank" rel="noopener">https://www.cbsnews.com/news/celsius-bankruptcy-filing-most-activity-still-paused/</a></li>
<li>
<a href="https://fortune.com/2022/07/08/voyager-crypto-bankruptcy-protection-next-steps-life-savings/" target="_blank" rel="noopener">https://fortune.com/2022/07/08/voyager-crypto-bankruptcy-protection-next-steps-life-savings/</a></li>
<li>
<a href="https://www.forbes.com/sites/jonathanponciano/2022/07/14/crypto-winter-watch-all-the-big-layoffs-record-withdrawals-and-bankruptcies-sparked-by-the-2-trillion-crash/?sh=4eb8957020f5" target="_blank" rel="noopener">https://www.forbes.com/sites/jonathanponciano/2022/07/14/crypto-winter-watch-all-the-big-layoffs-record-withdrawals-and-bankruptcies-sparked-by-the-2-trillion-crash/?sh=4eb8957020f5</a></li>
<li>
<a href="https://www.youtube.com/watch?v=bBC-nXj3Ng4&amp;t=906s" target="_blank" rel="noopener">https://www.youtube.com/watch?v=bBC-nXj3Ng4&amp;t=906s</a></li>
<li>
<a href="https://en.bitcoin.it/wiki/Script" target="_blank" rel="noopener">Bitcoin Scripting Language</a></li>
<li>
<a href="https://www.youtube.com/watch?v=GU4igNeYr-Q" target="_blank" rel="noopener">https://www.youtube.com/watch?v=GU4igNeYr-Q</a></li>
<li>
<a href="https://en.wikipedia.org/wiki/Cryptographic_hash_function" target="_blank" rel="noopener">https://en.wikipedia.org/wiki/Cryptographic_hash_function</a></li>
<li>
<a href="https://www.docusign.com/how-it-works/electronic-signature/digital-signature/digital-signature-faq" target="_blank" rel="noopener">https://www.docusign.com/how-it-works/electronic-signature/digital-signature/digital-signature-faq</a></li>
</ol>
</description>
</item>
<item>
<title>A Morning Walk Along The Rail Corridor</title>
<link>https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/</link>
<pubDate>Fri, 22 Apr 2022 10:14:53 +0800</pubDate>
<guid>https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/</guid>
<description><p>I&rsquo;ve been doing early morning photo walks lately to replace my &ldquo;wake up and scroll the phone&rdquo; habit. In addition to getting a bit of exercise in I also get to see nice scenery and take photos! I live near one of the entrances to Singapore&rsquo;s Rail Corridor. Today morning, I decided to walk along a section of it and take as many photos as I can.</p>
<p>I intended to wake up at 6.00 a.m., but it was 6.20 by the time I managed to shake off all my sleepiness. I was a little apprehensive about the weather as this week has been unusually rainy and cloudy. However, the sky was already light orange when I set out. Thin, wispy clouds stretched out across the eastern horizon. I took the shortest route to the main road from where I could see the sky. Majestic shafts of light were already shining through breaks in the cloud cover.</p>
<figure id="figure-shafts-of-light">
<a data-fancybox="" href="https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/sky1_hu6525cb3507b48870ae99821a7840af61_14333711_2000x2000_fit_q90_lanczos.jpeg" data-caption="Shafts of light">
<img data-src="https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/sky1_hu6525cb3507b48870ae99821a7840af61_14333711_2000x2000_fit_q90_lanczos.jpeg" class="lazyload" alt="" width="5033" height="4000">
</a>
<figcaption>
Shafts of light
</figcaption>
</figure>
<p>I like this time in the morning when the sky is beginning to get lighter, but the streetlamps haven&rsquo;t turned off yet. It feels like the lamps are clinging on to that last bit of night, hoping that it will last just a little longer.</p>
<figure id="figure-the-lamps-were-still-shining-and-the-wispy-clouds-were-casting-shadows-in-the-sky">
<a data-fancybox="" href="https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/lonely-lamp_hu849b0110fe347dadf8ecdfbc628fd5a9_4299705_2000x2000_fit_q90_lanczos.JPG" data-caption="The lamps were still shining, and the wispy clouds were casting shadows in the sky.">
<img data-src="https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/lonely-lamp_hu849b0110fe347dadf8ecdfbc628fd5a9_4299705_2000x2000_fit_q90_lanczos.JPG" class="lazyload" alt="" width="5328" height="4000">
</a>
<figcaption>
The lamps were still shining, and the wispy clouds were casting shadows in the sky.
</figcaption>
</figure>
<p>Dawn time skies have always embodied a sense of evanescence to me. The light and shadows changed every time I looked up. The shafts of light soon faded, and the sky brightened. I could see more of the golden morning light in the sky.</p>
<figure id="figure-the-lamps-were-still-shining-and-the-wispy-clouds-were-casting-shadows-in-the-sky">
<a data-fancybox="" href="https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/three-trees_huf8814ff9b9758148daf2f732faf2d859_186853_2000x2000_fit_q90_lanczos.jpeg" data-caption="The lamps were still shining, and the wispy clouds were casting shadows in the sky.">
<img data-src="https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/three-trees_huf8814ff9b9758148daf2f732faf2d859_186853_2000x2000_fit_q90_lanczos.jpeg" class="lazyload" alt="" width="1249" height="960">
</a>
<figcaption>
The lamps were still shining, and the wispy clouds were casting shadows in the sky.
</figcaption>
</figure>
<figure id="figure-the-clock-tower">
<a data-fancybox="" href="https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/featured_hu0658c00cd3310781b57c94ad1b0cb3fc_4929206_2000x2000_fit_q90_lanczos.JPG" data-caption="The clock tower.">
<img data-src="https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/featured_hu0658c00cd3310781b57c94ad1b0cb3fc_4929206_2000x2000_fit_q90_lanczos.JPG" class="lazyload" alt="" width="5328" height="4000">
</a>
<figcaption>
The clock tower.
</figcaption>
</figure>
<p>The air was cool but humid, and my glasses were covered in a permanent fog from mask-breath. Ferns, tall grasses, and overgrown vines lined the entrance to the rail corridor. Tall trees occasionally rose above the greenery. Skyscrapers and residential buildings towered above the trees on either side of the walkway. Some of the taller buildings were already beginning to catch a bit of sunlight. The waning gibbous moon was visible high in the sky, unobstructed by clouds. Despite its notoriety as a difficult subject to capture, my camera proved capable enough to capture some surface detail.</p>
<figure id="figure-the-moon-was-still-bright-in-the-sky">
<a data-fancybox="" href="https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/moon-1_hu67988bae97c0f4b74bcdcfe5210bca90_6505320_2000x2000_fit_q90_lanczos.JPG" data-caption="The moon was still bright in the sky.">
<img data-src="https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/moon-1_hu67988bae97c0f4b74bcdcfe5210bca90_6505320_2000x2000_fit_q90_lanczos.JPG" class="lazyload" alt="" width="5328" height="4000">
</a>
<figcaption>
The moon was still bright in the sky.
</figcaption>
</figure>
<figure id="figure-some-of-the-surface-detail-on-the-moon-is-visible-here">
<a data-fancybox="" href="https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/moon-2_hu7b1f9085b3dde423558c22d7954989c3_3855523_2000x2000_fit_q90_lanczos.JPG" data-caption="Some of the surface detail on the moon is visible here.">
<img data-src="https://www.ashwinnarayan.com/post/a-morning-walk-rail-corridor/moon-2_hu7b1f9085b3dde423558c22d7954989c3_3855523_2000x2000_fit_q90_lanczos.JPG" class="lazyload" alt="" width="5328" height="4000">
</a>
<figcaption>
Some of the surface detail on the moon is visible here.
</figcaption>
</figure>
<p>A short walk brought me to a futuristic looking bridge that connected either side of the rail corridor. I noticed that the lamps were finally off. The morning was officially here.</p>