Links
This commit is contained in:
203
static/archive/bogdanthegeek-github-io-p0gyop.txt
Normal file
203
static/archive/bogdanthegeek-github-io-p0gyop.txt
Normal file
@@ -0,0 +1,203 @@
|
||||
[1]
|
||||
BogdanTheGeek's Blog
|
||||
|
||||
• Menu ▾
|
||||
•
|
||||
□ [2]About
|
||||
□ [3]Insights
|
||||
□ [4]Projects
|
||||
□ [5]Thoughts
|
||||
|
||||
• [6]About
|
||||
• [7]Insights
|
||||
• [8]Projects
|
||||
• [9]Thoughts
|
||||
|
||||
[10]Hosting a WebSite on a Disposable Vape
|
||||
|
||||
2025-09-13Bogdan Ionescu6 min read (1266 words)[11]source [12]report issue
|
||||
#[13]programming #[14]arm #[15]tools #[16]electronics Hosting a WebSite on
|
||||
a Disposable Vape
|
||||
|
||||
Preface[17]#
|
||||
|
||||
This article is NOT served from a web server running on a disposable vape. If
|
||||
you want to see the real deal, click [18]here. The content is otherwise
|
||||
identical.
|
||||
|
||||
Background[19]#
|
||||
|
||||
For a couple of years now, I have been collecting disposable vapes from friends
|
||||
and family. Initially, I only salvaged the batteries for “future” projects
|
||||
(It’s not hoarding, I promise), but recently, disposable vapes have gotten more
|
||||
advanced. I wouldn’t want to be the lawyer who one day will have to argue how a
|
||||
device with USB C and a rechargeable battery can be classified as “disposable”.
|
||||
Thankfully, I don’t plan on pursuing law anytime soon.
|
||||
|
||||
Last year, I was tearing apart some of these fancier pacifiers for adults when
|
||||
I noticed something that caught my eye, instead of the expected black blob of
|
||||
goo hiding some ASIC (Application Specific Integrated Circuit) I see a little
|
||||
integrated circuit inscribed “PUYA”. I don’t blame you if this name doesn’t
|
||||
excite you as much it does me, most people have never heard of them. They are
|
||||
most well known for their flash chips, but I first came across them after
|
||||
reading Jay Carlson’s blog post about [20]the cheapest flash microcontroller
|
||||
you can buy. They are quite capable little ARM Cortex-M0+ micros.
|
||||
|
||||
Over the past year I have collected quite a few of these PY32 based vapes, all
|
||||
of them from different models of vape from the same manufacturer. It’s not my
|
||||
place to do free advertising for big tobacco, so I won’t mention the brand I
|
||||
got it from, but if anyone who worked on designing them reads this, thanks for
|
||||
labeling the debug pins!
|
||||
|
||||
What are we working with[21]#
|
||||
|
||||
The chip is marked PUYA C642F15, which wasn’t very helpful. I was pretty sure
|
||||
it was a PY32F002A, but after poking around with [22]pyOCD, I noticed that the
|
||||
flash was 24k and we have 3k of RAM. The extra flash meant that it was more
|
||||
likely a PY32F002B, which is actually a very different chip.^[23]1
|
||||
|
||||
So here are the specs of a microcontroller so bad, it’s basically disposable:
|
||||
|
||||
• 24MHz Coretex M0+
|
||||
• 24KiB of Flash Storage
|
||||
• 3KiB of Static RAM
|
||||
• a few peripherals, none of which we will use.
|
||||
|
||||
You may look at those specs and think that it’s not much to work with. I don’t
|
||||
blame you, a 10y old phone can barely load google, and this is about 100x
|
||||
slower. I on the other hand see a blazingly fast web server.
|
||||
|
||||
Getting online[24]#
|
||||
|
||||
The idea of hosting a web server on a vape didn’t come to me instantly. In
|
||||
fact, I have been playing around with them for a while, but after writing my
|
||||
post on [25]semihosting, the penny dropped.
|
||||
|
||||
If you don’t feel like reading that article, semihosting is basically syscalls
|
||||
for embedded ARM microcontrollers. You throw some values/pointers into some
|
||||
registers and call a breakpoint instruction. An attached debugger interprets
|
||||
the values in the registers and performs certain actions. Most people just use
|
||||
this to get some logs printed from the microcontroller, but they are actually
|
||||
bi-directional.
|
||||
|
||||
If you are older than me, you might remember a time before Wi-Fi and Ethernet,
|
||||
the dark ages, when you had to use dial-up modems to get online. You might also
|
||||
know that the ghosts of those modems still linger all around us. Almost all USB
|
||||
serial devices actually emulate those modems: a 56k modem is just 57600 baud
|
||||
serial device. Data between some of these modems was transmitted using a
|
||||
protocol called SLIP (Serial Line Internet Protocol).^[26]2
|
||||
|
||||
This may not come as a surprise, but Linux (and with some tweaking even macOS)
|
||||
supports SLIP. The slattach utility can make any /dev/tty* send and receive IP
|
||||
packets. All we have to do is put the data down the wire in the right format
|
||||
and provide a virtual tty. This is actually easier than you might imagine,
|
||||
pyOCD can forward all semihosting through a telnet port. Then, we use socat to
|
||||
link that port to a virtual tty:
|
||||
|
||||
pyocd gdb -S -O semihost_console_type=telnet -T $(PORT) $(PYOCDFLAGS) &
|
||||
socat PTY,link=$(TTY),raw,echo=0 TCP:localhost:$(PORT),nodelay &
|
||||
sudo slattach -L -p slip -s 115200 $(TTY) &
|
||||
sudo ip addr add 192.168.190.1 peer 192.168.190.2/24 dev sl0
|
||||
sudo ip link set mtu 1500 up dev sl0
|
||||
|
||||
Ok, so we have a “modem”, but that’s hardly a web server. To actually talk TCP/
|
||||
IP, we need an IP stack. There are many choices, but I went with [27]uIP
|
||||
because it’s pretty small, doesn’t require an RTOS, and it’s easy to port to
|
||||
other platforms. It also, helpfully, comes with a very minimal HTTP server
|
||||
example.
|
||||
|
||||
After porting the SLIP code to use semihosting, I had a working web server&
|
||||
mldr;half of the time. As with most highly optimised libraries, uIP was
|
||||
designed for 8 and 16-bit machines, which rarely have memory alignment
|
||||
requirements. On ARM however, if you dereference a u16 *, you better hope that
|
||||
address is even, or you’ll get an exception. The uip_chksum assumed u16
|
||||
alignment, but the script that creates the filesystem didn’t. I actually
|
||||
decided to modify a bit the structure of the filesystem to make it a bit more
|
||||
portable. This was my first time working with perl and I have to say, it’s
|
||||
quite well suited to this kind of task.
|
||||
|
||||
Blazingly fast[28]#
|
||||
|
||||
So how fast is a web server running on a disposable microcontroller. Well,
|
||||
initially, not very fast. Pings took ~1.5s with 50% packet loss and a simple
|
||||
page took over 20s to load. That’s so bad, it’s actually funny, and I kind of
|
||||
wanted to leave it there.
|
||||
|
||||
However, the problem was actually between the seat and the steering wheel the
|
||||
whole time. The first implementation read and wrote a single character at a
|
||||
time, which had a massive overhead associated with it. I previously benchmarked
|
||||
semihosting on this device, and I was getting ~20KiB/s, but uIP’s SLIP
|
||||
implementation was designed for very low memory devices, so it was serialising
|
||||
the data byte by byte. We have a whopping 3kiB of RAM to play with, so I added
|
||||
a ring buffer to cache reads from the host and feed them into the SLIP poll
|
||||
function. I also split writes in batches to allow for escaping.
|
||||
|
||||
Now this is what I call blazingly fast! Pings now take 20ms, no packet loss and
|
||||
a full page loads in about 160ms. This was using almost all of the RAM, but I
|
||||
could also dial down the sizes of the buffer to have more than enough headroom
|
||||
to run other tasks. The project repo has everything set to a nice balance
|
||||
latency and RAM usage:
|
||||
|
||||
Memory region Used Size Region Size %age Used
|
||||
FLASH: 5116 B 24 KB 20.82%
|
||||
RAM: 1380 B 3 KB 44.92%
|
||||
|
||||
For this blog however, I paid for none of the RAM, so I’ll use all of the RAM.
|
||||
|
||||
As you may have noticed, we have just under 20kiB (80%) of storage space. That
|
||||
may not be enough to ship all of React, but as you can see, it’s more than
|
||||
enough to host this entire blog post. And this is not just a static page
|
||||
server, you can run any server-side code you want, if you know C that is.
|
||||
|
||||
Just for fun, I added a json api endpoint to get the number of requests to the
|
||||
main page (since the last crash) and the unique ID of the microcontroller.
|
||||
|
||||
Resources[29]#
|
||||
|
||||
• [30]Code for this project
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
1. While getting things together for this post, I came across [31]this project
|
||||
that correctly identified these MCUs as PY32C642, which are pretty much
|
||||
identical to the 002B. [32]↩︎
|
||||
|
||||
2. Later modems used PPP (Point-to-Point Protocol) [33]↩︎
|
||||
|
||||
© 2025 Bogdan Ionescu
|
||||
|
||||
References:
|
||||
|
||||
[1] https://bogdanthegeek.github.io/blog/
|
||||
[2] https://bogdanthegeek.github.io/blog/about
|
||||
[3] https://bogdanthegeek.github.io/blog/insights
|
||||
[4] https://bogdanthegeek.github.io/blog/projects
|
||||
[5] https://bogdanthegeek.github.io/blog/thoughts
|
||||
[6] https://bogdanthegeek.github.io/blog/about
|
||||
[7] https://bogdanthegeek.github.io/blog/insights
|
||||
[8] https://bogdanthegeek.github.io/blog/projects
|
||||
[9] https://bogdanthegeek.github.io/blog/thoughts
|
||||
[10] https://bogdanthegeek.github.io/blog/projects/vapeserver/
|
||||
[11] https://github.com/BogdanTheGeek/blog/tree/main/content/projects/vapeserver.md
|
||||
[12] https://github.com/BogdanTheGeek/blog/issues/new?template=corrections.md&title=[Correction]:%20Hosting%20a%20WebSite%20on%20a%20Disposable%20Vape
|
||||
[13] https://bogdanthegeek.github.io/blog/tags/programming/
|
||||
[14] https://bogdanthegeek.github.io/blog/tags/arm/
|
||||
[15] https://bogdanthegeek.github.io/blog/tags/tools/
|
||||
[16] https://bogdanthegeek.github.io/blog/tags/electronics/
|
||||
[17] https://bogdanthegeek.github.io/blog/projects/vapeserver/#preface
|
||||
[18] http://ewaste.fka.wtf/
|
||||
[19] https://bogdanthegeek.github.io/blog/projects/vapeserver/#background
|
||||
[20] https://jaycarlson.net/2023/02/04/the-cheapest-flash-microcontroller-you-can-buy-is-actually-an-arm-cortex-m0/
|
||||
[21] https://bogdanthegeek.github.io/blog/projects/vapeserver/#what-are-we-working-with
|
||||
[22] http://pyocd.io/
|
||||
[23] https://bogdanthegeek.github.io/blog/projects/vapeserver/#fn:1
|
||||
[24] https://bogdanthegeek.github.io/blog/projects/vapeserver/#getting-online
|
||||
[25] https://bogdanthegeek.github.io/blog/insights/jlink-rtt-for-the-masses/
|
||||
[26] https://bogdanthegeek.github.io/blog/projects/vapeserver/#fn:2
|
||||
[27] https://github.com/adamdunkels/uip/tree/uip-0-9
|
||||
[28] https://bogdanthegeek.github.io/blog/projects/vapeserver/#blazingly-fast
|
||||
[29] https://bogdanthegeek.github.io/blog/projects/vapeserver/#resources
|
||||
[30] https://github.com/BogdanTheGeek/semihost-ip
|
||||
[31] https://github.com/grahamwhaley/py32c642_vape
|
||||
[32] https://bogdanthegeek.github.io/blog/projects/vapeserver/#fnref:1
|
||||
[33] https://bogdanthegeek.github.io/blog/projects/vapeserver/#fnref:2
|
||||
Reference in New Issue
Block a user