{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreigy7wtlx5pn6q4lngnln6avm2entxeyflvksqerrcmjojsrszowpm",
"uri": "at://did:plc:ogsypfnyf6uzkppsrqgdirne/app.bsky.feed.post/3m5zflpzvpc62"
},
"path": "/_posts/2024-03-01-ov2-tomtom-adventures/",
"publishedAt": "2026-04-30T11:46:29.176Z",
"site": "https://nickwasused.com",
"tags": [
"TomTom",
"TomTom MyDrive Connect.",
"POIbase",
"https://gordthompson.github.io/ov2optimizer/",
"BP",
"https://tankpreise.uk",
"above",
"[4]",
"here",
"https://www.tomtom.com/en_us/navigation/mydrive-connect/",
"https://bp.com",
"https://gordthompson.github.io/ov2optimizer/ov2FileFormat.html",
"https://plan.tomtom.com/en/"
],
"textContent": "By chance, I have received an outdated version of the TomTom Start 52. The device has no Internet connection by itself, only through the TomTom software \"TomTom MyDrive Connect.\"\n\nOn first connect, the Map of Europe got updated to the newest Version, as TomTom Devices usually get lifelong Map updates, at least for the one included at the time of purchase. I knew that you can save your own **Points of Interest** 's, in short **POI** , as there were some saved already, but there is also the method of importing them with **OV2** files. (I still don't know what **OV2** stands for.)\n\n## POI (ov2) file format\n\nA `ov2` file is a POI database; they contain multiple POIs. For that, they can have 4 record types:\n\n * Deleted records\n * Skipper records\n * Simple records\n * Extended records\n\n\n\nWe only take a look at skipper and simple records, but I have linked a document that describes the others as well, below. [1]\n\nA simple record is, as the name says, simple. It consists of:\n\n * a (little-endian) Byte for the Type. For a simple record, this is always a 2.\n * 4 bytes that define the length of the whole record\n * 4 bytes signed integer for the longitude\n * 4 bytes signed integer for the latitude\n * a \"zero−terminated ASCII string specifying the name of the POI\" [1, p. 12].\n\n\n\nOr, in short, Coordinates and the Name, e.g. A Point in the USA with the Name of \"McDonald's.\"\n\n * The latitude/longitude needs to be divided by **100,000**!\n\n\n\n## adding some files\n\nSo I started adding some POI files from POIbase that contain current construction zones, Hospitals and some more. That is where I got suspicious: The Hospital POI file had numerous Points! How was a weak device capable of showing them **all** on a Map?\n\n## Checking Performance\n\nWhile searching for the file format, I stumbled about https://gordthompson.github.io/ov2optimizer/, especially the page about \"How Indexing Helps.\" What I now knew was that there should be a reasonable amount of skipper records. I set my requirement to 1 skipper record per 20 simple records, as mentioned on the page multiple times.\n\nOne more great thing about the page is that there are tools available `ov2scan` and `ov2optimizer`. So I ran `ov2scan` on the Hospital file:\n\n\n PS C:\\Users\\Nick\\Desktop\\in> ov2scan.exe .\\Hospitals.ov2\n deleted POI records (type 0): 0\n skipper records (type 1): 80\n regular POI records (type 2): 1020\n extended POI records (type 3): 0\n\n\nThat's more than enough, great!\n\n## Creating a `ov2` file\n\nAs a small project, I generate data for all BP gas stations. That is because I usually go to a sub-brand of them, \"Aral.\" While using their official website, I noticed that it was too packed, so I created https://tankpreise.uk.\n\nThe project uses `.json` and `sqlite3`, but it would be a great test to generate `ov2` files!\n\nSo let's say I want to use a list of all BP gas stations worldwide and show them when I get near them. That is around **18,000** POIs. How will the device handle that?\n\nA good thing is that I don't have to test that, as it has been done already. [2] The device needs to calculate the distance to all 18,000 Points! That can't be good. And is even worse, if you show them on the Map, then the Device will do that for every \"Screen Update\" while driving.\n\n### Introduce the skipper record.\n\nAs seen above, A skipper record can skip a certain part of the file when it is not in range. Let's say I have 20 records in New Zealand. Then a skipper record defines the borders of all 20 POIs and the size to skip. So when I am in South Africa, the device only needs to check 2 locations: the border of the skipper record. If we are not near it [3], then we skip the defined size of the 20 records.\n\nHere is an example:\n\n\n decoded skipper record: 1 1050 17658722 -3833799 17507574 -4121712\n decoded simple record: 2 82 176.58722 -39.94494 [NZ-None] BP\n decoded simple record: 2 81 175.38627 -40.17633 [NZ-None] BP Bulls\n decoded simple record: 2 88 175.65618 -40.95201 [NZ-None] BP 2go\n decoded simple record: 2 110 175.60367 -40.34684 [NZ-None] BP\n decoded simple record: 2 95 175.62228 -40.35152 [NZ-None] BP 2go\n decoded simple record: 2 95 175.59529 -40.36307 [NZ-None] BP 2go\n decoded simple record: 2 86 175.38549 -40.17701 [NZ-None] BP\n decoded simple record: 2 88 175.16715 -38.33799 [NZ-None] BP Te\n decoded simple record: 2 103 175.16699 -38.33807 [NZ-None] BP 2go\n decoded simple record: 2 100 175.07574 -41.12353 [NZ-None] BP\n decoded simple record: 2 101 175.45792 -41.21712 [NZ-None] BP 2go\n decoded skipper record: 1 967 17501094 -3678409 17484129 -4126259\n\n\n**Update 14.03.2024:** I am not so sure about the skipper record structure that I defined below. It is based on the official documentation, but when I used that in my scripts, it was not working on the Start 52. But the structure defined on [4] is working!\n\nThe structure of this skipper record is as follows: `decoded skipper record: 1 1050 17658722 -3833799 17507574 -4121712`\n\n * `1`: type = skipper record\n * `1050`: If you are not near me, then skip **1050** bytes, including this record.\n * `17658722`: Longitude of the west edge\n * `-3833799`: Latitude of the south edge\n * `17507574`: Longitude of the east edge\n * `-4121712`: Latitude of the north edge\n\n\n\nThe structure of this simple record is as follows: `decoded simple record: 2 82 176.58722 -39.94494 [NZ-None] BP`\n\n * `2`: type = simple record\n * `82`: total length of this record\n * `176.58722`: Longitude\n * `-39.94494`: Latitude\n * `[NZ-None]` BP: shortened POI name (this can be any string)\n\n\n\nNow let's check if the given size is correct! First we add the size of each simple record together:\n\n\n 82 + 81 + 88 + 110 + 95 + 95 + 86 + 88 + 103 + 100 + 101 = 1029\n\n\nThen we add the **21** Bytes of the skipper record:\n\n\n 1029 + 21 = 1050\n\n\nAnd in fact, **1050** is the size the skipper record defines to skip!\n\n### Map example\n\n(Some points appear to be outside, when in fact they are not.)\n\nIn the map example are Blue points that represent gas stations. The black boxes around them are the defined borders of the skipper records. I have a maximum of 20 POIs in one box. The device would have to do **10** latitude/longitude comparisons.\n\nHere is another one:\n\nYou can see the black borders again; the line should be straight but is bent; this is just a display issue.\n\n# Using the generated file on the device\n\nTo add a `ov2` file to the device, I need to import it here. Then it will magically transfer through \"TomTom MyDrive Connect\" onto the device. This happens really fast.\n\n# Sources and notes\n\n[1] https://archive.org/details/ttnavsdk3_manual_3.0_193\n[2] https://github.com/gordthompson/ov2optimizer, https://gordthompson.github.io/ov2optimizer/\n[3] I actually do not know how this exactly works! [4] https://gordthompson.github.io/ov2optimizer/ov2FileFormat.html\n\nYou can find the generated `ov2` files here.\n\n### archive\n\nThe following links are archived versions, as the main ones could break.\n\nhttps://www.tomtom.com/en_us/navigation/mydrive-connect/\nhttps://gordthompson.github.io/ov2optimizer/\nhttps://bp.com\nhttps://tankpreise.uk\nhttps://gordthompson.github.io/ov2optimizer/ov2FileFormat.html\nhttps://plan.tomtom.com/en/\n\n### tags\n\n#tomtom #ov2",
"title": "OV2 TomTom Adventures",
"updatedAt": "2024-03-01T00:00:00.000Z"
}