Skip to content
Michael Farrell edited this page Oct 5, 2019 · 6 revisions

Octopus is the smart-card ticketing system in use in Hong Kong. Octopus uses FeliCa card media. They are readable by the official Octopus App, but only with an internet connection.

Related cards:

  • First-generation (pre-2007) Shenzhen Tong (SZT) are the same format as Octopus, but use a different System Code and encode the balance in CNY. Second generation (post-2007) cards are ISO 7816-based, and are an entirely different format.
  • Hu Tong Xing (互通行) cards are a FeliCa card that acts as both an Octopus and first-generation SZT card (despite being issued from 2012-09-11). We don't have any samples of this.
  • Octopus Lingnan Pass we presume to be also FeliCa, but don't have any samples. These were issued from 2012-07-18.

nfcard has a reader for this: FelicaReader.

All references to FeliCa Codes are little endian, and references to card data are big endian.

Metrodroid changes

  • v2.9.29 (2016-12-01): Adds support for Octopus and first-generation SZT cards
  • v2.9.38 (2019-03-09): Handles post-2017 balance offset change

Detecting

FeliCa cards normally respond to a poll for all System Codes, and polling for Service Codes in a System Code. However some older Octopus cards do not respond to this.

Metrodroid works around this by explicitly polling for Octopus' System Code and then presuming the Octopus Balance Service Code will also be present. This is also applied to first-generation SZT cards -- though we don't have any samples, we presume the bugs will be the same... :)

Card System Code Balance Service Code
Octopus 0x0880 0x0117
SZT (1st gen) 0x8005 0x0118

Balance data (16 bytes)

First Last Length Field description
0 3 4 Balance in units of 0.1 HKD, plus 500 (eg: 551 = 5.1 HKD)
4 13 10 unused
14 15 2 unknown

Note: For Shenzhen Tong, the balance is in CNY rather than HKD. We think this is still offset by 350 rather than 500.

Balance offset change (2017-10-01)

Note: This only applies to Octopus.

As of 2017-10, some cards allow a negative balance of up to 50 HKD. The previous limit was 35 HKD (which still applies to some older cards depending on issue date).

Before this change the balance was offset by 350, and after it was offset by 500. Because of this, we think Octopus treats the balance as effectively an unsigned value. So 00 00 00 00 represents the maximum amount negative value (debt) that a card may be in.

This results in the balance being encoded differently. We assume (based on the FAQ) this change was implemented by updating the balance field the next time the card is used in the Octopus system (regardless of whether it supports the new 50 HKD limit), rather than crediting all Octopus cards 15 HKD (which would be expensive!)

We don't have samples of the same card before and after the change to know for sure if the unknown data can be used to identify an updated vs. not-updated card.

To resolve this, Metrodroid assumes all Octopus scanned after 2017-10-01 to be in the "new" format.

If a card has not been used since 2017-10-01, this will result in an incorrect balance being shown (15 HKD lower than actual). But we would rather be correct for cards that have been used more recently.

See also: Octopus card years [QUESTION].

Clone this wiki locally