Magic Reader Documentation 0.3
August 4th, 2020
Shonumi aka D.S. Baxter

***************************************************
1. Introduction
***************************************************   

Beast Shinden: Ultimate Beast Battlers for the NDS used a special Slot-2 device called the "Magic Reader", which allowed players to scan collectible trading cards to battle opponents. Released in 2007 by Konami, the game makes heavy use of the scanning functionality, and the accessory is required for the software. While the card game itself is yet another monster fighting TCG, the scanning process itself was unique. Whereas all previous card reading devices on the DMG, GBC, GBA, and NDS involved swiping a card through a slot, the Magic Reader detects the card when hovered over its sensor.


***************************************************
2. General Hardware Information
***************************************************

* The Magic Reader is a dark-gray add-on that sticks out of Slot-2. It has a bulb at one end housing an optical sensor
* A small guard can be added or removed to better suit an NDS Lite or original NDS Slot-2
* Uses a Sonix SN9S102C image sensor
* Uses a Sonix SN9P701FG-005 Optical ID decoder


***************************************************
4. Device Detection
***************************************************

The software will read some values from the GBA cart space between 0x8000000 and 0x801FFFF. The following psuedo-code will allow software to properly detect the presence of the Magic Reader:

//Read individual bytes from GBA cart space
if address AND 1
	return 0xFB
else
	return 0xFF


***************************************************
5. I/O Registers
***************************************************

-------------------------------------
MR_CNT 	(R/W)	0xA000000
-------------------------------------
Bit 0	(W) 	Serial Clock aka SCK 		
Bit 1	(R/W) 	Serial Data IO aka SDIO
Bit 2	(W) 	NDS Read (1) or Write (0) Flag
Bit 3	N/A
Bit 4	N/A
Bit 5	N/A
Bit 6	(W)	Power On Optical ID?	
Bit 7	N/A

SCK and SDIO are used for the so-called "two-wire interface" between the NDS and the Optical ID decoder. Using those two bits, the NDS communicates with the Magic Reader to send commands as well as retrieve image data. SCK must be pulsed from LOW to HIGH (0 to 1) by the NDS to start or continue receiving or sending data. The Magic Reader can signal to the NDS that it has data available to read by setting SDIO LOW, however.

Although the two-wire interface's protocol makes read and write operations explicitly different, MR_CNT appears to use Bit 2 to indicate the direction I/O direction. For reads, this bit is set HIGH, but for writes it is set LOW. Oddly enough, this is the inverse of SDIO when sending the Read/Write bit used for the two-wire interface.

Bit 6 appears to be set by the NDS before powering on the Optical ID decoder, effectively waking it from sleep mode. In that case, the Magic Reader should set SDIO low to indicate it has data for the NDS to read (the OIDCmd_PowerOn value).

It is important to note that when reading MR_CNT, all bits except for Bit 1 are always set HIGH. In effect, when reading MR_CNT, only two values are ever returned: 0xFB or 0xFF.


***************************************************
6. Two-Wire Interface: Reading
***************************************************

The Magic Reader must set SDIO LOW to indicate to the NDS that data is available to read. This is often in response to a command sent by the NDS, or in some cases by setting Bit 6 of MR_CNT. Once the NDS recognizes that the Magic Reader is requesting a read, the following happens:

1) NDS sets SCK and SDIO LOW and sets Bit 2 of MR_CNT HIGH for the duration of the transfer.

2) NDS sets SCK HIGH and sets SDIO LOW to indicate a read operation for the two-wire interface.

3) NDS sets SCK and SDIO LOW to begin data transmission.

4) NDS sets SCK and SDIO HIGH, then reads MR_CNT. The SDIO bit indicates incoming data from the Magic Reader arriving MSB first.

5) NDS sets SCK LOW and SDIO HIGH. Steps 5-6 are done a total of 23 times to receive a 23-bit value from the Magic Reader.

6) NDS sets SCK LOW and SDIO HIGH and sets Bit 2 of MR_CNT LOW to indicate that the transfer is complete.

Below is an example of how the NDS would read data from the Magic Reader:

