Trying to improve x49gp
05-05-2018, 10:43 PM (This post was last modified: 08-29-2018 10:33 PM by 3298.)
Post: #14
 3298 Member Posts: 117 Joined: Oct 2014
RE: Trying to improve x49gp
I'm resurrecting this thread because I want to publish another set of x49gp patches. You might wonder why I'm not throwing them at GitHub, but I'd like to avoid creating an account there due to their terms of service and privacy policy (there are some things I'd like to keep private which always end up on a user's public profile). Oh well, I'll just stick to plain old diffs posted in a forum. If anybody wishes to put them onto GitHub or anywhere else, no problem; take them (though please mention author (3298) and source (link to this thread) if you do so). I've sent some of these patches to the current maintainer as well, but he indicated that life is keeping him busy. We discussed a few small bits, but nothing has happened since then (more than 7 weeks) - he must be really busy, so I'm putting this out there myself.

x49gp has seen quite a few changes since I created this thread for the grayscale patch. Most notably, Egan Ford aka datajerk has yielded official maintainer status to ecd aka chwdt. Unfortunately the new maintainer has forked the original GitHub port by NicholasKirchner instead of datajerk's, and the forks have not been merged yet. Some changes (but not all of them) have been copied and wrapped into new commits (cherry-picking the existing ones would have been better, and it would have avoided attributing authorship of the patches from this thread to datajerk when he really is just the committer). Furthermore, there are a bunch of smaller forks on GitHub, but pretty much all of them are variations on the theme "compile fix + firmware update". The compile fixes resemble the one in this thread, which is present in datajerk's fork, and the firmware update is also present in chwdt's fork, so they are redundant. The only one I picked up is the fork by our well-known member Claudio L., which contains a better variant of a change I've been privately using for a few years: he provides a way to enable the debugger, and unlike my primitive version it's not even necessary to recompile for turning it on or off. Therefore I've merged these three forks and then put a bunch of patches on top of that.

---

Okay, with that out of the way, let's get to the details. First, the user-visible changes.
You probably won't notice the fixes unless you ran into their corresponding problems in previous versions, so I'll limit myself to mentioning their existence in this section; they are listed below in the developer-focused section.
What you will notice, however, is that the build process has changed slightly. The readme has been updated to reflect that. For new users, that's probably comprehensive enough to get started, so if "new user" applies to you, just stop reading after finishing this paragraph, download my source package and open the file "README.md" inside it. But until this patch series gets merged into chwdt's fork, you'll want to replace the 'git clone' action by extracting the source archive - I've put the 'git clone' line in there so this can be merged without changes.

For previous users of x49gp, most of my patches are only fixes or additions, so pretty much everything you remember about using x49gp will still work.
The most notable exception is the ./newconfig script - it's gone. Don't worry though, it's not needed anymore; the program itself has received improvements which render it obsolete. Its two usecases were setting up an initial valid configuration, which the program will now do by itself when confronted with an absent or empty config file. The other one is resetting the calculator as if you pushed the reset button on the back. If you need that, you can simply delete the file instead, or (better) look into the options for resetting while the emulator is running (e.g. the F12 key; this particular feature is actually from chwdt's fork).

There is another exception which you will run into unless you use a state file from a previous version: when the flash file does not exist yet, x49gp will create one which only contains the bootcode; you'll need to install a firmware yourself. This may look like a step back compared to the previous system which baked a firmware into the initial flash image, but with the emergence of NewRPL as an increasingly viable alternative to the stock HP firmware I wanted to give the freedom of choice to users. In addition, constructing the initial flash file with the firmware baked into it involved some largely unexplained magic ("marking blocks" was all the relevant code had to say about it); I was worried that might somehow interfere with custom firmware. The firmware images and an update.scp file corresponding to one of them are still shipped with the source, so if you want to run the stock firmware, you won't have to download it separately.

