<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Joshua Miller]]></title><description><![CDATA[Python, other programming, electric stuff.]]></description><link>https://jtm.gg/</link><image><url>https://jtm.gg/favicon.png</url><title>Joshua Miller</title><link>https://jtm.gg/</link></image><generator>Ghost 3.8</generator><lastBuildDate>Tue, 12 Nov 2024 13:14:55 GMT</lastBuildDate><atom:link href="https://jtm.gg/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Gameboy ROM Hack: Trip World Casual Mode]]></title><description><![CDATA[Trip World is a Gameboy game from 1992. While some games now might really hold your hand, old games were harder. I hacked this game to make it easier.]]></description><link>https://jtm.gg/trip-world-gameboy-hack/</link><guid isPermaLink="false">5d6fbd0034a89005798661d7</guid><category><![CDATA[gameboy]]></category><category><![CDATA[asm]]></category><category><![CDATA[rom]]></category><category><![CDATA[hacking]]></category><dc:creator><![CDATA[Joshua]]></dc:creator><pubDate>Thu, 03 Oct 2019 18:34:25 GMT</pubDate><media:content url="https://jtm.gg/content/images/2019/09/result3-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://jtm.gg/content/images/2019/09/result3-1.png" alt="Gameboy ROM Hack: Trip World Casual Mode"><p>Trip World is a Gameboy game from 1992.<br>While some games now might really hold your hand and introduce you how to play the game, old games were different. Sometimes to know the story, controls, names of the characters etc, you had to read the <a href="https://archive.org/details/TripWorld_GameBoyManual">instruction manual</a> that came in the box.<br><br>It took me around 20 minutes of playing Trip World until I realized that you can turn into a fish!<br>Games then were arguably harder. Possibly to ensure that you would get your money's worth?<br>The fact I had to play the game in one sitting made it hard. The game has no battery so you can't save - although you can select the level you want to play. You have 3 lives and 4 bars of health and by the time I got to the 3rd boss I was dying a lot.</p><!--kg-card-begin: markdown--><p><img src="https://jtm.gg/content/images/2019/10/original.png" alt="Gameboy ROM Hack: Trip World Casual Mode"><br>
What the game looks like normally</p>
<!--kg-card-end: markdown--><p>I thought it would be a fun project to make a hack that makes the game a little easier.<br>I wanted to remove the 'lives' aspect of the game, so that you will never see a 'game over' screen. I really enjoyed playing Wario Land 3, a game with no health or lives, where if you get hurt you simply have to try whatever you were doing again. (Technically I think there were two expections to this rule in the game - anyway it was great fun)</p><p><strong>If anyone would appreciate me making a video of (re)creating this hack, let me know in the comments below.</strong></p><h3 id="how-i-did-it">How I did it</h3><ol><li>To start, I downloaded bgb (a Gameboy emulator and debugger) and loaded up the Trip World rom. Right click on the main screen and go to 'Other'-&gt;'Debugger' to get the debugger up.</li><li>When in-game, I found the offset in RAM for where the lives are stored, via the 'cheat search' (bgb debugger, 'Window'-&gt;'cheat searcher')<br>This is basic cheat finding stuff, if you have 3 lives, search for 3, get killed and search for 2... repeat until you have 1 address.</li><li>I set an 'access breakpoint' (bgb debugger, 'Debug'-&gt;'access breakpoints') that breaks (pauses) the game and shows you the current ASM instruction when a value is written to the lives offset. Kill the player, the lives will decrease by 1, and the game will pause.</li><li>I then NOPed out the function that decrements your lives when you die.<br>NOP is an ASM instruction that does nothing (NO OPeration), and we use it to replace an existing instruction when we want to stop it from happening.<br>To change the ASM instruction in bgb, right click the line of the instruction, click on 'Modify code/data', and type in your new instruction - 'nop'.</li></ol><figure class="kg-card kg-image-card"><img src="https://jtm.gg/content/images/2019/09/bgb-debugger-change-inst-1.png" class="kg-image" alt="Gameboy ROM Hack: Trip World Casual Mode"></figure><p>That's quite simple and only took a few minutes. But I was then left with a useless lives indicator on screen. There's no need to show that I have 3 lives left if the game doesn't use lives anymore.<br>So I worked on removing the lives from the UI. When working with graphics, BGB's Tile Viewer comes in very handy.</p><h3 id="how-i-removed-the-number-of-lives-from-the-ui">How I removed the number of lives from the UI</h3><ol><li>Set BGB to break when the lives are read in game - and so it breaks every frame to update the UI with the current amount of lives.</li><li>From the ASM I could see that the number of lives were read, then 50 was added, and that value was used to fetch a tile that gets drawn on the UI. 2 lives + 50 = 52.</li><li>When looking at the tiles, tile 50 was a graphic of '0', 51 was '1', etc. Tile 0 is blank.</li><li>I changed the ASM so that instead of using 'lives+50' to pick the tile, always use Tile 0.</li></ol><!--kg-card-begin: markdown--><p><img src="https://jtm.gg/content/images/2019/10/result1-1.png" alt="Gameboy ROM Hack: Trip World Casual Mode"><br>
After removing the lives counter</p>
<!--kg-card-end: markdown--><p>This removes the number of living being displayed, but icons to the left ('🐇x') of it are still present and it looks strange. I want to remove them too. <br>Originally I did this in a cheap and dirty way, I simply edited the tile graphics in ROM so that these tiles were blank. Technically the game was still drawing the icons, but it was just drawing 'nothing'. I didn't like that method and wanted to do it neater, so I then tried again and found where the UI is defined in ROM and stopped the icons from getting displayed in the first place. </p><h3 id="how-i-removed-the-player-icon-from-the-ui">How I removed the player icon from the UI</h3><ol><li>Open the VRAM Viewer and see the graphics that the game has currently loaded.</li><li>On the 'BG Map' tab, I change the current map to '9C00', the Gameboy can have 2 background maps and the tiles I'm looking for are on the 2nd map.</li><li>Get the 'Map address' of the tile we want. (9C0E)</li><li>Go to the 'Tiles' tab on the VRAM viwer, and find that same tile and get the tile number - it's 86 for this one.</li><li>Go to <code>9C0E</code> in the hex view of bgb, you should see 86, the tile number for the icon. Right click it, set a breakpoint when 86 is written to this address. It will happen when the game play starts, when starting the game or after dying.</li><li>The game should break, look what's happening - the instruction above that just executed is <code>ld a, (de)</code> and you should be able to see in your registers that a is now 86. We see that a is getting it's value from the byte at <code>de</code>. Change the data at <code>de</code> to 00 and you did it!<br>Repeat the same thing for the 2nd tile (the one that contains the 'x')</li></ol><!--kg-card-begin: markdown--><p><img src="https://jtm.gg/content/images/2019/10/result2-1.png" alt="Gameboy ROM Hack: Trip World Casual Mode"><br>
After removing the player lives icons</p>
<!--kg-card-end: markdown--><p>Now, there are no trace of lives on the UI, but I don't like how the score is two tiles longer than the health bar. Plus, this is a hack to make the game easier, so I'll increase the health bar to make it 6. Now it will line up with the score.</p><h3 id="how-i-increased-the-health-from-4-to-6">How I increased the health from 4 to 6<br></h3><p>I used the same methods as above and found 3 instructions/places that we have to change from 4 to 6.</p><ul><li>Initializing your health value to 4 at the start of game play</li><li>Drawing the maximum of 4 health pieces on the UI</li><li>Recovering to full health when picking up a big heart recovery item</li></ul><p>Replace these instructions to use 6 instead of 4 and you are done! See how far you get by yourself.<br><br><strong>Note:</strong> I didn't realize there were 2 different health recovery items (the heart flowers) There's a big one that recovers all of your HP, I fixed that easily, but I forgot about the smaller heart that increases your HP by 1.<br>For the smaller one, the game checks to see if you are at max HP before incrementing. Well, it doesn't explicitly check to see if your HP is 4, it actually checks if bit 2 (the 3rd bit from the right) is set.<br>100 in binary is 4, so this works great. But we can't check a <em>single </em>bit to see if our HP is at the new max of 6, because 6 in binary is 110. We would need to check 2 bits, and I don't think that's possible in one instruction. We don't want to take up more instructions/bytes that the original instruction because otherwise we would overwrite and destroy the next instructions in the game.<br>Anyway, here's what's going on and how to fix it.</p><h2 id="fixing-the-small-health-flower-that-adds-1-to-your-health">Fixing the small health flower that adds 1 to your health</h2><p>What happens in the game:<br>Instruction 1 : <code>bit 2, a</code> sets the 'z' (zero) flag if the value at bit 2 is 0.<br>So the 'z' flag will be SET if our HP is 1 (bit 2 is not set, value at that bit is 0, so 'z' (zero) flag is true - that makes sense), and UNSET if our HP is 4 (bit 2 is set, value at that bit is 1, 'z' (zero) flag should be false).<br>Instruction 2: <code>jr nz, 41B9</code>, this jumps (skips code) and continues at 41B9 if the 'z' flag is not set (nz = not 'z'). The health incrementation happens before 41B9, so by skipping ahead it doesn't add 1 to your HP.<br><br>What we change those 2 instructions to:<br>Instruction 1: <code>cp a, 06</code> will set the 'z' (zero) flag if a-6 is 0.<br>Now, the 'z' flag is set if we are at max health, before, it was unset if we were at max health, we need to change the jump to handle this. <br>Instruction 1: <code>jr z, 41B9</code> will only jump after the health increment if our health is equal to 6. (We just take away the 'n' from the 'nz' before)<br><br>Thankfully it doesn't take any more space in ROM to change that instruction to <code>cp a, 06</code> which explicitly checks if our health is 6. If the <code>cp</code> instruction did take more space in ROM (different ASM instructions can be made up of different amount of bytes), we would have to jump to a different area in the ROM with enough room, add the code we want there, and jump back to where we came from. It complicates things and I didn't want this small project to stay simple. </p><!--kg-card-begin: markdown--><p><img src="https://jtm.gg/content/images/2019/10/result3.png" alt="Gameboy ROM Hack: Trip World Casual Mode"><br>
After raising max health to 6</p>
<!--kg-card-end: markdown--><p>Although, would it look better if the UI was centered?<br>I didn't perfect it, and I'm not sure if I really do want it centered.<br>I thought about having the text on the far left and the health indicators/points on the far right, but that would be harder and require more modifications to the game. The game only expects a certain amount of tiles to be written on those the 'LIFE' line and the 'SCORE' line. Moving the start position of the line isn't difficult, but adding more tiles to be drawn would be.<br>Below is a screenshot from when I was trying, health didn't (visually) decrement properly when I made it so this screenshot is just for fun.</p><!--kg-card-begin: markdown--><p><img src="https://jtm.gg/content/images/2019/10/result4-2.png" alt="Gameboy ROM Hack: Trip World Casual Mode"><br>
Centered UI (health wasn't fully functional if not at max)</p>
<!--kg-card-end: markdown--><p><br>I've uploaded the hack in the form of an IPS patch to romhacking.net: <a href="https://www.romhacking.net/hacks/4990/">https://www.romhacking.net/hacks/4990/</a><br>Use something like Lunar IPS to patch it to the Japanese ROM which has a CRC32 of 11568E64.</p><p>The finished piece in action:</p><!--kg-card-begin: markdown--><p><img src="https://jtm.gg/content/images/2019/10/tw-realgb-1.jpg" alt="Gameboy ROM Hack: Trip World Casual Mode"><br>
The modded game running on my real DMG (via a EMS 32M flash card - a card with no usb interface or removable storage!)</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[How to Install Ghost 2.x on Debian 9]]></title><description><![CDATA[For some reason, the Ghost team only officially recommend and support Ubuntu.
I prefer Debian.
Starting from a new clean install of Debian 9, here we go:]]></description><link>https://jtm.gg/how-to-install-ghost-2-on-debian-9/</link><guid isPermaLink="false">5cc1502d34a8900579865e4d</guid><dc:creator><![CDATA[Joshua]]></dc:creator><pubDate>Fri, 26 Apr 2019 06:12:00 GMT</pubDate><content:encoded><![CDATA[<p>I found a few other pages with similar stuff, but what I saw was a bit outdated and some things I didn't agree with, so hopefully this is of help to someone.</p><p>For some reason, the Ghost team only officially recommend and support Ubuntu. Many people before me have compared Debian and Ubuntu before, so I won't debate about it here.</p><p>I prefer to use Debian. </p><p>Starting from a new clean install of Debian 9, here we go:</p><!--kg-card-begin: markdown--><ul>
<li>We are root, so create a new user (don't call it ghost!)<br>
<code>adduser coolguy</code></li>
<li>Add this new user to sudoers, to give the user the ability to run privileged commands<br>
<code>usermod -aG sudo coolguy</code></li>
<li>Log in as the new user (su = switch/substitute user)<br>
<code>su - coolguy</code></li>
<li>Update package lists<br>
<code>sudo apt-get update</code></li>
<li>Update installed packages<br>
<code>sudo apt-get upgrade</code></li>
<li>Install nginx<br>
<code>sudo apt-get install nginx</code></li>
<li>Add node to your sources - the list of programs that Debian knows about<br>
<code>curl -sL https://deb.nodesource.com/setup_10.x | sudo bash -</code><br>
The dash at the end of the command basically indicates the file we want to run is the result of the curl command<br>
The -sL simply tells curl to not print anything, and to follow any links if they exist<br>
(Command is from <a href="https://github.com/nodesource/distributions/blob/master/README.md#debinstall">https://github.com/nodesource/distributions/blob/master/README.md#debinstall</a>)</li>
<li>Now that Debian knows about node, you can install it<br>
<code>sudo apt-get install nodejs</code></li>
<li>Install MariaDB to use as our database system<br>
<code>sudo apt-get install mariadb-server</code></li>
<li>Secure MariaDB with a simple command<br>
<code>sudo mysql_secure_installation</code>
<ul>
<li>The current root password should be blank.</li>
<li>You <em>can</em> choose to create a root password but that is optional - you can read why at the end of this article</li>
<li>Answer yes to all questions.</li>
</ul>
</li>
</ul>
<h4 id="nowletssetupadatabaseforghosttouse">Now let's set up a database for Ghost to use</h4>
<p>(We are not letting Ghost set up the database for us, you can read why at the bottom.)</p>
<ul>
<li>Enter the SQL shell<br>
<code>sudo mysql</code></li>
<li>Create a database for our Ghost site<br>
<code>CREATE DATABASE ghost_coolsite_db;</code></li>
<li>Create a user for that database, giving a password<br>
<code>CREATE USER 'ghost_coolsite_usr'@'localhost' IDENTIFIED BY 'my_password';</code></li>
<li>Give that user full control of the database<br>
<code>GRANT ALL PRIVILEGES ON ghost_coolsite_db. * TO 'ghost_coolsite_usr'@'localhost';</code></li>
<li>Exit the SQL shell<br>
<code>exit</code></li>
<li>Install the Ghost command line tool<br>
<code>sudo npm install ghost-cli@latest -g</code></li>
<li>Make a directory for the Ghost install for our website<br>
<code>sudo mkdir -p /var/www/coolsite</code></li>
<li>Change the ownership of this directory to your user<br>
<code>sudo chown coolguy:coolguy /var/www/coolsite</code></li>
<li>Set the correct permissions<br>
<code>sudo chmod 775 /var/www/coolsite</code></li>
<li>Navigate into our directory<br>
<code>cd /var/www/coolsite</code></li>
</ul>
<h4 id="finallywecaninstallghost">Finally we can install Ghost!</h4>
<ul>
<li>Install using the Ghost tool we installed<br>
<code>ghost install</code>
<ul>
<li>Ignore it gently complaining about the OS not being Ubuntu</li>
<li>Enter your domain when it wants</li>
<li>For the MySQL hostname, leave it blank for the default of 'localhost'</li>
<li>Give the database username we created</li>
<li>And the password</li>
<li>And the database name</li>
<li>Say <strong>no</strong> to setting up a Ghost database user, you won't be able to since the database user is not root</li>
<li>Say yes to setting up nginx</li>
<li>If you gave a URL with https, say yes to setting up SSL - you will be asked for an email address</li>
<li>Say yes to setting up systemd</li>
<li>Say yes to starting up Ghost, you are finished!</li>
</ul>
</li>
</ul>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><h4 id="explainationaboutthedatabase">Explaination about the database:</h4>
<p>For security reasons, by default the MariaDB/MySQL root user doesn't log in using a password, the authentication happens via 'unix sockets'.<br>
It means that authentication behind the scenes and you are simply logged in if you have superuser privileges - and even if a password is set for the root user, you won't be asked to enter it. This is not because we are using Debian, this also happens if we are using Ubuntu. It is just what newer versions of MariaDB/MySQL are doing.</p>
<p>When we install Ghost, it offers to setup its database automatically for us which is nice and easy - to do this it needs our root MariaDB/MySQL password.<br>
But remember, our root database user cannot be authenticated via a password, so it will fail.<br>
Our options are to:</p>
<ol>
<li><strong>Change the root database user's authentication method to 'password'</strong><br>
This is what Ghost recommend doing, but changing the authentication method to password might not be as slick as some think because it looks like some things rely on the root password being blank(?):<br>
<a href="https://websiteforstudents.com/mariadb-installed-without-password-prompts-for-root-on-ubuntu-17-10-18-04-beta/#comment-2463">https://websiteforstudents.com/mariadb-installed-without-password-prompts-for-root-on-ubuntu-17-10-18-04-beta/#comment-2463</a></li>
<li><strong>Run Ghost installer with root privilege</strong><br>
This might work but Ghost say not to run ghost-cli commands with sudo (I'm not sure exactly why though)<br>
<a href="https://github.com/TryGhost/Ghost/issues/8682#issuecomment-314984155">https://github.com/TryGhost/Ghost/issues/8682#issuecomment-314984155</a></li>
<li><strong>Set up the Ghost database ourselves</strong><br>
This is easy to do, so I think it's a no-brainer (<em>lowest common denominator</em>) so that's why I chose it. I'm not entirely sure of the reasons MariaDB/MySQL don't use password authentication for the root user, but I guess it's for a good reason, so I feel it's a good idea to leave it how it is.</li>
</ol>
<p>Also, as a rule, it's best not to give anything our root database credentials if it doesn't truly need them. Even though Ghost is open source and we can see what it is doing, bugs exist, people make mistakes and it's just good practice to try to be safe.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[PokeInkDis - Python Pokemon E-Ink Display for Raspberry Pi]]></title><description><![CDATA[PokeInkDis - Displays a random pokemon and weather stats (not random) on a Raspberry Pi + e-ink screen]]></description><link>https://jtm.gg/pokeinkdis-pokemon-eink-display/</link><guid isPermaLink="false">5c7975ee78ea5e56791ed2ac</guid><dc:creator><![CDATA[Joshua]]></dc:creator><pubDate>Thu, 04 Oct 2018 16:07:07 GMT</pubDate><media:content url="https://jtm.gg/content/images/2018/10/PokeInkDis-2018-10-02--78-2.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jtm.gg/content/images/2018/10/PokeInkDis-2018-10-02--78-2.png" alt="PokeInkDis - Python Pokemon E-Ink Display for Raspberry Pi"><p><img src="https://jtm.gg/content/images/2018/10/rapidash.png" alt="PokeInkDis - Python Pokemon E-Ink Display for Raspberry Pi"><br>
<img src="https://jtm.gg/content/images/2018/10/parasect.JPG" alt="PokeInkDis - Python Pokemon E-Ink Display for Raspberry Pi"></p>
<h2 id="shortversion">Short version:</h2>
<p>Displays a random pokemon with weather stats.<br>
Needs to be passed a Dark Sky API key (free) and your coordinates.<br>
<code>python3 PokeInkDis.py -dskey XX -lat XX -lon XX</code><br>
<code>-j</code> puts display in Japanese<br>
<code>-f</code> puts temperature in °F<br>
<code>-g</code> limits to a specific pokemon generation (<code>-g 2</code> for Johto)<br>
<code>-p</code> forces a specific pokemon (<code>-p 25</code> for Pikachu)</p>
<p><a href="https://github.com/llakssz/PokeInkDis/">https://github.com/llakssz/PokeInkDis/</a></p>
<h2 id="longversion">Long version:</h2>
<p>I bought a Raspberry Pi Zero W and an eink screen, and was trying to think of something interesting to do with it.</p>
<p>I decided on showing a random pokemon every day, along with the weather and some visitor stats for my (this) website.</p>
<p>The eink screen I chose is very cool, it has white, black, and red. (I think it's an E Ink Spectra, I've seen these 3 color screens being used in some stores to display the price of items, 12% of E Ink's revenue comes from price labels)</p>
<p>I assumed it supported greyscale too, but no - when I got it I realized it really only has 3 colors. Some pokemon look a bit strange with only 3 colors, but most of them are ok, I'm happy with the result.</p>
<p>The screen's resolution is only 212x104, so I didn't have much room to work with.<br>
The pokemon sprites I used are 96x96, so they just fit in with 4 'pixels' to spare on the top and bottom. The pokemon sprites are from Black/White 2. The later games don't have 2d sprites (right?) - so that's why sixth gen and up isn't supported.</p>
<p>My program is in Python 3, and connects to the eink screen using the <a href="https://github.com/pimoroni/inky-phat/">inkyphat library</a> made by Pimoroni. They created the library for their <a href="https://shop.pimoroni.com/products/inky-phat">eink screens that they sell</a>.<br>
To be honest, I didn't use their screen, I found a cheaper (at the time) alternative on ebay from company called Waveshare, and modified their library to make it compatable after finding <a href="https://boeeerb.co.uk/creating-a-monzo-pot-epaper-tracker/">this</a> page. Thank you boeeerb!<br>
I only used the inkyphat library to push the image to the eink screen, to build the actual image I used PIL.</p>
<p>I tried to annotate the code and explain what's going on, so maybe someone can learn from what I did, or edit it and make their own changes.<br>
If there are any questions please ask!</p>
<p>For the weather icons, I'm using a weather icon font - <a href="https://erikflowers.github.io/weather-icons/">https://erikflowers.github.io/weather-icons/</a> - clever name.<br>
I choose what icon gets drawn by getting the weather status from Dark Sky and matching that up to the correct unicode value for the font from a json file I made. Then I simply draw that character just like any string.<br>
PIL's text renderer doesn't seem to be that good, because I'm sure the weather icon should look better than it does. I'm sure if I rendered it at a larger size and then scaled it down it would look better.</p>
<p>The font for all the text is a cool free pixel/bitmap font - <a href="https://osdn.net/projects/mix-mplus-ipa/releases/58930">https://osdn.net/projects/mix-mplus-ipa/releases/58930</a></p>
<p>You can see in the pictures I have shared that my personal version displays site visitor statistics. I have removed that code from the public version, so there will just be a blank space for you.</p>
<p>I thought about keeping a log of the previous random pokemon that have been displayed, so that you won't get the same pokemon in a row, or a few days later - I might add that functionality later.</p>
<p>I found a cool little holder/case for the Pi and eink screen which you can see in my pictures - <a href="https://coretecrobotics.co.uk/collections/frontpage/products/phatbadge">https://coretecrobotics.co.uk/collections/frontpage/products/phatbadge</a> - it works great. Because that case is meant for the inkyphat screens, the Waveshare screen needed a connector broken off (pliers did it in 10 seconds), and the plastic case needs a little filing or sanding down to make room for a pcb component.</p>
<h2 id="howtosetitup">How to set it up:</h2>
<ol>
<li>Set up almost everything needed to get the eink screen working:<br>
curl <a href="https://get.pimoroni.com/inkyphat">https://get.pimoroni.com/inkyphat</a> | bash</li>
<li>Next, downgrade to the old version because the 1.0 seems to have some bugs, and I know v0.1.1 works:<br>
sudo pip3 install --upgrade inkyphat==0.1.1</li>
<li>I noticed numpy needs libatlas to work (not sure why not installed in the inkyphat installer):<br>
sudo apt-get install libatlas-base-dev</li>
<li>Optional, if you want to play with the examples, delete the Pimoroni folder in your home directory because those are for v1.0 and we downgraded, and should use this: <a href="https://github.com/pimoroni/inky-phat/archive/v0.1.1.zip">https://github.com/pimoroni/inky-phat/archive/v0.1.1.zip</a></li>
<li>If you are using a waveshare eink screen (like me) and not the inkyphat screen, edit the inkpyhat library:<br>
Find the file that we need to edit: <code>sudo find / -name inky212x104.py</code><br>
Copy that file path, open it in something like nano and change these values:<br>
<code>RESET_PIN = 27 BUSY_PIN = 17 DC_PIN = 22</code><br>
to<br>
<code>RESET_PIN = 17 BUSY_PIN = 24 DC_PIN = 25</code></li>
</ol>
<p>Now, my program should run for you.</p>
<h2 id="howtouse">How to use:</h2>
<p>Download from here - <a href="https://github.com/llakssz/PokeInkDis/releases/latest">https://github.com/llakssz/PokeInkDis/releases/latest</a><br>
Sign up for a free (limited to 1000 calls a day) Dark Sky account and get an API key.<br>
Get the latitude and longitude of your location.</p>
<p><code>python3 PokeInkDis.py -dskey XX -lat XX -lon XX</code><br>
<code>-j</code> puts display in Japanese<br>
<code>-f</code> puts temperature in °F<br>
<code>-g</code> limits to a specific pokemon generation (<code>-g 2</code> for Johto)<br>
<code>-p</code> forces a specific pokemon (<code>-p 25</code> for Pikachu)</p>
<h2 id="ifyouwantpokeinddispytorunautomatically">If you want PokeIndDis.py to run automatically:</h2>
<p>Let's assume PokeInkDis.py is in ~/PokeInkDis/<br>
First, in your home directory:<br>
<code>nano run_pokeinkdis.sh</code><br>
Enter these 3 lines (plus any options to PokeInkDis.py you want):</p>
<pre><code>#!/bin/sh
cd PokeInkDis
python3 PokeInkDis.py -dskey YOUR_DARKSKY_API_KEY -lat YOUR_LAT -lon YOUR_LON
</code></pre>
<p>Save and exit nano (Ctrl o, Ctrl x)</p>
<p>Make our script able to be executed:<br>
<code>chmod u+x run_pokeinkdis.sh</code></p>
<p>Now we have a shell script to run PokeInkDis.</p>
<h3 id="tomakepokeinkdisruneverydayat3am">To make PokeInkDis run every day at 3am:</h3>
<p><code>crontab -e</code><br>
Choose nano, then enter this:<br>
<code>0 3 * * * /home/pi/run_pokeinkdis.sh</code></p>
<h3 id="tosetupaservicetostarttheprogramatbootafterwehaveinternet">To set up a service to start the program at boot, after we have internet.</h3>
<p><code>sudo systemctl edit --force --full pokeinkdis.service</code><br>
For me, nano opens up, paste into it:</p>
<pre><code>[Unit]
Description=PokeInkDis
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi
ExecStart=/home/pi/run_pokeinkdis.sh

[Install]
WantedBy=multi-user.target
</code></pre>
<h2 id="morepictures">More pictures:</h2>
<p><img src="https://jtm.gg/content/images/2018/10/rhyhorn.png" alt="PokeInkDis - Python Pokemon E-Ink Display for Raspberry Pi"><br>
<img src="https://jtm.gg/content/images/2018/10/doduo.JPG" alt="PokeInkDis - Python Pokemon E-Ink Display for Raspberry Pi"></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Get PPP password from TG582n Modem]]></title><description><![CDATA[I wanted the PPP details from my modem so I could use them with a better device. Other tricks I found online didn't work, this was very easy to do.]]></description><link>https://jtm.gg/get-ppp-password-tg582n/</link><guid isPermaLink="false">5c7975ee78ea5e56791ed2ab</guid><dc:creator><![CDATA[Joshua]]></dc:creator><pubDate>Wed, 19 Sep 2018 13:15:28 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I wanted the PPP details from my modem so I could use them with a better device. You can easily see the PPP username in the admin page of the modem, but it doesn't give the password.</p>
<p>First I thought to look in the modem's config settings backup, to see if the password is in there. It's not plain text, it's encrypted, and so is the username. I have no idea how to decrypt them, and the method below is easier and faster anyway.</p>
<p>The modem's software version is 8.4.4.J. I don't know if it works with different versions.</p>
<p>Guide:</p>
<ol>
<li>Go to the modem's web interface. Mine is at 192.168.1.254, the ip of your device may be different.</li>
<li>Go to this screen: <img src="https://jtm.gg/content/images/2018/09/step1-1.png" alt="Screen"> (Home -&gt; Broadband Connection -&gt; Internet Services -&gt; Internet) (Your connection may not be called 'Internet')</li>
<li>Click the disconnect button, the page should refresh and show that it is not connected now.</li>
<li>Bring up the 'Inspect Element' tool (right click), or simply view the source code of the page - and you will see your password!</li>
</ol>
<p><img src="https://jtm.gg/content/images/2018/09/result.png" alt="Result"></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Why Windows 10 LTSC is a good choice]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>When I'm not using Fedora or macOS, I use Windows.<br>
I consider myself a poweruser and I like to use (but don't limit myself to) open source software.<br>
The version of Windows I use is Windows 10 Enterprise LTSC.<br>
(It used to be called LTSB, 'Long Term Servicing Branch', 'Branch'</p>]]></description><link>https://jtm.gg/why-ltsc-is-a-good-choice/</link><guid isPermaLink="false">5c7975ee78ea5e56791ed2a9</guid><dc:creator><![CDATA[Joshua]]></dc:creator><pubDate>Sun, 19 Aug 2018 12:27:39 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>When I'm not using Fedora or macOS, I use Windows.<br>
I consider myself a poweruser and I like to use (but don't limit myself to) open source software.<br>
The version of Windows I use is Windows 10 Enterprise LTSC.<br>
(It used to be called LTSB, 'Long Term Servicing Branch', 'Branch' has now become 'Channel'.)</p>
<p><strong>But Microsoft really doesn't want people to use Windows 10 Enterprise LTSC.</strong></p>
<p>Basically, it's Windows 10 but without all the junk. Like Windows 7, but newer.<br>
If one of the first things you do on a new Windows setup is install Firefox/Chrome/$browser, you will know what I mean. You won't find stuff like Edge, the Windows Store, Cortana, etc.<br>
There won't be weird adverts for Candy Crush or Xbox on your start menu.<br>
Everything I want to use on it works, development tools, games, hardware drivers, no problems that I have come across at all.<br>
You can turn off telemetry, unlike Home/Pro.<br>
The only thing I had to remove was the OneDrive links in Explorer, apart from that it's exactly what I want.</p>
<p>Yet many people dissuade you from using it, saying that it's only for 'mission-critical' situations, things like ATM machines, or for medical computers in a hospital that have some sort of life saving equipement attached.<br>
To me that sounds silly, a bit like saying, &quot;Don't use this car, it's too stable, it's meant to never breakdown&quot;.<br>
I want my OS to be just as dependable as those 'mission-critical' ones. I don't want my computer to crash or restart to install an update when I'm watching a movie.</p>
<p>I think the main reason is that LTSC is the least SaaS Windows 10 you can get. SaaS - Software as a Service, is when you basically rent software.<br>
For example, instead of buying a one off license for Microsoft Office 2016 and Adobe CS6, now we have the pay monthly option of Office 365 and Adobe CC.<br>
Like leasing a car, it's good because it's always up to date and the monthly payments are small.<br>
But the negatives are the same: the payments add up, and you never get to own anything.<br>
If you try use Adobe CC offline for 1 month, you will get a warning message. 99 days later and you will only be able to launch it once more, it will stop working.<br>
Adobe doesn't even offer CS6 anymore, only CC.<br>
Microsoft have called Windows 10 'WaaS' - Windows as a Service.</p>
<p><strong>What is the cost I am paying by using LTSC? What am I losing out on?</strong></p>
<p>A Microsoft consultant has written a post here - <a href="https://blogs.technet.microsoft.com/ukplatforms/2018/06/11/say-no-to-long-term-servicing-channel-ltsc/">https://blogs.technet.microsoft.com/ukplatforms/2018/06/11/say-no-to-long-term-servicing-channel-ltsc/</a><br>
He gives many reasons why you shouldn't use LTSC, yet some of the points he gives are exactly the reason I choose to use LTSC! I have shared his points below:</p>
<ul>
<li>Using LTSC means missing out on new OS enhancements that are included in SAC releases – particularly new security features</li>
<li>LTSC does not keep pace with new silicon releases in the same way SAC does – so LTSC 2016 does not support Intel chips beyond the ‘Kabylake’ generation<br>
Windows Analytics Upgrade Readiness does not support LTSC</li>
<li>No support for the modern Edge browser</li>
<li>No support for Cortana</li>
<li>No support for Windows Store</li>
<li>No support for Surface hardware</li>
<li>LTSC does not support ConfigMgr Express Updates</li>
<li>In-Place Upgrade from Windows 7 to Windows 10 is not supported for LTSC<br>
From January 2020, Microsoft Office 365 will not be supported on LTSC<br>
LTSC does not keep pace with feature enhancements to Windows Defender ATP<br>
Potential Independent Hardware and Software Vendor support and limitations on LTSC</li>
<li>Non-security operating system fixes and enhancements may not get back-ported to LTSC</li>
<li>Loosely defined LTSC release cycles make planning ahead more difficult</li>
</ul>
<p>Interesting.</p>
<p>My thoughts:<br>
LTBC definelty gets security updates, so I don't believe there is anything to worry about security-wise. I can live with not getting new little features, things like Microsoft's Night Light. I have been using f.lux/redshift/cf.lumen for years, so that makes no difference to me. I'm not sure about the other feature updates, but I don't feel like I'm missing anything!<br>
I actively stay away from Cortana, Windows Store, and Edge. I'm happy they are gone, it was difficult removing them from 10 Pro.<br>
I don't have use a Surface device.<br>
I'm not upgrading in place from Windows 7.<br>
I don't want to use Office 365, I'll use 2016 or 2019.</p>
<p>The only negatives I think that are important for others:</p>
<ul>
<li>It won't get updates to new chipsets. - <em>Personally I use a notebook, so I'm not going to swap out the CPU.</em></li>
<li>You may not get support from a company, because it's not a commonly used OS. Company ABC might say they don't officially support LTSC, so even if that's not the reason application XYZ isn't working right, they may not help you.</li>
<li>When a new LTSC release comes out and you want to update, I think you need to do a fresh install - you can't update in place. Maybe it is possible! (A new LTSC version comes out every 2-3 years or so, with the latest chipset support and other features from the main Windows 10.)</li>
</ul>
<p><strong>So why shouldn't I use LTSC?</strong></p>
<p>The only reason I feel I shouldn't use LTSC is because I shouldn't normally be able to accquire a license for it, because it's not sold for personal use.<br>
(Looking on eBay though, I can see some licenses being sold for less than $10!)<br>
Apart from that sole reason, I'm perfectly happy to use it and I have done for a while. I'll update to the 1809(?) release when it's out.</p>
<p>If you are not tied into the Microsoft ecosystem and consider yourself a poweruser, and want to have your Windows installation 'just work', I really recommend using LTSC!</p>
<p>If you are interested and want to try out LTSC, check out this link:<br>
<a href="https://forums.mydigitallife.net/threads/discussion-windows-10-enterprise-2016-ltsb.73435/">https://forums.mydigitallife.net/threads/discussion-windows-10-enterprise-2016-ltsb.73435/</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[How to add new playlists and disable the volume cap on a Sony Walkman NW-A45]]></title><description><![CDATA[In the Japanese version of the Walkman NW-A45 you can create playlists, there's no volume cap, and you can record audio.
Sony removed these features in non-Japanese models.
Here is how we can get them back!]]></description><link>https://jtm.gg/walkman-create-playlists/</link><guid isPermaLink="false">5c7975ee78ea5e56791ed2a8</guid><dc:creator><![CDATA[Joshua]]></dc:creator><pubDate>Sun, 03 Jun 2018 09:56:36 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><strong>UPDATE - Also applies to the new A55 model!</strong></p>
<p>To dissuade people from importing things to save money, sometimes companies make the Japanese version of the product a bit more special.<br>
That's why in Japan you get things like bonus tracks/more artwork/free stickers with CDs, or exclusive color choices for some devices. Maybe, possibly, that's the reason that Sony removed features from non-Japanese Walkmans.</p>
<p>Sony's European portable devices come with AVLS (Automatic Volume Limiter System), which stops the volume from getting too loud. Even though this can be turned off in the 'Output Settings', the maximum volume is still a bit limited.</p>
<p>Volume aside, if you attempt to add a song to a playlist on your device, I saw a 'No playlists available' message. There's no option to create playlists, you may only add to a pre-existing one that you put on via your computer.</p>
<p>In Japan though, the NW-A45 can create playlists on the device. It also has no volume cap. Plus it can even make 'line in' recordings, if you have a cable like this: <img src="https://jtm.gg/content/images/2018/06/WMC-NWR1-1.jpg" alt="WMC-NWR1 cable"></p>
<p>(There's more differences, but you're probably not interested in the fact it can play ATRAC files unless you're still living in 1999!)</p>
<p>To enable this all of this stuff, we need to change our device's region to Japan. It takes only a few minutes.<br>
This will not put your player in Japanese, so don't worry, it will stay in the same language you had it in.<br>
Although, when the region is set to Japanese, there will be no Language menu under 'Device Settings', so you won't be able to change the language anymore, unless you change the region back.</p>
<h2 id="guide">Guide</h2>
<p>Download <a href="https://www.rockbox.org/wiki/SonyNWDestTool">SonyNWDestTool</a>.<br>
Make sure your device is connected in Mass Storage Mode (you should see a drive letter like 'H:' under My Computer)<br>
Open CMD (Windows key + R, type 'cmd', hit OK)<br>
CMD should be working in 'C:\Users\MYUSERNAME'.<br>
Assuming the tool downloaded to your Downloads folder, type:<br>
<code>cd Downloads</code><br>
Now test the tool, giving it your drive letter.<br>
<code>scsitool-nwz-v20.exe H: dest_tool get</code><br>
I received this output:<br>
<code>Model: NW-A45<br>
Series: NW-A40 Series<br>
Destination: CEW2 (103)<br>
Sound pressure: 0 (off)<br>
</code></p>
<p>The device was recognized, great.<br>
Let's change the region to Japan.<br>
<code>scsitool-nwz-v20.exe D: dest_tool set J off</code><br>
Output:<br>
<code>Model: NW-A45<br>
Series: NW-A40 Series<br>
Destination successfully changed.<br>
Please RESET ALL SETTINGS on your device!<br>
</code></p>
<p>Now we can unplug the device. Remember to do what it says, by going to:<br>
Settings-&gt;Device Settings-&gt;Reset/Format-&gt;Reset All Settings<br>
Tap yes, and we are all done.</p>
<h2 id="beforeandafter">Before and After</h2>
<h3 id="playlist">Playlist</h3>
<p><img src="https://jtm.gg/content/images/2018/06/walkman_playlists.JPG" alt="walkman_playlists"></p>
<h3 id="homemenu">Home Menu</h3>
<p><img src="https://jtm.gg/content/images/2018/06/walkman_home-1.jpg" alt="walkman_home-1"><br>
I'm not sure why the 3 icons at the top aren't centered, it would look better.</p>
<h2 id="ending">Ending</h2>
<p>As I wrote at the beginning, I understand about bonus tracks on CDs and things like that, but this seems different.<br>
Is on-device playlist creation really a 'bonus'? A 'gift' for the devices bought in Japan?<br>
It's simply a small user experience/quality of life thing.<br>
Very strange.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[GloTool Guide 1: Splitting your Glossika files.]]></title><description><![CDATA[Here we'll be taking your Glossika files and splitting them into 1000, 3000 individual audio files for you to use how you wish.]]></description><link>https://jtm.gg/glotool-glossika-splitting/</link><guid isPermaLink="false">5c7975ee78ea5e56791ed2a7</guid><category><![CDATA[glossika]]></category><category><![CDATA[glotool]]></category><dc:creator><![CDATA[Joshua]]></dc:creator><pubDate>Sun, 27 May 2018 17:23:47 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="introduction">Introduction</h2>
<p>Glossika is a great language learning course.<br>
To explain it simply, the course consists of 3000 sentences.<br>
You hear the sentence in your source language, then you hear it in your target language.<br>
These setences are put together for you in MP3 files, 50 sentences in each.<br>
I wanted to split these files to get 2x 3000 individual sentence audio files. (3000 for the source language, 3000 for the target language)</p>
<p>Although as of late 2017 - early 2018 they phased out their old, fully offline materials and we can't even redownload any old purchases.<br>
I now feel comfortable making this tool public because, I did not want to make any impact on Glossika's sales at all. Glossika's course is now all online, so I'm not worried anymore.</p>
<h2 id="guide">Guide</h2>
<h3 id="setup">Setup</h3>
<p>Get GloTool from my Github - <a href="https://github.com/llakssz/GloTool/releases/latest">https://github.com/llakssz/GloTool/releases/latest</a></p>
<p>You need Python 3 installed, along with the python module 'pydub'.<br>
On my system, Python 3 is installed as 'python', not 'python3'.<br>
If you have Python 3 already installed, you can install pydub by going to your Terminal/Command Prompt and entering:<br>
<code>pip install pydub</code><br>
If pip couldn't be found, try:<br>
<code>python -m pip install pydub</code></p>
<p>You also need to have ffmpeg or avconv on your system.<br>
Install either one and make sure it's in your PATH.<br>
If you are on Windows and have trouble, you can be lazy and place the ffmpeg.exe into the same folder as GloTool.<br>
(Download the archive from <a href="https://ffmpeg.zeranoe.com/builds/">https://ffmpeg.zeranoe.com/builds/</a>, go to the /bin/ folder, use that the ffmpeg.exe)<br>
This exact release worked perfectly for me.<br>
<a href="https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-3.4.2-win32-static.zip">https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-3.4.2-win32-static.zip</a></p>
<p>In this example I will use my English-Japanese Glossika files, and split them up into individual sentences.<br>
It documents any problems and how to fix them.</p>
<h3 id="usage">Usage</h3>
<p>Let's start with Fluency 1 (the first 1000 sentences), the zip file is called ENJA-F1-GMS.zip<br>
Extract it, and you will get GMS-A, GMS-B, and GMS-C.<br>
We want the B files. The B files are special because, for every sentence, they have it in English once, then Japanese once.<br>
Place the GMS-B files in the same directory as GloTool.</p>
<p>Open Terminal/Command Prompt, navigate to the folder where GloTool is and enter:<br>
<code>python GloTool.py GMS-B -Bfiles -s</code></p>
<p>Our input folder is called 'GMS-B'.<br>
They are B files, not C (or A - unsupported).<br>
We want to split these files.</p>
<p>Wait a little, and we see some output:<br>
<code>** ENJA-F1-GMS-B-0001.mp3 **<br>
Detecting silence...<br>
Writing files...<br>
Wrote 102 files - BAD!  X-X-X-X-X-X-X-X-X<br>
We detected too many sentences.<br>
Try using -skipfirst X and -skipend X to fix.<br>
Took 87 seconds<br>
Exiting</code></p>
<p>This is bad, too many sentences were detected in the mp3 file.<br>
There should be 50 sentences for a B file, so 100 separate English and Japanese audio clips.<br>
But we got 102.<br>
Take a look at the output files that were generated.<br>
Look in the 'source' folder (Our source language is English)<br>
0001.wav should be the very first sentence in English.<br>
&quot;The weather's nice today.&quot;<br>
No, we hear &quot;日本語/Nihongo&quot; ('Japanese language' in Japanese)<br>
Why:<br>
At the beginning of these B files, we hear:<br>
&quot;The GMS Method    Fluency 1    English    Nihongo&quot;<br>
We don't want these audio pieces saved, we just want the sentences.<br>
The Glossika files can vary quite a bit among the different languages availiable, I couldn't really make it so all files are detected perfectly all the time, so we have to play around a little.<br>
Solution:<br>
We need to skip an extra piece at the beginning.<br>
By default, the '-skipfirst' argument is 2.</p>
<p>This time, enter:<br>
<code>python GloTool.py GMS-B -Bfiles -s -skipfirst 3</code></p>
<p>Bad output again:<br>
<code>** ENJA-F1-GMS-B-0001.mp3 **<br>
Detecting silence...<br>
Writing files...<br>
Wrote 101 files - BAD!  X-X-X-X-X-X-X-X-X<br>
We detected too many sentences.<br>
Try using -skipfirst X and -skipend X to fix.<br>
Took 88 seconds<br>
Exiting</code></p>
<p>101 pieces were saved. This makes sense, we got 102 last time, and we fixed it to skip one more.<br>
Verify that 0001.wav in the source and 0001.wav in the target folder are what they should be. (Look at your pdf)<br>
They are correct, good.<br>
So the beginning isn't the problem anymore.<br>
There are usually 2 possibilites for the problem:<br>
1 - (Easy) Similar to earlier, we are simply picking up an extra unwanted piece, this time at the end.<br>
2 - (Tricky) One of the sentence pieces has a pause that's too long, and so it looks like a new sentence.<br>
If 2 is the case, you will need to find which file has this too long silence, and cut it shorter (less than 2 seconds) in a program like Audacity.</p>
<p>In my case, listening to 0051.wav (the file that shouldn't exist) in the 'source' folder we hear:<br>
&quot;Licensed by HLXKAG...&quot;<br>
So this is possibility 1 from above, we want to ignore a piece from the end.<br>
We fix this with the argument -skipend. The default is 1, so let's give it 2.</p>
<p>This time, enter:<br>
<code>python GloTool.py GMS-B -Bfiles -s -skipfirst 3 -skipend 2</code></p>
<p>And the output:<br>
<code>Let's split...<br>
** ENJA-F1-GMS-B-0001.mp3 **<br>
Detecting silence...<br>
Writing files...<br>
Wrote 100 files - GOOD! *****************<br>
Took 87 seconds</code></p>
<p>Great! Exactly what we want. Let it run and hopefully there won't be any problems with the later files.</p>
<p>I'll try to make a guide for joining later, although it's not impossible to figure it out yourself looking at GloTool, it's Python after all :)</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>