-------------------------------------
INIT TRANSFER
-------------------------------------
READ  -> 0xFB	//SDIO = LOW, Magic Reader has data to send
WRITE -> 0x04	//SCK = LOW, SDIO = LOW, Bit 2 set HIGH for duration of transfer
WRITE -> 0x05	//SCK = HIGH, SDIO = LOW, sets R/W bit
WRITE -> 0x04	//SCK = LOW, SDIO = LOW, transfer data now
-------------------------------------
TRANSFER DATA
-------------------------------------
WRITE -> 0x07	//SCK = HIGH, SDIO = HIGH, data is available now
READ  -> xxxx	//SDIO = Bit 22
WRITE -> 0x06	//SCK = LOW, SDIO = HIGH

WRITE -> 0x07	//SCK = HIGH, SDIO = HIGH, data is available now
READ  -> xxxx	//SDIO = Bit 21
WRITE -> 0x06	//SCK = LOW, SDIO = HIGH

...

WRITE -> 0x07	//SCK = HIGH, SDIO = HIGH, data is available now
READ  -> xxxx	//SDIO = Bit 1
WRITE -> 0x06	//SCK = LOW, SDIO = HIGH

WRITE -> 0x07	//SCK = HIGH, SDIO = HIGH, data is available now
READ  -> xxxx	//SDIO = Bit 0
WRITE -> 0x06	//SCK = LOW, SDIO = HIGH
-------------------------------------
END TRANSFER
-------------------------------------
Write -> 0x02	//SCK = LOW, SDIO = HIGH, end communications
-------------------------------------

The data for each bit is available after clocking SCK HIGH. The value of SDIO is valid until SCK is set HIGH again. Even after setting SCK LOW, MR_CNT can still be read and SDIO will reflect the serial 23-bit data. Juushinden, the only official software that uses the Magic Reader, reads MR_CNT after setting SCK LOW, for example. 

Switching SCK from LOW to HIGH has several timing conditions. SCK should be set LOW for a minimum of 2μs during the transfer and should ideally not exceed 64μs. Going further than 64μs stops the transfer. SCK should be set HIGH for a minimum of 2μs. The 23-bit data format is described below:

-------------------------------------
Magic Reader Data
-------------------------------------
Bit 0  - Bit 17		Optical ID Index
Bit 18 - Bit 19		Reserved (Always 0)
Bit 20			Battery Status
Bit 21			Data Type (Command/Index)
Bit 22			Reserved (Always 1)
-------------------------------------

Bits 0 through 17 represent the Optical ID Index. The SN9P701FG-005 automatically takes image data from the SN9S102C and converts it into a binary number. The image data is similar to e-Reader dot-code or QR codes, so they can be reduced to a single value. Different models of the SN9P701-00X support different amounts of indices. The SN9P701FG-005 supports a total of 65536 indices with a range of 0x0000 to 0xFFFF. There are extra indices up to 0x3FFEF reserved for future use. Indices above 0x3FFEF have special usages:

-------------------------------------
Extended Index Usage
-------------------------------------
0x3FFF0 - 0x3FFFA	Reserved for internal use
0x3FFFB			Null response when no usable data is returned to NDS
0x3FFFC - 0x3FFFF	Captured image not recognized
-------------------------------------

The battery status is a single bit that describes whether the SN9P701 has a high or low battery (1 or 0, respectively).

The data type describes what the NDS is receiving. If Bit 21 is set LOW, then the Magic Reader is returning a regular index after having processed an image. If Bit 21 is set HIGH, the Magic Reader is responding to a command with pre-set data:

-------------------------------------
Command Responses
-------------------------------------
0x60FFF8	OIDCmd_PowerOn
0x60FFF7	OIDCmd_PowerDown
0x60FFF1	OIDCmd_SystemReset
-------------------------------------


***************************************************
7. Two-Wire Interface: Writing
***************************************************

The NDS can transfer a command to the Magic Reader like such:

1) NDS sets SCK and SDIO LOW and sets Bit 2 of MR_CNT LOW for the duration of the transfer.

2) NDS sets SCK and SDIO HIGH to indicate a write operation for the two-wire interface.