The less apparent changes include the ability to omit the config file on the command line. That means you can now run x49gp without any parameters; in that case it will default to using a config file at ~/.x49gp/config (and if that file doesn't exist, it will be created with default values, of course). It's still possible to specify a config file, allowing you to have multiple instances of x49gp with their own configurations and memory files. I should probably secure it against using the same file for two simultaneously running instances, because they will literally share their memory - that will confuse the hell out of the firmware when they write anything to RAM or flash memory. For now, just avoid doing that. But honestly, x49gp has behaved like that right from the beginning, so that's at least not my fault.

If you want to use an old state file, I should probably point out that a handful of config properties have changed. The "basename" property is gone because it was limiting: you weren't able to move the entire collection of state files without adjusting the basename property. Add the fact that the basename wasn't allowed to be an absolute path (it was always relative to the home directory), and you have a recipe for frustration. Okay, individual filenames were allowed to be absolute, bypassing the basename entirely, but then those have to be adjusted instead. So I thought, why not interpret relative paths as relative to the location of the config file? That way you can move the collection of files without breaking anything. As a bonus, any setup created by ./newconfig and the Makefile which wasn't edited manually will continue working because that setup places all files in the source directory and puts just the bare names of the other files into the filename properties. Also, the duo of properties called "image" and "name" are reorganized into properties called "type" and "name". Previously it was possible to screw these up such that you got a 50g image with 49g+ text colors or vice versa; now you are guaranteed to get a consistent appearance determined by the "type" property (allowed values are hp49g+ and hp50g, other values will default to hp50g and emit a warning on the terminal). The name only affects the window title. (No, the lack of window decoration does not make that useless because it shows up in all places listing window names, such as KDE's dashboard or any kind of window bar that allows text.) Editing the title could be beneficial when using multiple instances at the same time. Unfortunately all old state files will convert to 50g because the "type" property is new and defaults to that, but I guess for the vast majority that's not even a change because they already were set up to be a 50g.

For users who debug ARM programs in x49gp (most likely custom firmware or HPGCC3 programs), I've added the ability to override the default debugger port and the ability to (re-)connect to an already running x49gp session via an additional popup menu entry that's hidden by default. It's hidden to prevent accidents (connecting to the debugger locks up the emulator until the connection is established). Consult the readme, the manpage, or the help page ('x49gp --help' in a terminal, also a new addition) for more info on that.

Now for the other big feature, the ability to install x49gp system-wide. This allows you to run x49gp from any directory, puts a shortcut into your applications menu (still looking for a decent icon), and puts the new manpage into the appropriate system folder. Note that on most systems, you might want to look into creating a package so the package manager doesn't complain about unowned files in the system directories. I've done it on Arch, so it's probably possible on most Unix-based systems (maybe excluding OSX, because Apple likes to do things differently; I have zero experience with installing stuff on OSX and no Mac, so someone else has to figure it out).

