]> fortfriendship.online Git - gnargle.github.io.git/blob - projects/pipboy.html
05fe3c029eb8c2f7806a01f1eea61413eab785b3
[gnargle.github.io.git] / projects / pipboy.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="UTF-8" />
5 <title>Pipboy Prop Custom Apps</title>
6 <meta property="og:title" content="Pipboy Prop Custom Apps" />
7 <meta name="twitter:title" content="Pipboy Prop Custom Apps" />
8 <meta
9 name="description"
10 content="There's an official Fallout TV show prop. It's hackable."
11 />
12 <meta
13 property="og:description"
14 content="There's an official Fallout TV show prop. It's hackable."
15 />
16 <meta
17 name="twitter:description"
18 content="There's an official Fallout TV show prop. It's hackable."
19 />
20 <meta
21 property="article:published_time"
22 content="2025-03-19T00:00:00+00:00"
23 />
24 <meta
25 property="og:image"
26 content="https://athene.gay/img/projects/pipboy/pipboy2.jpg"
27 />
28 <meta
29 name="twitter:image"
30 content="https://athene.gay/img/projects/pipboy/pipboy2.jpg"
31 />
32 <link rel="stylesheet" href="../main.css" />
33 </head>
34 <body class="whole-site">
35 <div>
36 <iframe class="embed-title" src="../shared/title.html"> </iframe>
37 <div class="main-container">
38 <div class="main">
39 <div class="entry">
40 <a href="../index.html">Home</a>
41 <div class="title-block">
42 <a
43 class="blog-title"
44 target="_blank"
45 href="https://github.com/gnargle/pipboy-apps"
46 >
47 <h3>Pipboy Prop Custom Apps</h3>
48 </a>
49 <h3 class="datestamp">2025</h3>
50 </div>
51 <div class="content">
52 <p>There's an official Fallout TV show prop. It's hackable.</p>
53 <p>
54 OK, we're doing something a little different with this one. But
55 first the preamble.
56 </p>
57 <div class="title-block">
58 <h3 class="blog-title">The Preamble</h3>
59 <h3 class="datestamp">19/03/2025</h3>
60 </div>
61 <p>
62 So I haven't cosplayed properly in a while. I did it prettyu
63 regularly in 2023, but 2024 was a nadir for me menty h and
64 cosplay, with its ill-fitting, itchy fabrics that are not
65 designed with trans people in mind, was not gonna help that. I
66 didn't go to many cons, those I did I avoided being in cosplay,
67 yadda yadda.
68 </p>
69 <p>
70 Thing is, is I do actually really like cosplay, when I'm of the
71 frame of mind to do it. I like prop work. I like wearing the
72 clothes Cat has designed for me. It's fun when it's not autistic
73 agony.
74 </p>
75 <p>
76 You may have noticed I've got mad into Fallout of late. See the
77 previous entry on this blog. I've loved Fallout for a long time
78 but never really considered cosplay for it, not really sure why.
79 </p>
80 <p>
81 But this dive back into the series coincided well with me
82 wanting to get back into cosplay proper. And because I want to
83 do it properly, I've gone a bit all out.
84 </p>
85 <p>
86 I've ordered a reaaaalllly nice vault 33 suit, with backpack.
87 I'm gonna dye my hair instead of wearing a wig, which is the
88 worst thing sensory-wise for me in cosplay.
89 </p>
90 <p>And, I made a Pip-Boy! Look at it here, it's pretty great!</p>
91 <a href="../img/projects/pipboy/pipboy-homemade.jpg">
92 <img
93 class="blog-img-lrg"
94 src="../img/projects/pipboy/pipboy-homemade.jpg"
95 alt="A photo of the home-made pip-boy in question. It looks pretty accurate but it is very very large."
96 />
97 </a>
98 <p>It's also <i>absolutely fucking massive.</i></p>
99 <p>
100 Wearing it is deeply uncomfortable and my arms get tired after
101 mere minutes, let alone the hours of continuous wear a con would
102 require. It's impractical.
103 </p>
104 <p>
105 There is, however, a solution. Bethesda and 'The Wand Company'
106 produce a screen-accurate version of the tv series hero prop,
107 which normally wouldn't particularly interest me, as often
108 screen-accurate props are just display pieces and are
109 non-functional.
110 </p>
111 <p>
112 Props I use for cosplay need to have flare. I use LEDs to make
113 them nicer, or in the case of my own homebrew pipboy, I was
114 using a phone with an android app that mimics the Fallout 3
115 pip-boy interface, fully interactable. That's cool! And it's a
116 showcase!
117 </p>
118 <p>
119 But luckily this prop also actually works. It features a lot of
120 animations from the tv show, but more to the point, all the
121 dials on it function and are used to interact with it. It's
122 really excellent.
123 </p>
124 <p>
125 It's expensive, though, and that alone wouldn't have been enough
126 to sway me. That is, until I did a little bit of digging and
127 discovered that
128 <a
129 href="https://log.robco-industries.org/documentation/pipboy-3000/"
130 >the firmware is customisable, supporting custom applications
131 out of the box.</a
132 >
133 </p>
134 <p>
135 That's basically a red rag to a bull for me. I
136 <i>love</i> writing software for esoteric things. I mean. Look
137 at the projects on this website. Two of them use a midi device
138 and one of them is a plugin for a videogame. I've also written
139 plenty of software for and interfacing with embedded hardware.
140 This is simply made for me!
141 </p>
142 <p>
143 But if you click through the link at the top there, you'll
144 notice that there's basically nothing in the repository right
145 now. That's because, dear reader, we're gonna be exploring this
146 hardware TOGETHER. IN REAL TIME.
147 </p>
148 <p>
149 There's a sequence at the start of the social network where zuck
150 liveblogs him making facesmash. A lot of what he writes is
151 despicable, and the concept of facesmash is awful, but I dfo
152 love the idea of liveblogging a project. It's not something I
153 have really done before. So we're gonna do it with this one.
154 </p>
155 <p>
156 It's a good candidate. There's some documentation at the above
157 link, but not a lot, and there's lots left to explore in terms
158 of how the system works. The author of the above linked article
159 makes an assumption, for example - that the graphics context
160 should be one bit per pixel - but I don't think that's actually
161 the case. There are different tones in the monochrome screen,
162 and it doesn't look like they're made using dithering. So how
163 are they done? That's jsut one of many questions we will explore
164 together.
165 </p>
166 <p>
167 My ultimate aim here is to put something like the in-game stats
168 screen together. When I was setting up my homemade pip-boy, I
169 put some funny and personaly jokes into what stats and perks I
170 picked - being able to replicate them here would be really nice.
171 </p>
172 <p>
173 There's a long walk between here and there, though, so strap in.
174 </p>
175 <p>
176 However, let's get one thing straight here - I'm not a teenager
177 in a university dorm running on monster energy and rage. I'm a
178 31 year old woman with a full-time job and a bedtime.
179 </p>
180 <p>
181 So the 'liveblog' will not be me hacking away at this until 4AM,
182 oh no no. I will be working on this off and on over the next few
183 weeks most likely, and keeping this post updated as I go.
184 </p>
185 <p>
186 I am sure you will agree that this is a much healthier choice.
187 </p>
188 <div class="title-block">
189 <h3 class="blog-title">Beginnings</h3>
190 <h3 class="datestamp">19/03/2025</h3>
191 </div>
192 <p>
193 OK, so, the device itself. This is a boutique prop with
194 functionality that, while not an afterthought, is certainly not
195 economically worthy of any kind of custom silicon. This is a
196 collector's item, there's only a few thousand of them made, best
197 to use something off the shelf.
198 </p>
199 <p>
200 And, indeed, it does! An STM32 to be exact, an absolute
201 <i>classic</i> bit of IC hardware. The STM32 series are ARM
202 microcontrollers, architecturally similar to the hardware in
203 your common or garden smartphone. ARM is wonderful because it's
204 somehow managed to succeed in all 3 corners of the 'you can only
205 have two' triangle: it's [relatively] quick, it's cheap, and
206 it's Good. It also sips power relative to bigger, more
207 traditional chips, but that's true of any microcontroller,
208 really, so shouldn't really be counted as a strength here.
209 </p>
210 <p>
211 I was a smidge surprised to see an ARM chip in this - if this
212 were a homebrew project you'd expect probably an arduino, an
213 RP2040 or maybe a teensy - but this thing does have some
214 relatively complex graphics to drive.
215 </p>
216 <p>
217 I imagine the main reason this was chosen, however, was hardware
218 video decoding capability. Most (maybe all?) of the show-derived
219 animations are video files on-disk that are just decoded and
220 straight to the graphics context. You can argue this is cheating
221 if you want but to me it reeks of sensible design. Instead of
222 requiring the programmers to design and animate elegantly in a
223 very inelegant context (we'll get to that, believe me), you get
224 the raw files made for the show, re-encode them, and plonk them
225 on. Easy!
226 </p>
227 <p>
228 Additionally, the raw power the STM32 chip here has allows for a
229 less conventional (but friendlier-ish) development context. This
230 chip uses
231 <a href="https://www.espruino.com/">Espruino</a>.
232 </p>
233 <p>
234 Espruino is javascript for microcontrollers. Some of you may
235 have just hissed, and you'd be right to. Javascript is, pretty
236 infamously, horrible. It's heavy and unwieldy, it's untyped,
237 it's messy, it's functional-but-not-quite. If you want an
238 example of how not to design a programming language, you need
239 look no further than javascript. Yet because it runs in-browser,
240 it is the most common language in the world. Go figure.
241 </p>
242 <p>
243 Some of the words in that paragraph may have you convinced that
244 javascript is a bad fit for the lean, high-performance world of
245 microcontrollers, and really, you'd be right. But that hasn't
246 stopped the most insane people alive, javascript monodevelopers,
247 from crowbarring it into them anyway. And so: Espruino.
248 </p>
249 <p>
250 Cards on table, I've never used Espruino before today. I've
251 touched basically every other microcontroller going, and
252 everything else uses C++. I'm not a great C++ programmer, but I
253 can get by.
254 </p>
255 <p>
256 Comparative to my javascript, I might as well be the Bach of
257 C++. I do not like promises, I think throwing all your code to
258 'some indeterminate point in the future' is a horrendous choice,
259 but it's what we have to work with here, so we go with it.
260 </p>
261 <p>
262 The thing is though, in this case, this is actually a fairly
263 massive strength. Because Espruino is a JS interpreter, it will
264 run any valid JS you throw at it. This means you can actually
265 program it interactively from a serial connection, which is
266 pretty snazzy. Here's me throwing some debug code at it purely
267 from the terminal and seeing it display the results in real
268 time.
269 </p>
270 <a href="../img/projects/pipboy/pipboy2.jpg">
271 <img
272 class="blog-img-lrg"
273 src="../img/projects/pipboy/pipboy2.jpg"
274 alt="A photo of the prop pip-boy displaying the word 'TEST' on its screen."
275 />
276 </a>
277 <p>
278 It <i>also</i> means we can dump the firmware with one line from
279 the terminal and, instead of being binary and unreadable, it's
280 in regular-ass javascript. Holy shit!
281 </p>
282 <a href="../img/projects/pipboy/pipboyfirmwarescreenshot.png">
283 <img
284 class="blog-img"
285 src="../img/projects/pipboy/pipboyfirmwarescreenshot.png"
286 alt="A screenshot of some of the pip-boy firmware's built in function names."
287 />
288 </a>
289 <p>
290 As mentioned, the guy in the link above has already done this to
291 some extent, but I want to dig through a bit further and
292 understand a bit more what's going on. There's some very
293 interesting functions here that I wanna figure out.
294 </p>
295 <p>
296 For legal reasons, I can't share this firmware wholesale in the
297 repo, so you won't be able to see precisely what I'm talking
298 about. As we go, however, I'll screenshot various parts of the
299 code so you, reader, have context. Like the above!
300 </p>
301 <p>
302 Anyway, I think that's where I'm leaving it for tonight. It's
303 11pm, after all. More tomorrow.
304 </p>
305 <div class="title-block">
306 <h3 class="blog-title">Let's get some images displayed</h3>
307 <h3 class="datestamp">20/03/2025</h3>
308 </div>
309 <p>
310 OK, it's 6pm, there's 3 hours until the Apprentice is on, let's
311 get hacking. The first thing I need to do is, uh... take the
312 thing apart.
313 </p>
314 <a href="../img/projects/pipboy/pipboyopen.jpg">
315 <img
316 class="blog-img-lrg"
317 src="../img/projects/pipboy/pipboyopen.jpg"
318 alt="A photo of the pipboy's arse with a ribbon cable hanging out of it."
319 />
320 </a>
321 <p>
322 That's an micro-sd extender cable stringing out of it, there.
323 Nearly everything that makes up the pip-boy is stored on an sd
324 card which is, conveniently, not bolted into the board.
325 </p>
326 <p>
327 You can open up the thing and take it out, you can copy all of
328 its files over to a folder and, most usefully for us, you can
329 copy those same files over to another, bigger sd card (the one
330 installed is only 250MB) and it works, as long as the card is
331 fat32 formatted.
332 </p>
333 <p>
334 I've put a 32GB one in there, which is overkill, but I had it
335 lying around. It also means I can put the entirety of the
336 FO3/4/NV soundtracks on there, if I want. Which, maybe, I do in
337 future! Who knows.
338 </p>
339 <p>
340 More importantly, however, that SD card has a USER/ folder where
341 we can drop our own custom javascript files and it'll display
342 them in a nice 'APPS' menu in the INV menu.
343 </p>
344 <p>
345 We're gonna start with the the helloWorld and graphicsTest files
346 that are currently in the repo. Some file wiggling and inserting
347 and removal of SD cards and bang, there they are!
348 </p>
349 <a href="../img/projects/pipboy/pipboyapps.jpg">
350 <img
351 class="blog-img-lrg"
352 src="../img/projects/pipboy/pipboyapps.jpg"
353 alt="A photo of the pipboy's arse with a ribbon cable hanging out of it."
354 />
355 </a>
356 <p>
357 So we want tio draw something to screen that isn't just text,
358 next. So I need to dive into some docs. More updates in a bit...
359 </p>
360 <b>Code Updated. Check the github link to keep up.</b>
361 <p>
362 OK, first thing I want to do is draw a square. Which means we
363 need to understand how the graphics buffer is working. See,
364 right here, in the dump of the buffer of the main portion of the
365 screen, is some interesting evidence.
366 </p>
367 <a href="../img/projects/pipboy/firmwarebCbuffer.png">
368 <img
369 class="blog-img"
370 src="../img/projects/pipboy/firmwarebCbuffer.png"
371 alt="A screenshot of an the graphics context in the pip boy firmware."
372 />
373 </a>
374 <p>
375 The interesting thing here is 'UInt8.' This is an array of 8bit
376 integers. This could mean the pixels are rendered as 3-byte RGB
377 values, with the r and b just ignored, or it could mean each bit
378 in the byte is a pixel, and the different tones is achieved
379 using dithering. Right now, I'm not sure!
380 </p>
381 <p>So, to find out, we're gonna draw three squares.</p>
382 <a href="../img/projects/pipboy/squares.jpg">
383 <img
384 class="blog-img-lrg"
385 src="../img/projects/pipboy/squares.jpg"
386 alt="A photo of the pipboy screen showing 3 16x16 squares. One is slightly dimmer than the other two."
387 />
388 </a>
389 <p>
390 And there we have it! Three squares. Now if we look at the code
391 I've written, and note that the middle square is the dimmest of
392 the three, we can deduce...
393 </p>
394 <a href="../img/projects/pipboy/squarecode.png">
395 <img
396 class="blog-img"
397 src="../img/projects/pipboy/squarecode.png"
398 alt="A screenshot of the code to make the three squares. The three are commented 'full byte pp', 'dithered square', and 'fullbright square'"
399 />
400 </a>
401 <p>
402 That I was completely wrong and the screen is compeltely
403 monochrome, and any dimming is done by dithering. I'm so glad
404 I'm liveblogging this so everyone can see how stupid I am.
405 </p>
406 <p>
407 That's ok though! We're here to learn, and this actually makes
408 things relatively nice and easy. I'm sure there are monochrome
409 image -> uint arrays somewhere out there one the web already,
410 thisn is a very common format on embedded platforms, so I just
411 need to find one and run the icons for various perks etc through
412 them, and we can get one displaying.
413 </p>
414 <p>In fact, maybe that's what we do next. BRB...</p>
415 <b>Code Updated. Check the github link to keep up.</b>
416 <p>
417 Excellent, here's one, first hit on google.
418 <a href="https://javl.github.io/image2cpp/">image2cpp</a>
419 Let's run the Cherchez La Femme image through it and upload it
420 to the machine aaaand...
421 </p>
422 <a href="../img/projects/pipboy/errorlowmem.png">
423 <img
424 class="blog-img-lrg"
425 src="../img/projects/pipboy/errorlowmem.png"
426 alt="A screenshot of the espruino terminal reading 'New interpreter error: LOW_MEMORY,MEMORY'"
427 />
428 </a>
429 <p>
430 So, that's not good. In fairness, I am loading a 167x167 bitmap
431 into memory here, I suppose it makes sense that that wouldn't
432 exactly work. But it is going to make this more difficult.
433 </p>
434 <p>
435 Next question then. What is a reasonable maximum array size we
436 can use here? Time to experiment. We'll start with half the
437 resolution, 83x83.
438 </p>
439 <a href="../img/projects/pipboy/chercheztake1.jpg">
440 <img
441 class="blog-img-lrg"
442 src="../img/projects/pipboy/chercheztake1.jpg"
443 alt="A photo of the pipboy screen showing garbage in a square."
444 />
445 </a>
446 <p>
447 OK, it's displaying, but that's clearly not right. Here's what
448 it's supposed to look like:
449 </p>
450 <a href="../img/projects/pipboy/CherchezLaFemme.png">
451 <img
452 class="blog-img"
453 src="../img/projects/pipboy/CherchezLaFemme.png"
454 alt="The Cherchez La Femme perk icon from New Vegas"
455 />
456 </a>
457 <p>
458 That's ok though, there's options on the converter for just this
459 predicament. This was the default (Horizontal - 1bpp), and
460 Vertical - 1bpp landed similar results, so let's move on from
461 that converter and use the one hosted on
462 <a href="https://www.espruino.com/Image+Converter"
463 >Espruino's website</a
464 >
465 instead. Man I'm really proving myself soooo smart today.
466 </p>
467 <p>
468 Using the right tool for the job gives us this! And it's even
469 full resolution! Huzzah!
470 </p>
471 <a href="../img/projects/pipboy/cherchezsuccess.jpg">
472 <img
473 class="blog-img-lrg"
474 src="../img/projects/pipboy/cherchezsuccess.jpg"
475 alt="A photo of the pipboy screen showing the Cherchez La Femme icon."
476 />
477 </a>
478 <p>
479 OK, that's real, genuine progress. We can encode images and
480 display them, which we need for the perks screen. They are
481 pretty big though, so I think next order of business is going to
482 be keeping those strings in text files and loading them in when
483 we need to. Back to the docs... Although I might leave it there
484 tonight, my back hurts. No wonder Zuck had to be 19 to do this
485 live.
486 </p>
487 <div class="title-block">
488 <h3 class="blog-title">Loading from files</h3>
489 <h3 class="datestamp">21/03/2025</h3>
490 </div>
491 <p>Evening! Let's get right back to work.</p>
492 <p>
493 Yesterday, we figured out how to correctly convert and display
494 an image on the screen. Today,we're going to figure out storing
495 those images, loading them at runtime, and switching to another
496 image later.
497 </p>
498 <p>
499 So, first up: storing and loading the image. This is gonna need
500 me to look up how the espruino fs library works. BRB...
501 </p>
502 <b>Code Updated. Check the github link to keep up.</b>
503 <a href="../img/projects/pipboy/imgstringdump.png">
504 <img
505 class="blog-img-lrg"
506 src="../img/projects/pipboy/imgstringdump.png"
507 alt="A screenshot of the pipboys serial connection in vscode showing the file read from disk."
508 />
509 </a>
510 <p>
511 Well that was tremendously easy. First try baby, finally I'm not
512 completely stupid about something! We're gaming! I would take a
513 photo of the screen but I didn't change the image's position so
514 it looks exactly the same. but rest assured it is there!
515 </p>
516 <p>OK, next up, we swap images on the fly.</p>
517 <b>Code Updated. Check the github link to keep up.</b>
518 <video width="672" height="378" class="video-embed" controls>
519 <source
520 src="../img/projects/pipboy/pipboyperkswitch.mp4"
521 type="video/mp4"
522 />
523 Your browser does not support the video tag.
524 </video>
525 <p>
526 Done! Again! Wow we're going win after win today. Apart from the
527 weird bit of artifacting in the top left of the image there,
528 but, er... I'm sure that's fine. Let's ignore it for now. We'll
529 see if it continues with other images.
530 </p>
531 <p>
532 OK, so this is actually a fair cut through the work we need to
533 do here. So let's structure the screen a bit, and add the name
534 and descriptions.
535 </p>
536 <b>Code Updated. Check the github link to keep up.</b>
537 <p>
538 Hoooo boy I spent a while here huh! So much for 'live' blogging.
539 </p>
540 <a href="../img/projects/pipboy/perklist1.jpg">
541 <img
542 class="blog-img-lrg"
543 src="../img/projects/pipboy/perklist1.jpg"
544 alt="A photo of the pipboy screen showing a decent approximation of the perk menu from FO3/NV. Action Girl is selected and shows its icon and description."
545 />
546 </a>
547 <p>
548 While I've been gone I basically drew the rest of the fucking
549 owl. Look! It's the screen from the game! Pretty much
550 completely!
551 </p>
552 <p>
553 There's some artistic license; in-game the perk description
554 displays in the same column as the image, but the available area
555 there is too small to display it readably on screen, so I've
556 bannered it at the bottom instead.
557 </p>
558 <p>
559 But yeah, we've got the basics of the screen here! The list of
560 perks, the box around the selected one, the image, the
561 description. They're all loaded dynamically from the list of
562 files on the SD card, and I've just gone in and tested the
563 reselection with a timeout, and hot damn, it works.
564 </p>
565 <a href="../img/projects/pipboy/perklist2.jpg">
566 <img
567 class="blog-img-lrg"
568 src="../img/projects/pipboy/perklist2.jpg"
569 alt="Another photo of the pipboy showing the perk menu. Now Cherchez La femme, second in the list, is selected."
570 />
571 </a>
572 <p>
573 Additionally, if you're code digging, you'll see I've done a
574 bunch of reorganisation. While I was hacking before, I've gone
575 in and refactored and made all of this actually functionally
576 useful for building up the application proper.
577 </p>
578 <p>
579 Next thing, then, is input. Which hopefully, shouldn't be too
580 bad? I'll tackle that at some point over the weekend. Then it's
581 just filling the rest of the perk data (and fixing whatever is
582 wrong with the action girl image) and presto, that's a screen!
583 </p>
584 <b>Code Updated. Check the github link to keep up.</b>
585 <p>
586 OK I lied did a tiny bit more tonight. It's some housekeeping
587 code - I wanted to make sure the images displayed centrally if
588 they were cropped to just their actual data, any rows of empty
589 pixels around them removed.
590 </p>
591 <p>
592 This turned out to be a smart decision - It saves space, it
593 looks nice, and it meant I redid the action girl icon with its
594 bit of corrupted data, a bug I would have otherwise inevtiably
595 ignored until the end. No photos right now because not much has
596 actually changed but it's good and sets us up for just
597 implementing the manual selection now.
598 </p>
599 <div class="title-block">
600 <h3 class="blog-title">Chasing accuracy</h3>
601 <h3 class="datestamp">22/03/2025</h3>
602 </div>
603 <p>
604 Good morning! I'm up bright and early to continue my vital work.
605 </p>
606 <p>
607 Actually, I've already started. I looked up what the perk menu
608 looks like in Fallout 4 to check if there a) is one other than
609 the chart (there is) and b) if what I'm making is accurate to
610 that.
611 </p>
612 <p>
613 And it mostly is, but the selection box around the perk in the
614 list is actually all green and the text is black, see the below
615 image.
616 </p>
617 <a href="../img/projects/pipboy/pipboyfo4.png">
618 <img
619 class="blog-img-lrg"
620 src="../img/projects/pipboy/pipboyfo4.png"
621 alt="A screenshot of Fallout 4 showing the pipboy open on the perks screen."
622 />
623 </a>
624 <p>
625 So I kinda want to recreate that. Doing so would be useful as
626 it'll also bring my selection menu in line with some of the
627 official submenus on the device as well, making the app look
628 more official :)
629 </p>
630 <p>
631 This is what I've got so far - I couldn't get the text to draw
632 in black so I settled on a halftone selection box instead. I'm
633 still not completely happy with it though and want to get as
634 close to accurate as I can, so I'm going to dive into the
635 firmware and see if I can divine how it does the black on white.
636 </p>
637 <a href="../img/projects/pipboy/halftoneselection.jpg">
638 <img
639 class="blog-img-lrg"
640 src="../img/projects/pipboy/halftoneselection.jpg"
641 alt="A photo of the pipboy on the perks screen, showing the selected perk title with a grey box behind it."
642 />
643 </a>
644 <b>Code Updated. Check the github link to keep up.</b>
645 <p>
646 Ooookay, a lot has happened since I said I'd check the firmware.
647 Here's the current state of the screen:
648 </p>
649 <a href="../img/projects/pipboy/accurateLayout.jpg">
650 <img
651 class="blog-img-lrg"
652 src="../img/projects/pipboy/accurateLayout.jpg"
653 alt="A photo of the pipboy on the perks screen. The perk title is now boxed with green pixels, with the text in black. The font of all text is also accurate to the game now."
654 />
655 </a>
656 <p>
657 So, like I said, I dove into the firmware code. I found quite a
658 lot of interesting stuff in there while trying to figure out how
659 they did the black on white textbox. Let's run through.
660 </p>
661 <p>
662 Top of the order - there are three foreground colours the pipboy
663 can draw in, 0-3. These are actually different brightnesses of
664 the pixels. So drawing a fullbright pixel is colour 3, an off
665 pixel is colour 0, but there's also colours 1 and 2 which are
666 slightly dimmer on colours!
667 </p>
668 <p>
669 This is how the fading 'Attachment' and 'Aid' labels at the top
670 are drawn, although it's not very clear in the photos I've
671 taken.
672 </p>
673 <p>
674 I actually discovered this by accident - I saw a setColor(0) in
675 the firmware and deduced that was black, so then I added that in
676 to my drawing code - but in so doing I also set the colour of
677 everything not black to setColor(1), which made everything
678 dimmer.
679 </p>
680 <p>
681 This was a bit of a eureka moment - I'd figured out that there
682 were roughly 4 colours displayed on screen but earlier assumed
683 this was all dithering after my experiments a few days ago.
684 Turns out I was right all along! Ha-HA!
685 </p>
686 <p>
687 So, using this new knowledge, I've added correct coloring to
688 everything. I've also chosen to dim the perk image a shade and I
689 think it makes it look really good. The full brightness was
690 overpowering some of the details of the icons.
691 </p>
692 <p>
693 While digging, I also found an interesting function call:
694 setFontMonofonto18(). This was a call on the graphgics context
695 and was pretty self-explanatory.
696 </p>
697 <p>
698 The thing is, I'd noticed my fonts were a bit off. They weren't
699 as tall as they should have been. Turns out, that's because
700 there's a custom font in use, but only when you specifically set
701 it. So because I was just using setFontVector() instead of these
702 Monofonto calls, the font was getting set back to the default
703 Espruino vector font.
704 </p>
705 <p>
706 Ctrl-F-ing 'Monofonto' in the firmware dump showed up a few
707 similar calls, listed here for convenience:
708 </p>
709 <ul>
710 <li>setFontMonofonto16</li>
711 <li>setFontMonofonto18</li>
712 <li>setFontMonofonto23</li>
713 <li>setFontMonofonto28</li>
714 <li>setFontMonofonto96</li>
715 <li>setFontMonofonto120</li>
716 </ul>
717 <p>
718 I assumed Monofonto was the font name, and tried to plug it in
719 to a few of the Espruino font functions, but got errors each
720 time, which was troubling. Giving it a quick duckduckgo
721 presented an excellent result:
722 <a href="https://www.dafont.com/monofonto.font"
723 >DaFont Monofonto.</a
724 >
725 Turns out the font used on the pip-boy (and presumably in the
726 actual game!) is freely available to download. Perfect!
727 </p>
728 <p>
729 With that in hand, I looked at the Espruino setCustomFont call,
730 and with a smidge more docs digging I found
731 <a href="https://www.espruino.com/Font+Converter">this page</a>
732 that converts a font and size into a graphics context function
733 call - just like the ones already in the firmware!
734 </p>
735 <p>
736 This was perfect. I plugged in the font and set size to 14,
737 dropped the code in my file, and now my description is in the
738 correct font. I used the pre-existing setFontMonofonto18 for the
739 Title - 16 was proving a little too small, and other menus in
740 the device are size 18.
741 </p>
742 <p>
743 I'm honestly over the moon about this. I had kind of already
744 settled for things not looking quite right, but with a bit of
745 digging, I solved basically all the imparities with the games.
746 </p>
747 <p>
748 What that isn't, though, is input. Which was the title of this
749 update (I've changed it now). So I'll tackle that next!
750 </p>
751 <div class="title-block">
752 <h3 class="blog-title">Actually doing input this time</h3>
753 <h3 class="datestamp">22/03/2025</h3>
754 </div>
755 <p>
756 OK we're back again baby. And this time I sweart I am going to
757 do input. To show willing I've even already started diving into
758 the firmware to work out how it's done!
759 </p>
760 <a href="../img/projects/pipboy/firmwareInputListener.png">
761 <img class="blog-img-lrg"
762 src="../img/projects/pipboy/firmwareInputListener.png" alt="A
763 screenshot of the dumped firmware. It notably shows a function
764 'd' and a call Pip.on('knob1', d)")." />
765 </a>
766 <p>
767 So that firmware screenshot tells us all we need to know,
768 really. The Pip object has some events (in this case, 'knob1',
769 which is a) funny and b) the left hand wheel control) one which
770 you can register functions to call.
771 </p>
772 <p>
773 This screenshot is from the portion of the code that handles
774 switching between the different health animations, but this
775 applies anywhere really. So what we need to do is:
776 </p>
777 <ul>
778 <li>Create a listener and register it</li>
779 <li>
780 Make sure we play the knob click audio like the rest of the
781 device does
782 </li>
783 <li>Move our selection up and down the list with each click</li>
784 </ul>
785 <p>Pretty simple! OK, lets go do that.</p>
786 <b>Code Updated. Check the github link to keep up.</b>
787 <p>And look at that! We're done.</p>
788 <video width="672" height="378" class="video-embed" controls>
789 <source
790 src="../img/projects/pipboy/inputWorking.mp4"
791 type="video/mp4"
792 />
793 Your browser does not support the video tag.
794 </video>
795 <p>
796 Nothing really special to talk about here, just some basic
797 increment/decrement handling and looping back to the start of
798 the list when necessary.
799 </p>
800 <p>
801 There is a specific wrinkle of having to deregister the input
802 event. Early on in my testing I hadn't done that and it kept the
803 .js loaded even after removing the SD card, which meant it
804 looked like any edits I made weren't actually working. In order
805 to prevent this I added gracefulClose() which deregisters the
806 handler and shows the main menu again.
807 </p>
808 <p>
809 Last thing here is really to handle what happens when we have
810 more perks than will fit in our available space. Then this
811 screen is basically done!
812 </p>
813 <b>Code Updated. Check the github link to keep up.</b>
814 <p>
815 And now that's done too! Couple of bugs with loading the right
816 files to list (primarily loading too many) but smart use of the
817 modulo operator and we're done! I filled in every perk I think
818 is funny and applicable to me, did some manual edits to some of
819 the icons (new vegas icons seem to generally be less optimised
820 for a real monochrome display, a rare instance where Bethesda's
821 attention to detail is better than Obsidian's) and filled in all
822 their data and, well, that's it!
823 </p>
824 <video width="672" height="378" class="video-embed" controls>
825 <source
826 src="../img/projects/pipboy/fullscreendemo.mp4"
827 type="video/mp4"
828 />
829 Your browser does not support the video tag.
830 </video>
831 <p>
832 I'm pretty happy with it! This was a really enjoyable project
833 and let me flex a lot of the muscles I don't tend to use a lot
834 in my pure software day-to-day.
835 </p>
836 <p>
837 I might come back to this later and make a second screen with
838 stats on it, but that's basically the same layout etc as the
839 perks screen just with a number, so I probably won't write it
840 up.
841 </p>
842 <p>
843 So yeah, for now, I'll leave it here. Thank you for reading and
844 following my thought processes, if you did!
845 </p>
846 <b>Code Updated. Check the github link to keep up.</b>
847 <p>
848 OK I LIED one last update. I wanted to handle the selector on
849 the right moving away from INV gracefully. Until now, switching
850 this while in the app would do nothing, and to get around this I
851 had the click in of the left wheel as the 'return me to the main
852 menu' key. That's not very accurate to how it should work,
853 though.
854 </p>
855 <p>
856 So I dove into the firmware again and after a few false starts I
857 found checkMode(). This is called on a timer in all the other
858 apps every 50 milliseconds. I experimented a little with this
859 timeout in my app - 50ms made the perk list feel laggy (because
860 I'm loading data from disk so ops take a bit more time than
861 everything else in the system) so I tweaked it up to 100ms,
862 which was a nice compromise.
863 </p>
864 <p>
865 Twiddling the mode dial triggers a menu change, but I also made
866 sure to gracefully shutdown when a change was detected - this
867 includes running showMainMenu(), which if we don't do the
868 control handlers don't get registered properly. Important.
869 </p>
870 <p>
871 I also dropped in a handler for the torch button - it does
872 nothing other than shutdown and activate the torch normally.
873 While testing this I actually found a bug with the current
874 firmware - if you stay on the torch page and the time changes,
875 the footer will display over the torch screen. Neat!
876 </p>
877 <p>Anyway that is really it this time. Thanks for reading <3</p>
878 </div>
879 </div>
880 </div>
881 </div>
882 <iframe class="embed-links" src="../shared/links.html"> </iframe>
883 <iframe class="embed-footer" src="../shared/footer.html"> </iframe>
884 </div>
885 </body>
886 </html>