3) NDS sets SCK LOW and sets SDIO HIGH to begin data transmission.

4) NDS sets SCK HIGH and sets SDIO accordindly to trasmit 1 bit of the command MSB first.

5) NDS sets SCK LOW and maintains the same SDIO level from Step 4. Steps 4-5 are done a total of 8 times to send an 8-bit command to the Magic Reader.

6) NDS sets SCK LOW and SDIO HIGH and sets Bit 2 of MR_CNT LOW to indicate that the transfer is complete.

Below is an example of how the NDS would send the 0xA3 command:

-------------------------------------
INIT TRANSFER
-------------------------------------
Write -> 0x00	//SCK = LOW, SDIO = LOW, signals start of operation
Write -> 0x03	//SCK = HIGH, SDIO = HIGH, sets R/W bit 
Write -> 0x02	//SCK = LOW, SDIO = HIGH, transfer data now
-------------------------------------
TRANSFER DATA
-------------------------------------
Write -> 0x03	//SCK = HIGH, SDIO = Bit 7 (1)
Write -> 0x02	//SCK = LOW

Write -> 0x01	//SCK = HIGH, SDIO = Bit 6 (0)
Write -> 0x00	//SCK = LOW

Write -> 0x03	//SCK = HIGH, SDIO = Bit 5 (1)
Write -> 0x02	//SCK = LOW

Write -> 0x01	//SCK = HIGH, SDIO = Bit 4 (0)
Write -> 0x00	//SCK = LOW

Write -> 0x01	//SCK = HIGH, SDIO = Bit 3 (0)
Write -> 0x00	//SCK = LOW

Write -> 0x01	//SCK = HIGH, SDIO = Bit 2 (0)
Write -> 0x00	//SCK = LOW

Write -> 0x03	//SCK = HIGH, SDIO = Bit 1 (1)
Write -> 0x02	//SCK = LOW

Write -> 0x03	//SCK = HIGH, SDIO = Bit 0 (1)
Write -> 0x02	//SCK = LOW
-------------------------------------
END TRANSFER
-------------------------------------
Write -> 0x02	//SCK = LOW, SDIO = HIGH, end communications
-------------------------------------

Like reading on the two-wire interface, switching SCK from LOW to HIGH while writing has several timing conditions. SCK should be set LOW for a minimum of 2μs during the transfer and should ideally not exceed 64μs. Going further than 64μs stops the transfer. SCK should be set HIGH for a minimum of 2μs.

Depending on the command sent, the Magic Reader may immediately reply with its own data (setting SDIO LOW to indicate a read request). Below are the supported commands for the Magic Reader:

Command 0x24 - Unknown Command
This appears after UserCMD_AutoSleepFunDisable (0xA3). It does not appear to expect a response from the Magic Reader.

Command 0x30 - UserCmd_CheckOIDStatus
Instructs the Optical ID to return its status. Magic Reader will typically reply with OIDCmd_PowerOn, OIDCmd_PowerDown, OIDCmd_SystemReset, a valid index, or a null response.

Command 0x50 - UserCmd_NonClearAutoSleepTimerIfOIDDetect
Instructs the Optical ID to not clear the auto-sleep timer when reading an index.

Command 0x56 - UserCMD_PowerDownOID
Instructs the Optical ID to enter sleep mode.

Command 0xA0 - UserCMD_AutoSleepFunEnable
Instructs the Optical ID to enable the auto-sleep timer.

Command 0xA3 - UserCMD_AutoSleepFunDisable
Instructs the Optical ID to disable the auto-sleep timer.

Command 0xA6 - UserCMD_TriggerToClearAutoSleepTimer
Manually clears the auto-sleep timer.

Command 0xAC - UserCMD_ClearAutoSleepTimerIfOIDDetect
Instructs the Optical ID to clear the auto-sleep timer when reading and index.


***************************************************
8. Control Flow
***************************************************

Below is the general control flow used for Juushinden. Note that the full functionality of the SN9P701FG-005 is not necessarily used. There are generally 2 phases: 1 for the initial startup (shortly after the game boots) and the other used when reading cards.