And just because I know someone will ask this again: no, Windows is still not supported. No, there are no plans to change this either. I did get x49gp to compile on Windows by swapping MinGW out for Cygwin (which has a compatibility layer that tries to cover up the differences between Windows and Unix) and grabbing another specialized x49gp fork from GitHub, but it crashes on startup somewhere deep inside the QEMU code. Fixing that will probably need a QEMU upgrade - I've been trying for a month to upgrade to a current version, but the 8 years of changes since datajerk upgraded from 0.9.0 to 0.12.50 (they're past 2.12 now) are not playing nice with x49gp, especially because QEMU isn't designed to be used as an emulation library like x49gp does. I'm stuck at an estimated 10% progress with no clear path forward (couldn't even make a binary, let alone one that works), so I'll probably abandon that attempt.

---

For interested developers, here is a summary of the code changes in the form of my commit messages (plus sometimes a few additional notes), and a handful of commands to reproduce the harder parts of the patch series on your computer. (Those who just wish to get the resulting version of the source should grab the attached source package instead.) For this to work, it's necessary that all of the three forks I use stay at the same state as they are at when this post is published. Otherwise some conflicts may show up.

Again, if you plan to push the resulting repository somewhere else, e.g. to GitHub, please remember to put a note about author and source into the commit messages. Seeing one's hard work taken and (implicitly or explicitly) attributed to someone else hurts, even when it's not done intentionally.

1. Set up a local repository and get the three forks in there.
Code:
git clone https://github.com/chwdt/x49gp cd x49gp git remote add -f datajerk https://github.com/datajerk/x49gp git remote add -f claudiobsd https://github.com/claudiobsd/x49gp

3. Perform the first merge and resolve the conflicts. Diffs of merges are not a well-supported thing, so I've created a combined diff (describes the changes in a stable format, but cannot currently be applied automatically) as well as a diff from the state with conflict markers to the state with all conflicts resolved (depends on the exact presentation of the conflicts being the same as for me, which may change depending on git version or settings, but at least there is a tool for applying this). I've written the commands below such that they set a relevant setting to the value I use, so you should be able to just run them. If it fails, the combined diff is there so not all is lost, but applying it by hand means you have to be familiar with the format.
Code:
git config --local merge.conflictStyle diff3 git merge datajerk/master git apply 01.diff
Now you can do a 'git commit -a' as usual.

4. Perform the second merge. Git will not detect any conflicts by itself, but the commits in the fork to be merged add two reasons for compile warnings, and on the other side of the merge is a change that turns warnings into errors, so the result of the merge will be broken. I prefer to fix this in the merge commit itself, so the following command sequence makes it stop before producing a commit and puts a fix in.
Code:
git merge --no-commit claudiobsd/master git apply 02.diff
5. From now on it gets easier as the remaining patches are just that, simple patches. You can apply them using 'git apply' as before, then commit them as you're used to.
This particular commit contains a number of small fixes and enhancements I've collected over a larger timeframe (if you re-read this thread, you may recognize one of them). I'll let the commit message speak for itself:
Code:
Misc changes, mostly fixes: - fix ./newconfig systems other than OSX (broke in c8b823f) - fix palette usage in 2-bit color mode (was broken ever since grayscale was implemented in 18e1003 and its improperly attributed copy f7913eb) - fix continuing from breakpoints in the debugger (never worked, was exposed when the debugger was enabled in 9c1f2ed) - restore the printf statements commented out in 9c1f2ed and hide them with #ifdefs instead - close the server socket after accepting a debugger connection to allow another simultaneous debug session to be started using the same TCP port - use the symbolic constant DEFAULT_GDBSTUB_PORT (already defined in gdb_stub.h as 1234) when starting the gdb server in main.c in place of the raw number 1234 - change Makefile to read the name of the firmware file from the file update.scp instead of hardcoding it; this allows users to switch to another firmware by simply pasting it along with its accompanying update.scp into the x49gp directory
Several of these fixes and enhancements are superseded by changes in later patches, but I left them in there instead of squashing them just in case someone has objections about those later changes.
6.
Code:
Enhance port G (keyboard) handling to remember the value of output bits across periods with these bits configured as input This fixes interaction with HPGCC3 keyboard routines, and it also fixes keys with eint==7 (assuming the stock firmware is in use) needing a double-tap to work unless pressed very shortly after another keypress (the latter broke in b5f93ed)
chwdt nudged me in the right direction on this one. I had a patch that fixed the first of the keyboard issues but didn't affect HPGCC3 at all. He had a theory about how the hardware really worked, I tested and confirmed his theory and wrote a patch based on it.

7.
Code:
Get rid of the deprecated function warning by switching from gdk_pixbuf_new_from_inline to gdk_pixbuf_new_from_data (based on code by chwdt)
We discussed the single warning he excluded from the compile option -Werror, which was about a deprecated function from GTK2. It started with me looking for a replacement that wasn't deprecated but didn't require as much work as the replacement suggested in the official docs. I found one and made a 2-line patch from it, but I wasn't quite happy with the quality of the resulting code; he answered by writing a wrapper around the function I identified that mostly emulates the deprecated function. This patch contains his function with the minor compile errors and a bug that prevented it from working fixed (he was clearly in a hurry when writing it).

8.
Code:
Delete remaining now-redundant CVS files
What it says on the tin. The SVN files and some of the CVS files have been removed by others - might as well finish the job.

9.
Code:
Don't release all buttons anymore if there are still physical keys and/or the left mouse button are holding some down On the other hand, forcibly release all buttons when losing focus to avoid getting stuck in a state with buttons down when they are not held down by anything; this would happen due to missed events while not in focus
The part about keys getting stuck when losing focus is already happening in all previous versions, but it can be worked around by tapping a stuck key. This workaround stops working after the other half of this patch takes effect, because I made that possible by counting how many keys are down, and when events are missed because x49gp is not in focus, this counter goes out of sync. In a key-release event only the key this event is about is processed - unless no more keys are down, then all keys are released. That last part is necessary for releasing right-clicked keys after releasing a key that wasn't pressed via right-click. Before this patch, however, all keys were released in any release event that didn't come from the right mouse button, which prevented actions like typing text with a shift key held down; the shift key would get auto-released after typing the first letter.

10.
Code:
Add a context menu to the screen, containing only "Reset" and "Quit" items for now
The remaining menu items come in later patches.

11.
Code:
Ensure that the files backing flash, sram, and s3c2410-sram exist and have the correct size when opening them Note that if the flash file does not exist, this will not fill it with the code that's supposed to be in there, obviously causing the calculator to crash. That's an improvement for later.
12.
Code:
Allow the config system to fill not only numbers, but also strings (including filenames) with default values basename is excluded, but it's planned to be dropped entirely.
13.
Code:
Add an "install" target to the Makefile This is not fully functional yet; some bits of the configuration (notably, the "basename" property, the UI image property and the flash) need to be set up manually. The "install" target installs some files which will help remove this limitation, though the necessary code is not yet there. The ./newconfig script combined with the "flash-*" targets, which used to be responsible for this job, continue to exist for now. They aren't really suitable for being installed themselves, though.
Okay, one could install the ./newconfig script, but when x49gp is in a state where users can install an already-compiled version from a software repository like Ubuntu's, they won't read a readme file and therefore won't know about the need to run ./newconfig before starting the emulator for the first time. They'll just assume it's broken instead.

14.
Code:
Implement a more generic command-line parser for substantially improved flexibility This allows specifying the debug port, as well as omitting the config file, falling back to a default one at ~/.x49gp/config Also adds a proper help option, though the manual referenced in the corresponding output (a manpage, hopefully) does not exist yet.
15.
Code:
Drop the "basename" config property in favor of interpreting relative paths in the config as relative to the config file's location
16.
Code:
Retire the "image" config property in favor of simply loading the image from next to the binary or from the install directory
17.
Code:
Split the UI name property into name (affecting only the window title) and type (affecting the UI image and in the future also the default bootcode) properties This allows setting the window title independently, which might be useful with multiple different instances; that's the only reason I could think of for keeping the window title configurable at all. Also, change the default calculator type to the 50g everywhere, which probably matches today's user expectations better than the 49g+. The config.tmpl file used by the newconfig script already contained a line specifying that the type should be 50g, which overrode the code defaults unless deleted manually.
18.
Code:
Create a flash file from the calculator model's appropriate boot file if it does not exist, relying on the bootcode to detect the absence of a firmware The bootcode will complain about the missing firmware and enter update mode, so the user needs to supply their favorite firmware version and point the bootcode's updater to it. The easiest way is probably pointing the emulated SD card at a directory containing the firmware and its accompanying update.scp file, and then starting the SD-based update.
19.
Code:
Add SD mount / unmount options to the right-click / menu-key popup menu Due to GTK+ silliness, a file dialog cannot be set to allow file and folder selection at the same time, only one or the other. That is why there are two mount options (folder, image) in the menu now.
20.
Code:
Remove most of the old script-based config-generating system since the binary now has these capabilities as well The sdcard target can stay in the Makefile because generating an image may still be useful sometimes, even though folders are supported too. The firmware images can stay as well because the user still needs to select one during the first start, and this way they can mount the source folder as SD to pick up one.
21.
Code:
Add an applications menu item for installing
You'll need to run 'git add x49gp.desktop.in' before committing, otherwise the new file won't go into the commit.
22.
Code:
Keep some debug output on stderr and a huge vvfat.log file from showing up when not debugging x49gp itself
23.
Code:
Allow (re-)connecting a debugger to a running session This is done through the right-click / menu-key popup menu. To avoid confusion due to the accidental clicks leading to an unresponsive interface (caused by waiting for the debugger to connect), this option is hidden unless option -d or its new companion -D (same as -d, but does not start the debug interface right away) is present. Users who regularly debug with x49gp are encouraged to add -D to whatever shortcut they use to launch x49gp; if -d and -D are both present, the port is the last one explicitly specified (same as multiple of the same variant), and the debug interface will start immediately as instructed by the presence of -d.
24.
Code:
Improved support for hardware keyboards Notably, any pressed key is now interpreted according to its unshifted function. The previous situation could cause some key combinations to press possibly unintended virtual keys, e.g. on a US English QWERTY keyboard Shift+8 would have been interpreted as leftshift-multiply, i.e. typing square brackets. The intention could have been either only the multiply sign or the exp&ln menu (which is leftshift-8); the former conflicts with having both shift keys assigned to virtual keys and prevents some shift-hold virtual key combinations, so x49gp will now assume the latter. Also adds additional keybinds for y^x (caret or circumflex, when available), enhances support for German QWERTZ keyboards (sharp s -> divide, # -> multiply), removes the Alt and Meta keybinds to avoid Alpha presses when switching applications with Alt-Tab or Meta-Tab, and changes the hardware right Shift (formerly rightshift) and Control (formerly unused) keys to do the same as their left counterparts (leftshift and rightshift, respectively), to avoid surprises when typing with the right shift key held down like in a regular text editor. Further input on support for various keyboard layouts is welcome.
Now you can guess what keyboard layout I'm using...

25.
Code:
Update README.md, add manpage, rename other README files to TODO to reflect their contents
Another patch with new files. You'll need to tell Git about the new file x49gp.man.in, and to keep Git from thinking the renamed files got deleted, you'll also have to add TODO and TODO.QEMU.
---

Well, that's that. Unfortunately I had to pick the most efficient compression format I could find (7z with LZMA2 algorithm), split it into a few parts, and append an allowed file extension just to upload it here. That shouldn't be a big problem though, just remove the bogus .zip file extension and open it with any decent archiving program. Enjoy!

Attached File(s)