Tuesday, October 8, 2024

Getting started with Monkey C

OK, now onto the fun part. I've written lots of PHP code before and I generally find it painful. I have to say, the combination of a small project, the project being essentially greenfield, using the latest PHP features and "doing it right" (rather than just hacking something together) actually made that a relatively pleasant experience.

But what I really want to do is to build an app for the watch; as I said, it's something I've been wanting to do for about seven years now. So, let's get started.

Installing the SDK

I'm not sure there's any particular merit to my decisions, but I opted to do all the PHP work on my linux box (where I have PHP installed and it was easy to install other components such as PHPUnit) but have opted to do the watch side of things on my Mac, since Mac is a supported environment for Monkey C (so is linux, for what it's worth).

There is a Getting Started page which I am basically paraphrasing here, although similar instructions are on the download page.

Head over to the Garmin SDK Download page and agree to their terms and click to download the installer. This requires you to have an account and log in - I have done this previously when trying to get things to work, so I can just sign in.

It then downloads the current SDK and a whole bunch of metadata about devices. Fortunately, it downloads the SDK first, so I think we can carry on while it downloads all the devices.

Switching our attention to VSCode, we now install the "Monkey C" extension, complicated a little by the fact that there seem to be a few with the same name; I'm going to install the official Garmin one. It apparently then needs VSCode to restart, and then wants us to "verify the installation" by running the command "Monkey C: Verify Installation". I can do that. I think. It turns out that this requires me to have a "developer key" which was not mentioned in the instructions and is not obviously implied by "verify installation" (in the way it would be by "complete" or "configure" installation). I guess everything depends on context.

I may have generated a key 7 years ago, but if so, I've probably lost it or at least misplaced it (I don't take these things as seriously as I should to begin with, before even thinking about the fact I was just messing around, and that is two computers ago now), so I opt to generate a new one and save it in "a safe place". Hopefully I'll be able to find it again. Then everything seems fine.

The final set of instructions are about installing the SDK for your phone, which I don't want to do right now, so I won't.

Let's Build Something

So there is documentation at the Monkey C page which describes a simple application, but I'm going to follow the instructions at Your First App in order to build something quickly.

So, using CMD-SHIFT-P and Monkey C: New Project, I create a project called metrolink-watch which will be a widget. It then asks what API level I want to use. Normally, I would pick the highest number to be compatible as far into the future as possible; but on this occasion, I would like it to be compatible with the watch I already own. Looking at the compatibility page, I can see that my watch uses API level 3.1.0, so I will pick that one. It then asks me which devices I'm interested in supporting, so I select the "vivoactive 3". It then asks me for a directory. This is presumably the directory where it is going to put my project. Is it going to create a subdirectory, or just put the project there? I don't know, so I play it safe and create a new directory for it ... but no, it creates its own subdirectory. So now I have metrolink-watch/metrolink-watch. OK, delete all of that and start again.

Very good. We now have a project on the disk, in VSCode and incorporated in the workspace. Just what I wanted. The manifest file has also been opened in a special manifest editor. I'm not sure whether I wanted that or not, but I suppose it's not unreasonable.

(By now, the installer has finished its work so I have closed it.)

The continuing instructions on getting started tell me how to configure the manifest, but all of those options are already taken care of, so that's fine. So let's try running it in the simulator and see what happens. The instructions say use CMD-F5 on mac, but that seems to launch "VoiceOver" on my machine. VSCode suggests trying CTRL-F5, but that tells me something about npm not being available. From the Run menu, I get the same message. I try the context menu, and that has an option to "Build Current Project", so I try that, which seems to work, but still doesn't offer me the ability to run the program (it does have the option to run tests). Even when I point at the "binary" (metrolinkwatch.prg), it doesn't have an option to "run me". What am I missing?

(At this point I notice the instructions say, "if all goes well..."; presumably they aware that things not going well is a possibility, but not one they choose to dwell on).

In desperation, I try Run Unit Tests, which at least pops up a window, but doesn't seem to do anything else, presumably because I don't yet have any unit tests (maybe I should write some?).

I still feel I struggle a lot with VSCode and what you need to set it up. I feel that I am missing some kind of launch configuration or task, just like I was with running the phpUnit, and I don't know where to configure it. So let's go google.