-------------------------------------
Initial Startup Sequence
-------------------------------------
1) NDS writes 0x42 to MR_CNT to force Power On. For this step, EXMEMCNT is set to 0xE003. For all subsequent steps, Bits 0-1 of EXMEMCNT are set LOW.

2) Magic Reader sets SDIO LOW to indicate a read request. NDS reads OIDCmd_PowerOn from Magic Reader.

3) NDS sends UserCMD_AutoSleepFunDisable and unknown command 0x24.

4) NDS continually sends UserCMD_PowerDownOID and waits for Magic Reader to respond with OIDCmd_PowerDown.


-------------------------------------
Card Reading Sequence
-------------------------------------
1) NDS writes 0x42 to MR_CNT to force Power On. For this step, EXMEMCNT is set to 0xE003. For all subsequent steps, Bits 0-1 of EXMEMCNT are set LOW.

2) Magic Reader sets SDIO LOW to indicate a read request. NDS reads OIDCmd_PowerOn from Magic Reader.

3) NDS sends UserCMD_AutoSleepFunDisable and unknown command 0x24.

4) NDS continually reads MR_CNT for incoming read requests from the Magic Reader. A 23-bit index value is then read.

5) NDS should compare the last index from the last read request and validate the value.


***************************************************
9. Card List and Index Values
***************************************************

There are total of 240 cards for Juushinden released in 4 sets of 60. There are also an unknown amount promotional cards. For the regular sets, the index values returned by the Magic Reader roughly matches the number printed on the card itself.

-------------------------------------
Set 1 - 第一弾「大いなる覚醒の時」
-------------------------------------
Card #	| Index	| Name
-------------------------------------
JS1-01	| 0000	| アバレ ピッグ
JS1-02	| 0001	| アダーガニ
JS1-04	| 0003	| レッドバンサー  
JS1-06	| 0005	| イカレコング
JS1-07 	| 0006	| タコ力士
JS1-08	| 0007	| ナックルリザード  
JS1-09 	| 0008	| イーグルカンフー
JS1-10	| 0009	| バルキー バイソン 
JS1-11	| 000A	| バクルオン
JS1-12	| 000B	| ブラックドーベル	
JS1-13	| 000C	| ガオー
JS1-14	| 000D	| 剛力獣神ガオー
JS1-15	| 000E	| モドリ玉	
JS1-18	| 0011	| ダイバクハーン
JS1-20	| 0013	| ソードザック
JS1-21	| 0014	| スルメボーイ 
JS1-22	| 0015	| 八つ裂きバチ
JS1-23	| 0016	| カワ・ウソン	
JS1-25	| 0018	| クワガイアス
JS1-26	| 0019	| スカルドレイン
JS1-28	| 001B	| ヨロイガエル
JS1-32	| 001F	| ザバット
JS1-33	| 0020	| シャア
JS1-37	| 0024 	| シールドブレイク
JS1-38	| 0025	| ソードブレイク
JS1-39	| 0026	| 聖なる闘技場
JS1-41	| 0028	| ポメ剣士
JS1-42	| 0029	| シロクマックス
JS1-43	| 002A	| アチョーモンキー
JS1-47	| 002E	| ハイエナガード
JS1-48	| 002F	| ヘビダイル
JS1-49	| 0030	| ブルドクター
JS1-50	| 0031	| エンゼルスワン	
JS1-52	| 0033	| 怪力エレファン
JS1-53	| 0034	| タイガ
JS1-57	| 0038	| いでよ鋼の盾
JS1-59	| 003A	| 炎の闘技場


The cards themselves use tiny carbon dots to produce an index value. According to the OID specification, carbon ink can replace K when using CMYK. Black colors would need to be reproduced by merging CMY dots in close proximity to one another. At any rate, these dots are meant to absorb light rather than reflect it. The CMOS inside the Magic Reader can't detect these dots, so these "empty" spots form a pattern that can be recognized and converted into a number. These dots are not completely invisible to the human eye, however. Ordinary cameras are capable of capturing them. The dots occupy the entire face of the card with the exception of the borders and likely the silver text of some cards.