On the page about the Monkey C Visual Studio Code Extension, there is a reference to launch.json, which attracted my attention (well, Google's), but before I get to the section on "Editing the Launch Configuration", I see this line:
Before running the program, make sure you have one of your source files (In the source folder with the .mc extension) open and selected in the editor.
which, I have to confess, is also in the instructions I was claiming to follow, but somehow escaped my attention. But no, that makes no difference.

OK, so where would I look for a launch.json? Well, in my .vscode directory in my workspace. It turns out I have four in other projects. I have no idea how VSCode decides which one(s) to use, so I move them all out of the way. Now when I push CTRL-F5, things happen and (eventually) a watch with a monkey in it appears on my screen. Woohoo!

(Interestingly, no launch.json seems to have been generated; if it has, I don't see where it has been put.)

I realize that I have not spent the time I should understanding all of the interactions between system installations, workspaces and projects that I should in VSCode, but this confuses me no end. If it has found five launch configurations, it should have some algorithm to figure out which one to use. Asking me seems like the obvious way, but I would accept "the one in this project". Randomly picking one of the four other projects and then complaining it doesn't work seems ridiculous in the extreme.

So I did some research, and it seems that launch configurations need to be defined in their various launch.json files, but then these can be named within the workspace file and possibly this allows you to see a menu of available launch configurations. But at the same time, I noticed that there is a menu option to create a new launch configuration for a project (Run>Add Configuration...).

When I run this with all my launch.json files moved out of the way, it sensibly creates one in metrolink-watch. But when I do it with an existing launch.json in the workspace, it attempts to add it to that one. So I'm forced into hacking things. I create a new .vscode/launch.json in the metrolink-watch directory, and put in some completely boilerplate content (the version and configuration tags, with minimal content). Now when I select the Run>Add Configuration... and choose Monkey C: Run App, it creates something reasonable for me - but it still put it in the existing one. Still, I can cut-and-paste with the best of them.

OK, for the time being at least, that seems to work, even with the other configurations in place, as long as I am in one of the .mc files.
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "monkeyc",
      "request": "launch",
      "name": "Run App",
      "stopAtLaunch": false,
      "device": "${command:GetTargetDevice}"
    }
  ]
}
Before going any further, I'm going to check that in and tag it as METROLINK_MC_SAMPLE.

On the Watch

The final part of the instructions gives information about "sideloading" an app: that is, loading onto your device without going through the store. So let's try that.

The first step is, reasonably enough, to plug the watch in to the computer. Easy enough.

Then I need to "build for device". I'm confused why the existing build is not enough. Does it need different packaging for simulators and devices? That seems a poor design choice. The instructions say that it will ask you to choose a device, but it didn't ask me (maybe because I only selected one during configuration?) and then asks for an output directory. I'm not sure why it doesn't just put it in bin/ but presumably there's a reason. So I create a new folder called vivoactive3 and click open. Then, it quietly puts another question at the top of the screen: Debug or Release. I didn't notice this the first couple of times through and was very confused as to what was going on (which seemed to be nothing). Eventually I selected Debug and my vivoactive3 directory was populated with a metrolinkwatch.prg file.

Following the instructions, I then copied that across to the device:
$ cp vivoactive3/metrolinkwatch.prg /Volumes/GARMIN/GARMIN/APPS/
Again, this seems a little confusing: the instructions say copy to your device's GARMIN/APPS directory but doesn't give the path to the device. This is apparently /Volumes/GARMIN/, so the full directory path ends up having two GARMIN segments.

And now I can do an ls on that directory:
$ ls -1 /Volumes/GARMIN/GARMIN/APPS/
DATA
LOGS
MAIL
OUT.BIN
SETTINGS
TEMP
metrolinkwatch.prg
OK, this is further I have ever managed to get before.

Turning to the watch, I find it seems "locked" in a weird mode. Presumably this is it's "I am currently connected to a PC" mode. I try unmounting the device, but that doesn't work. I then unplug it and it says "Verifying ConnectIQ apps". Very good. Then it goes back to normal mode. I slide through the widget carousel and the "last" or "bottom" one (as I think of it) says "IQ metrolink-watch" and then less than a second later shows me a picture of a monkey. Excellent. Not quite "hello, world", more sort of "hello, monkey".

But now I can start developing the app.

No comments:

Post a Comment