General Info

This wiki aims to document some details about the Pokewalker in a more organised way than Dmitry's original article. Also included will be more information and an expanded scope than the article also.

The wiki is divided into different sections, mostly aimed at people developing things for the Pokewalker.

  • The behaviour section details the inner workings of certain modules and sub-modules of the walker.
  • The manipulation section details things that can be done to manipulate things on the walker, such as RCE and re-flashing the firmware on the walker.

There are also sections for the EEPROM map, data structures used in the walker as well as all of the IR commands used in comms between the walker and either the DS or another walker.

This wiki aims to be actively updated whenever new discoveries are made for the walker.

Resources

Tools

Pokewalker Hardware

Definitions

Pokemon

  • POKEMON is just a generic name. Should only be used for sizes, not addresses.
  • CURRENT_POKEMON is the current pokemon on a walk. Unknown if "joined" pokemon are treated the same.
  • EXTRA_POKEMON is the pokemon gifted as an event by CMD_C2 or caught on a special route.
  • ROUTE_POKEMON are the three regular route-available pokemon. Stored in route_info_t.route_pokemon[].
  • GIFTED_POKEMON exclusively refers to the pokemon gifted by CMD_C2.
  • SPECIAL_ROUTE_POKEMON is the extra pokemon on the special route. Stored in special_route_info_t.special_pokemon.

Items

  • ITEM is a generic name, only used to refer to uint16_t le_item.
  • DOWSED_ITEM is an item currently in the inventory that was obtained through normal dowsing.
  • EXTRA_ITEM is an item currently in the inventory that was either obtained though a CMD_C2 gift or dowsed on a special route.
  • ROUTE_ITEM is an item not currently in the inventory, that is available to be dowsed thorough normal dowsing.
  • GIFTED_ITEM exclusively refers to the item gifted by CMD_C2
  • PEER_PLAY_ITEM is an item received after engaging in peer play.
  • SPECIAL_ROUTE_ITEM is an item not currently in the inventory, that is only available to be dowsed though special route dowsing.

Behaviour

This section outlines the detailed behaviour of the Pokewalker's apps ans subsystems. They may be in a bit of an unorganised state since I have been writing it as I've been reverse engineering the Pokewalker. Some information may be wrong, so take with a grain of salt.

Steps and Watts

This is more "health data" focussed, which contains steps and watts.

Function 0x24ac:process_step_taken

  • Compares two bytes, if they're equal then exit function
    • Probably how many steps are left to process
  • Increment byte 0xf7b4
  • If its less than 64, exit function
  • Increment 0xf7a4:watts_gained_since_last_sync, clamping to 9999
  • Increment 4-byte 0xf79c:current_steps, clamping to 99999
  • Increment 4-byte ram_health_data.total_steps, clamping to 9999999
  • Increment ram_health_data.steps_this_watt
  • If >= 20, subtract 20 and increment ram_health_data.current_watts, clamping to 9999
  • increment byte 0xf7b3 and compare to 0xf7b2
    • If 0xf7b3 <= 0xf7b2 then skip next step
  • set 0xf7b3 = 0xf7b2
  • Decrement byte 0xf7b4 by 63

Writing ram_health_data to eeprom

  • In add_watts
  • On receive command 0x20_IDENTITY_DATA_REQ
  • On receive commands 0x32, 0x40, 0x52
  • On receive command 0x66
  • On receive commands 0xc6, 0xd6
  • On walk start
  • On walk end
  • On battle lost
  • On log event
  • On pokemon join route
  • On update settings
  • Before entering dowsing or radar (to subtract watts)
  • On initialising eeprom

Periodic events

Function 0xa34a:regular_processing

Checks if each of the RTC_EVENTS bits are set, and if they are, perform that task. Only does anything for minute, hour and day.

Minute just increments walk_minute_counter. Hour and day have separate functions, seen below.

Function 0xa682:rtc_sec interrupt routine

  • Sets current_second
  • Increments ram_health_data.last_sync seconds counter
  • increments seconds_counter, clamping to 3600 seconds
  • Decrements sleep_mode_countdown
  • Decrements deep_sleep_countdown
  • Clears RTC interrupt bit

Function 0xa3aa:perform_every_hour_tasks

  • sets bit 2 in common_bit_flags
  • checks if total steps < 9999999 (7 9s)
    • If not, skip today steps checking
  • Checks if ram_health_data.today_steps < 9999999 (7 9s)
    • If not, skip increment
  • Increment ram_health_data.today_steps
  • Write ram_health_data to eeprom
  • Check if we have a pokemon (walker_status_flags.2 is set)
    • If we don't, skip to end, setting watts to 0
  • Read route_info from eeprom
  • Check if we're on a special route
  • Log event with type 0x1B_EVENT_TYPE_FELL_ASLEEP
  • Zero 0xf7a0:current_watts
    • This is watts gained since last write? Not actual current held watts
  • Check if time if at end of day hour in BCD
    • If so, set RTC_EVENTS bit 2 (every day?)

Function 0xa45e:perform_every_day_tasks

  • Increment ram_health_data.total_days, clamping to 9999
  • Write ram_health_data to eeprom
  • Read eeprom 0xcef0:historic_step_count
  • Shift the step count array, deleting 7th day and making room for today
  • Write today's steps at index 0
  • Write back to 0xcef0:historic_step_count
  • Fills 10 slots in 0xde24:MET_PEER_DATA with 40 bytes of 0xff

Pokewalker Sleep

Device has two sleep modes, "normal" sleep and "deep" sleep.

"Normal" sleep is triggered after 60 seconds of inactivity. "Deep" sleep is triggered after 90 seconds of inactivity.

Walker keeps track of what sleep state its in with bits [3..4] of 0xf7b6:walker_status_flags.

When putting the walker to sleep, the main event loop changes to sleep_mode_event_loop.

On wake-up, it resets these counters, and checks what sleep state its in. If it's in "deep" sleep mode, it resets the accel sample index to 0 then does the same as normal sleep. In "normal" sleep mode (and deep sleep) it sets the walker_status_flags to "awake" and tells the LCD to exit power save mode.

On "deep" sleep, it stops TIMERW, clears bit 2 of CKSTPR1, sets walker_status_flags to "deep sleep" and clears bit 0 of RTC_RTCCR2. On "normal" sleep, it sets bit 2 of CKSTPR1, sets walker status flags to "normal sleep", sets bit 2 of RTC_RTCCR2, sets the "deep sleep" countdown to 30 and clears bit 7 of 0xf7b5:common_bit_flags, likely to indicate that we aren't walking any more.

Function 0x7882:sleep_mode_event_loop

TODO

Walk Start

Procedure

  • Normal handshake, DS asserts master

What the walker does

On rx 0x5a:

  • runs start_walk
  • zeroes 0x6c8 bytes at 0xb800
  • go to animation

On rx 0x38:

  • runs start_walk
  • go to animation

Function start_walk

  • Write 0xa5 to eeprom reliable data area copy markers
  • (start of function eeprom_unfinished_copy)
  • copy 0x2900 bytes from eeprom 0xd700 to 0x8f00
  • copy 0x280 bytes ftin eeprom 0xd480 to 0xcc00 (my team data)
  • clears copy marker in eeprom reliable data area
  • (end of function eeprom_unfinished_copy)
  • zero event log (same as walk start)
  • zero peer team data, 0x1568 bytes of eeprom at 0xde24
  • zero current watts
  • zero health_data.walk_minute_counter
  • zero health_data.event_log_idx
  • zero health_data.current_watts
  • write ram cache health data to eeprom
  • reads walker_info_t from eeprom
  • set walker status flag bits [0..1], clears bit [2]
  • copy unk{0..3} in walker_info from peer_walk_info
  • copy walker_info.{tid,sid} from peer_walk_info
  • copy trainer_name, protocol_ver, protocol_subver, unk5 from peer_walk_info
  • sets walker_info.unk8 to 2
  • reliable write walker_info_t to eeprom
  • sets up walk start log event
  • writes walk start log event
  • clears obtained items/pokemon/peer items (zeros 0x64 bytes at 0xce8c)

Log

  • calls logEvent
  • e1 = 0x0000
  • [sp] = settings byte u8 and settings byte&0x01 u8
  • event type 0x19
  • isOnSpecialRoute = settings byte&0x01

Walk End

Procedure

  • Normal handshake, DS asserts master.
  • DS sends CMD_IDENTITY_REQ 0x20, no data
  • Walker sends CMD_IDENTITY_RSP 0x22, contains walker_info_t (IdentityData)
  • DS sends 0x40, contains walker_info_t (IdentityData) idk what to do with it
  • Walker sends 0x42, no data. Strange since this is apparently CMD_IDENTITY_SEND_ALIAS1
  • DS does a bunch of reads.
  • DS ping
  • Walker pong
  • DS sends CMD_WALK_END_REQ 0x4e
  • Walker sends CMD_WALK_END_RSP 0x50
  • End of connection

What the walker does

  • End walk action (after 0x4e)
    • clear special route bit in RamCache_settingsByte
    • clear walker has poke bit in walker_status_flags
    • set log write pointer to top of stack
    • set current watts to zero
    • copy ram health data to reliable HEALTH_DATA_1/2
    • reads IDENTITY_DATA_1/2
    • zeros walker_info_t.unk1, unk3, flags:[0..1]
    • writes to IDENTITY_DATA_1/2
    • zeros 0x64 bytes of eeprom at 0xcf0c (obtained items/pokemon/peer items)
    • 'zeros' 24 elements, each size 0x88 bytes, in eeprom starting at 0xcf0c (see eventLogInvalidate:0x188c)
    • zeros 0x6c8 bytes of eeprom at 0xb800 (event data)
    • zeros 0x1568 bytes of eeprom at 0xde24 (met peer data)
    • zeros 0x10 bytes of eeprom at 0x8f00 (current pokemon summary)

DS checks

In order for the DS to accept the walk end, the eeprom needs to contain:

  • valid walker_info_t (IdentityData)
    • protocol_ver = 2, protocol_subver=0
    • le_unk1=1, le_unk3=7
    • correct unique_identity_data_t
  • The correct species in route_info_t.pomeon_summary.le_species

Walker Initialisation

Checks on startup

  • Checks for nintendo string
    • if not found:
      • run eeprom_init(true, true)
      • write nintendo string to eeprom
      • check for unfinished copy
    • if found:
      • Reads health_data_t from eeprom.
      • Reads walker_info_t from eeprom
      • sets global init and has_pokemon flags based on walker_info_t.flags[0..1]
      • check for unfinished copy
  • go to sleep mode (??)
  • (In sleep mode now)
  • process splash normally
  • if we aren't inited, go to connect loop

Resetting via IR

Relevant commands are:

CMDDescription
0xe0Clear events and lifetime data
0x2aClear events only
0x2cDon't clear events or lifetime data

"clear events" means:

  • zero walker_info_t.event_bitmap
  • zero eeprom received_bitfield -> text_event_item_name

"clear lifetime data" means:

  • Zero walker_info_t.be_step_count
  • Zero health_data_t.total_steps
  • Zero health_data_t.total_days
  • health_data_t.last_sync = date 2nd Jan 2008
  • Zero health_data-t.today_steps
  • Zero eeprom caught_pokemon_summary-0x08 -> current_peer_team_data-0x34

All commands call eeprom_init with their respective flags set.

The one that's actually used by the game is 0x2a - only clear event data.

Function eeprom_init

  • Zero current_steps
  • Zero current_watts
  • Clear status_flags bits 1 and 2 (walker_inited, walker_has_pokemon)
  • Reliable read walker_info_t
    • Zero unk0, unk1, unk2, unk3
    • Zero tid/sid
    • Zero trainer name
    • If clear_events zero event_bitmap_t
    • Zero flags
    • Zero unk4[2]
    • Zero protocol_subver
    • unk8 = 2
    • Reliable read unique_identity_data_t into walker_t.unique_identity_data
    • if clear_steps zero be_step_count
    • Reliable write walker_info_t
  • Clear and write health_data_t
    • if clear_lifetime_data
      • Zero total_steps
      • Zero total_days
      • last_sync = 220924800 2nd Jan 2008
      • Zero today_steps
    • Zero walk_minute_counter
    • Zero current_watts
    • Zero steps_this_watt
    • settings = 0x24
    • Reliable write health_data_t
  • If clear_steps zero eeprom 0xce80 - 0xdbcc (caught_pokemon_summary-8 -> current_peer_team_data-0x34)
  • Else only zero inventory, event_log, step_log (note: this only skips clearing the staging area (?))
  • If clear_events zero eeprom 0xb800 - 0xbec8 (received_bitfield -> text_event_item_name)
  • Zero met peer data

Function check_and_validate_eeprom

  • Check for "nintendo" string at first 8 bytes of eeprom.
    • if not found:
      • run eeprom_init(true, true)
      • reset sound and contrast from ram health_data
      • write "nintendo" to start of eeprom
    • if found:
      • check settings byte and apply a minimum contrast?
      • update status flags from eeprom
  • Check for unfinished copy by reliable reading both copy markers
    • if not ok, continue the copy

Peer Play

IR Sequence

Taken from dmitry's writeup.

  • Normal keyex
  • Master sends command 0x10 containing its identity_data_t
  • Slave checks version compatability and if already played
    • What if these checks fail?
  • Slave replies with command 0x12 containing its identity_data_t
  • Master checks version compatability and if already played
    • What if these checks fail? These should pass if slave replies?
  • Master sends small animated sprite to slave's 0xf400
  • Master sends team data to slave's 0xdc00
  • Master reads slave's small animated sprite and writes to 0xf400
  • Master reads slave's team data and writes to 0xdc00
  • Master sends command 0x14 with peer_play_data_t
  • Slave writes this to 0xf6c0
  • Slave replies with command 0x14 and its own peer_play_data_t
  • Master writes this to 0xf6c0
  • Master sends command 0x16
  • Slave replies with command 0x16
  • Both play animation
  • Both calculate gift as seed = max(20000, 10*((remote.watts + self.watts) + (remote.steps + self.steps))
  • Checks if there's space in peer play gifts
    • If fails, gift watts = max(99, seed/200)
    • If passes, gift item = TBD

Animation

  • Self sits on middle right side, other walks in over 8 fast frames to middle-left, both animated
  • show message "{other} has arrived" for 8 fast frames (2-high), both animated
  • Show message "played a bit" with music note static in top middle, 8 fast frames, 2 high, both animated
  • Draw large present in middle, 8 px from top, show message "here's a gift", 4 fast frames, 1 high
  • Draw large message "{gift} received!", 4 fast frames, 2 high
  • Send to splash

Event logs

Notes

  • dmitry's struct is 0x5e bytes, missing route_name

walker function sig

r0 = TeamAndrouteInfo in ram ptr (0xBE bytes from 0x8f00) e0 = tmpBufPtr (0x88 bytes big) can be pre-initialized with data r1l = eventTYpe r1h = boolean isOnSpecialEventRoute e1 = extraInfo (eg: item type) [sp] = u8 pushed as u16, availablePokeIdx(1..3 are route availables, 4 is event poke, 0 for N/A)

notes on the decomp of logEvent

  • we have a log set up to write (apparently)
  • reads written event
  • if 0x1b, drop this log
  • if 0x19, increment index idx = (idx+1)%23
  • if our event is <0x0a, skip the zero part (this will be peer play events)
  • zero 0x88 bytes of our log buf
  • (buf+0x84) = our event type (u8)
  • (buf+0x0e) = extra data (u16)
  • (buf+0x00) = current time (u32, be)
  • (buf+0x78) = current watts (u16, be)
  • (buf+0x7c) = current steps (u32, be)
  • (buf+0x0a) = (route_info) (current species) (u16)
  • (buf+0x20) = (route_info+0x10) (current nickname) 22 bytes
  • (buf+0x77) = (route_info+0x26) pokemon happiness u8
  • (buf+0x85) = (pokemon_flags_1&0x1f) | (buf+0x85)&0xe0, u8
  • (buf+0x85):7 = are we on special route, u8
  • on normal route: (buf+0x76) = route_image_index u8
  • on normal route: (buf+0x4c) = route_name 0x2a bytes (21*u16)
  • on special route: (buf+0x76) = special route_image_index (eeprom:0xbf06) (u8)
  • on special route: (buf+0x4c) = special route_name 0x2a bytes (eeprom:0xbf50)
  • check if we have 1-3:normal_pokemon, 4:special_pokemon, else:no_pokemon (idk)
    • probably for caught pokemon
  • if we were normal pokemeon: (buf+0x0c) = caught species
  • normal pokemon: (buf+0x86) = caught gender/form &0x1f | (buf+0x86)&0xe0 + funky bitfield insert
  • event pokemon:
    • if log type is 0x0f or 0x10: (buf+0x0c) = (eeprom:bf08) event caught species (u16)
    • else: (buf+0x0c) = (eeprom:ba44) gifted pokemon species (u16)
  • event pokemon: (buf+0x86) = 1f&(eeprom:bf0d) (should be bf15) special pokemon flags (u8)
    • also orred with (buf+0x86)&0xe0 + funky bitfield insert
  • all routes: (no pokemon jumps straight here)
  • write 0x88 bytes to eeprom at 0xcf0c+0x88*idx
  • increment global index idx = (idx+1)%23
  • write total steps to reliable area

notes on decomp of logPeerPlay

  • Also grabs 0x88 bytes for log item
  • (buf+0x04) = peer_play+0x08 u32
  • (buf+0x08) = peer_play+0x0c u16
  • (buf+0x0c) = peer_play+0x0e u16
  • (buf+0x86) = peer_play+0x36 u8 + bitfield inserts again | peer_play:7
  • (buf+0x7a) = peer_play+0x04 (peer watts) u16
  • (buf+0x80) = peer_play+0x00 (peer steps) u32
  • (buf+0x36) = peer_play.nickname 22 bytes (walker copies 24)
  • (buf+0x10) = peer_play.trainer_name 16 bytes (walker copies 18)
  • pushes (2*number_of_peers_met)&0xff00 u16 to the stack??
  • event type is number of peers met so far
  • extra data = route_info.items[n_peers_met] u16:w

Radar Bush Game

Walker behaviour

  • Choose mon
    • check for event
      • check if we already have mon
        • check steps
        • check percent
        • exclamation level = 3+rand()%2
    • check option a > b > c
    • check steps
    • check percent (same rand() val)
    • exclamation level = 3-idx+rand()%2
    • always have at least option c
  • mark active timer = 5 ticks
  • timeout timer = 0x40
  • active bush = rand()%4
  • substate user choose bush
    • dec mark timer
    • if mark timer up, dec timeout timer
    • on enter, if cursur is on active bush, move to substate handle ok bush
    • else move to failed global state
    • set message timeout to 10 ticks
  • substate radar handle ok bush
    • dec message timeout
    • if exclamation level == chosen level
      • set show message
      • reset bar animation frame
      • switch to battle start state
    • mark active timer = 16+rand()/stuff
    • inc exclamation level
    • active bush = rand()%4
    • switch to choosing state
  • substate user failure (I don't know if this ever gets called, on failure we go to separate global state)
    • show received message (??)
    • wait for input
    • send to splash
  • substate battle start
    • 4 ticks to black out screen
    • send to battle state

PokeRadar

Choosing pokemon

  • Checks for event pokemon first
    • if rand() < chance, choose event mon
    • else choose route 3 mon
  • get new rand()
  • Check for normal pokemon
    • start at option A (rarest)
    • check for steps
    • check if same rand() < chance
    • if both pass, choose that option mon
    • else continue
  • substate_y = index+1 (probably found pokemon id)
  • substate_b = randomly add 1 to index+1
    • This means that even if it chose eg 0, there's a 50% chance it'll actually be 1 instead
    • Same applies for event mon? Skips event check?

Wild Pokemon Join

Notes

Walker stuff

In pokeJoinEmptyWalkerWalk

  • set global status has_walking_poke [2]
  • read reliable identity data
  • if walker_info_t.flags.1 (have pokemon) then break
  • set walker_info_t.flags.1
  • set walker_info_t.unk0 and walker_info_t.unk2
  • set walker_info_t.flags.2 (pokemon joined walk)
  • write back to reliable area
  • read small image for pokemon option c
  • write to current small pokemon sprite
  • read large image for pokemon option c
  • write to current large pokemon sprite
  • read pokemon option c name
  • write to current pokemon name
  • read route_info_t
  • copy route_info_t.route_pokemon[2] to route_info_t.current_pokemon
  • clear pokemon_summary_t.flags[7]
  • write 0x46 to route_info_t.current_pokemon.happiness
  • zero 0x16 bytes of route_info_t.pokemon_nickname
  • write route_info_t
  • reliable write global health data
  • clear event logs (write zero in each entry type)

In addRandomGift

  • (skipped some stuff)
  • standard log event, with event_type=(0x10+ addRandomGift param)
    • should be event type 0x17

Battle

General notes

  • Frames are twice as fast.
  • Does not show message during animation
  • Updates health at the end of each animation
  • Opponents sprite is flipped

Catching

  • "threw a poke ball" and ball anim
  • cloud "anim" (shows cloud for 2 frames)
  • wobble anim n times
  • outcome
    • on lose
      • cloud "anim"
      • show mon "almost had it"
      • fled
    • on win
      • stars anim ~5 frames
      • "was caught"

Animations

  • wobble has x=20 +/- 1, y=12, 4 frames each
  • throw has 6 frames
  • always wobbles once (? pretty sure)
  • can wobble 3 times and break out

RNG stuff

Seems like there's a percent chance each wobble based on its HP for it to break out. If it reaches 3 wobbles without breaking out, it's caught.

Audio

Random gift

Overview of the process

In sleep mode (and only in sleep mode), calls choose_random_event if device is awake. choose_random_event does this exact check again before doing anything. If we're in the splash state and walker_status_flags bit 0 is set then we can have a gift.

There's a 40% chance for an event to happen each time. If an event is chosen, first check if we have a pokemon. If we don't have a pokemon and current watts are more than 300, then set substate_y=EVENT_TYPE_JOIN_WALK. If we do have a pokemon then move on to gifts.

There's something about waiting an hour, not sure about this. First read route_info from eeprom and find if we have an item slot free.

  • If we have a free slow, pokemon happiness > 90 and we have >=500 watts then set substate_y=EVENT_TYPE_ITEM.
  • Else if pokemon happiness > 80 and we have >=250 watts then set susbtate_y=EVENT_TYPE_50_WATTS.
  • Else if we have >=200 watts then set substate_y=EVENT_TYPE_20_WATTS.
  • Else if we have >=100 watts then set substate_y=EVENT_TYPE_10_WATTS.
  • Else if we have >=50 watts and health_data.walk_minute_counter>=60 then substate_y=EVENT_TYPE_NO_GIFT.
  • Else no event

Next in the spash state in normal event mode (and for one(?) cycle of sleep mode), check if substate_z is nonzero. If it is, it means we have a random event, so we run handle_random_splash_event on button press. This uses event_type parameter to index into a pointer table random_event_table and sets substate_b. substate_b now points to an array of data/instructions corresponding to the event type chosen. The data/instructions just outline whether or not to draw a pokemon sprite, item sprite, which message to display, what to say we found, which emote/face to display, which sound to play and whether we should go back to the splash screen. Each "step" is 4 bytes and substate_b moves along 4 bytes at a time until dialogue is over.

Next handle_random_splash_event sets the current substate to 0x0c random_gift_state. It zeroes the seconds_counter and then proceeds to perform the action the event_type describes.

  • If event is for an item, item index is calculated by max(0,9-watts/500), where 0 is rarest item. Then finds a free slot and adds the item. if there are no free slots then don't add an item.
  • If event is for watts, call add_watts function with the right number of watts and writes it to substate_z.
  • Otherwise, zero substate_z Next write a log event for the random event. Log event index is 0x10+EVENT_TYPE, extra info is item_id (nothing for watts).

If the event type was either for watts or no gift, then set substate_a = (rand()>>3)%3, else zero it. This is to display a "random" mood message on the screen.

Now in random_gift_state event loop, on button press check if bit 0 of the data pointed to by substate_b is set. If it is, go to splash screen, else play sound id stored in substate_b[1] and move substate_b to point to next set of 4 bytes.

Finally, draw the state depending on what flags are set in the substate_b data array. Use draw_large_message with an index of substate_b[3] (+substate_a if told) to display the "found" and "is happy" messages etc.

Eventually, go back to splash screen once dialogue is done.


Analysis of 0x5d52 handle_random_splash_event

handle_random_splash_event takes parameter event_type in r0l. interaction_handler_splash zeroes substate_z, keeps substate_y as event_type and passes event_type into function.

  • Sets substate_b to random_event_table[event_type*2] - related to drawing?
  • Sets current state to 0x0c (random gift)
  • Sets seconds_counter to 0
enum event_type {
    // type 0 doesn't exist
    EVENT_TYPE_ITEM = 1,
    EVENT_TYPE_50_WATTS = 2,
    EVENT_TYPE_20_WATTS = 3,
    EVENT_TYPE_10_WATTS = 4,
    EVENT_TYPE_NO_GIFT = 5, // smiled/is happy etc
    // type 6 doesn't exist
    EVENT_TYPE_JOIN_WALK = 7,
};

If event type adds watts, just call 0x1f3e add_watts().

If event type was join walk, call 0x5c0a pokemon_join_walk()

If event type was add item then:

  • item_index = 9 - floor(current_watts / 500)
  • item_id = route_item_ids[item_index]
  • if we have slots free add item to slot
  • if we don't have slots free, don't bother

common to all event types:

  • alloc and read route info from eeprom
  • check if we're on a special map
  • malloc enough for log struct
  • log event
    • log type is (16 + event_type)
    • say if we're on a special route
  • if event type was add watts, g_substate_a = rand()>>3 % 3
    • this leads to a "random" message displayed on screen
  • else g_substate_a = 0

Analysis of 0x5c0a pokemon_join_walk()

  • clear current watts
  • set have_pokemon flag (bit 2) in walker_status_flags ram cache
  • malloc and read in walker_info from eeprom
  • set flags in walker_info
    • set walker inited if it wasn't already
    • copy unk0 to unk1
    • copy unk2 to unk3
    • set have pokemon in flags
  • reliable write walker info
  • reset and malloc 0x180 bytes for images
  • copy option c small sprite to current pokemon small sprite
  • copy option c large sprite to current pokemon large sprite
  • copy option c pokemon name to current pokemon name
  • reset, malloc and read route info
  • copy option c pokemon summary to route info
  • set bit 7 in pokemon flags (idk what this bit does)
  • set pokemon happiness to 70
  • copy pokemon nickname to route info
  • write route info again
  • reliable write ram health data to eeprom
  • clear event log

Analysis of 0x5fc2 choose_random_event

checks walker flags, if set on startup and not poke joined then do the following:

  • if we aren't in splash state, go to default
  • if walker flags bit zero is not set, go to default
  • clear walker flags bit 0
  • clear substate y, z
  • put current watts on stack
  • 40% rand check, if failed go to default
  • check walker flags, if we dont have pokemon:
    • if watts > 300 go to default
    • if not, move 7 to substate y (probably EVENT_TYPE_JOIN_WALK)
    • move 0x30 into substate z
    • exit
  • check walker flags, if we do have pokemon
    • if seconds counter > 3600, go to default
    • reset heap, malloc and read route_info
    • put happiness inro r5l
    • reset heap, malloc and read 12 bytes for obtained items
    • if we have free slot, happiness > 90 and watts > 500, substate_y = EVENT_TYPE_ITEM
    • else if no free slot, happiness > 80 and watts > 250, substate_y = EVENT_TYPE_50_WATTS
    • else if watts > 200 EVENT_TYPE_20_WATTS
    • else if watts > 100 EVENT_TYPE_10_WATTS
    • else if watts > 50 and ran_health_data.walk_minute_counter > 60 EVENT_TYPE_5
    • else exit (with y=z=0)
    • y is event type, set z to 0x30, then exit

Analysis of 0x5edc draw_random_gift_state

  • substate_b seems to be a pointer to an array/struct of data, outlined below. 12-bytes wide
  • substate_z seems to be what was found, depending on the flags in substate_b
  • substate_a gets added to substate_b[3] to make a "random" large message index
struct random_event_data {
    uint8_t  flags;         // [0]=go to splash, [1]=draw pokemon, [2]=draw item, [3:4]=apply range(?), [5:7]=face index
    uint8_t  sound_id;
    uint8_t  draw_id;       // fc=draw pokemon name, fd = draw item name, fe = draw watts, ff = do nothing, anything else = use as message index and draw it (never used)
    uint8_t  message_id;    // index into large message id table (see eeprom 0x2530)
}
  • reset heap pointer and malloc 0xc0 bytes
  • load substate_b[0] bit 1
    • if bit 1 is set, draw pokemon small animated at (32, 4)
  • converge, grab substate_b[0], treat top 3 bits like a u3 idx (face index)
    • if idx != 7 then call draw_talk_faces(idx)
  • converge, grab substate_b[0] and load bit 2
    • if set, then call draw_item_symbol(x=20, y=20)
  • converge, grab substate_b[2]
    • if val == 0xfc then draw pokemon name
    • if val == 0xfd then draw substate_z as item name index
    • if val == 0xfe then draw substate_z as watts
    • if val != 0xff then draw large message substate_z is index
  • get first byte of substate_b array
  • if val&0x18 <= 8 (ie bit 4 == 0) then
    • if substate_b[2] == 0xff then move substate_b[3] into r0h and draw large message with full border, blinking cursor
    • else move substate_b[3] into r0h and draw large message with partial border, blinking cursor
  • else move substate_b[3] + substate_a into r0h and draw large message with partial border, blinking cursor

Analysis of 0x5e9e random_gift_state()

Essentially steps through the 12-byte array on each button press. Does this 4 bytes at a time, so there's max 3 message states.

  • check if enter key pressed, if not then exit
  • load substate_b[0] bit 0
  • if set then call some_statevar_shuffling (sets y=z=0, sets a) then send to splash
  • else substate_b += 4 (moves 4 bytes across the 12-byte array), then grab substate_b[1]
    • if val != 0x10 then call play_sound(substate_b[1])

Decoding the event table

  • item event
    • draw pokemon, face_idx=0, [4:3] = 0b01, sound id 0x10, draw name, message id 0x32 "cheered!"
    • draw pokemon, face idx=7, [4:3] = 0b01, sound id 0x10, message id 0x3f "found something"
    • draw pokemon, draw item, go to splash, face idx=7, [4:3] = 0b01, sound id 5, draw item, message id 0x18 "found!"
  • 50 watts event
    • draw pokemon, face idx=1, [4:3] = 0b11, sound id 0x10, draw name, message id 0x33 "is very happy!" (+substate_a)
    • draw pokemon, face idx=7, [4:3] = 0b01, sound id 0x10, message id 0x3f "found something"
    • draw pokemon, go to splash, face idx=7, [4:3] = 0b01, sound id 5, draw watts, message id 0x18 "found!"
  • joined event
    • face idx 7, [4:3] = 0b01, sound id 0x10, message id 0x40 "what?"
    • go to splash, face idx 6, [4:3] = 0b01, sound id 7, draw name, message id 0x41 "joined!"
  • nothing event
    • go to splash, face idx 4, draw pokemon, [4:3]=0b11, sound id 0x10, draw name, message id 0x39 "is looking around" (+substate_a)

Structures

Walker

/*
 *  size: 0x68 = 104 bytes
 *  Dmitry: struct IdentityData
 */
typedef struct {
    /* +0x00 */ uint32_t le_unk0;
    /* +0x04 */ uint32_t le_unk1;
    /* +0x08 */ uint16_t le_unk2;
    /* +0x0a */ uint16_t le_unk3;
    /* +0x0c */ uint16_t le_tid;
    /* +0x0e */ uint16_t le_sid;
    /* +0x10 */ unique_identity_data_t identity_data;
    /* +0x38 */ event_bitmap_t event_bitmap;
    /* +0x48 */ uint16_t le_trainer_name[8];
    /* +0x58 */ uint8_t unk4[2];
    /* +0x5a */ uint8_t event_index;
    /* +0x5b */ uint8_t flags;              // [0]=init, [1]=has_pokemon, [2]=pokemon_joined, [3..7]=end_of_day_hour
    /* +0x5c */ uint8_t protocol_ver;
    /* +0x5d */ uint8_t unk5;
    /* +0x5e */ uint8_t protocol_subver;
    /* +0x5f */ uint8_t unk8;
    /* +0x60 */ uint32_t be_last_sync;
    /* +0x64 */ uint32_t be_step_count;
} walker_info_t;

/*
 *  size: 0x18 = 24 bytes
 *  dmitry: struct HealthData
 */
typedef struct {    // strut HealthData
    /* +0x00 */ uint32_t be_total_steps;
    /* +0x04 */ uint32_t be_today_steps;
    /* +0x08 */ uint32_t be_last_sync;  // seconds since 1 Jan 2001
    /* +0x0c */ uint16_t be_total_days;
    /* +0x0e */ uint16_t be_current_watts;
    /* +0x10 */ uint16_t le_walk_minute_counter;    // only used internally
    /* +0x12 */ uint8_t  steps_this_watt;           // only used internally
    /* +0x13 */ uint8_t  event_log_write_idx;       // only used internally
    /* +0x14 */ uint8_t  padding[3];
    /* +0x17 */ uint8_t  settings; // [0]=special_map, [1..2]=volume, [3..6]=contrast
} health_data_t;

/*
 *  size: 64 bytes
 *  dmitry: struct LcdConfigCmds
 */
typedef struct {
    uint8_t flags;
    uint8_t commands[0x3f];
} lcd_config_t;

/*
 *  size: 256 bytes
 *  dmitry: RELIABLE_DATA
 *
 *  Warning: gcc will add padding by default
 *  since members aren't aligned
 */
typedef struct {
    /* +0x00 */ uint8_t factory_data[2];
    /* +0x02 */ uint8_t factory_data_checksum;
    /* +0x03 */ unique_identity_data_t unique_data;
    /* +0x2b */ uint8_t unique_data_checksum;
    /* +0x2c */ lcd_config_t lcd_config;
    /* +0x6c */ uint8_t lcd_config_checksum;
    /* +0x6d */ walker_info_t walker_info;
    /* +0xd5 */ uint8_t walker_info_checksum;
    /* +0xd6 */ health_data_t health_data;
    /* +0xee */ uint8_t health_data_checksum;
    /* +0xef */ uint8_t copy_marker;
    /* +0xf0 */ uint8_t padding[16];
} reliable_data_t;

/*
 *  size: 1 byte
 *
 */
typedef struct {
    uint8_t stamp_heart: 1;
    uint8_t stamp_space: 1;
    uint8_t stamp_diamond: 1;
    uint8_t stamp_club: 1;
    uint8_t special_map: 1;
    uint8_t event_pokemon: 1;
    uint8_t evet_item: 1;
    uint8_t special_route: 1;
} special_inventory_t;

Notes:

  • Walker refuses walk end when walker_info_t.le_unk{1,3} are not {1,7} respectively, stating "not the correct pokewalker"

Pokemon

/*
 *  size: 0x38 = 56 bytes
 *  dmitry: struct PeerPlayData
 */
typedef struct {    // Dmitry struct PeerPlayData
    /* +0x00 */ uint32_t le_current_steps;
    /* +0x04 */ uint16_t le_current_watts;
    /* +0x06 */ uint8_t padding[2];
    /* +0x08 */ uint32_t le_unk0;
    /* +0x0c */ uint16_t le_unk2;
    /* +0x0e */ uint16_t le_species;
    /* +0x10 */ uint16_t pokemon_name[11];
    /* +0x26 */ uint16_t trainer_name[8];
    /* +0x36 */ uint8_t pokemon_flags_1;
    /* +0x37 */ uint8_t pokemon_flags_2;
} peer_play_data_t;

/*
 *  size: 16 bytes
 *  dmitry: struct PokemonSummary
 */
typedef struct {
    /* +0x00 */ uint16_t le_species;
    /* +0x02 */ uint16_t le_held_item;
    /* +0x04 */ uint16_t le_moves[4];
    /* +0x0c */ uint8_t level;
    /* +0x0d */ uint8_t pokemon_flags_1;    // [0..5] = variant (spinda, arceus, unown, etc.) [6] = female
    /* +0x0e */ uint8_t pokemon_flags_2;    // [0] = has form, [1] = shiny
    /* +0x0f */ uint8_t padding;
} pokemon_summary_t;

/*
 *  size: 0x38 = 56 bytes
 *  dmitry: struct TeamPokeData
 */
typedef struct {
    /* +0x00 */ uint16_t le_species;
    /* +0x02 */ uint16_t le_held_item;
    /* +0x04 */ uint16_t le_moves[4];
    /* +0x0c */ uint16_t le_ot_tid;
    /* +0x0e */ uint16_t le_ot_sid;
    /* +0x10 */ uint32_t le_pid;
    /* +0x14 */ uint32_t ivs;   // packed to 5-bits each
    /* +0x18 */ uint8_t evs[6];
    /* +0x1e */ uint8_t pokemon_flags_1;
    /* +0x1f */ uint8_t source_game;
    /* +0x20 */ uint8_t ability;
    /* +0x21 */ uint8_t happiness;
    /* +0x22 */ uint8_t level;
    /* +0x23 */ uint8_t padding;
    /* +0x24 */ uint16_t nickname[10];
} pokemon_info_t;

/*
 *  size: 0x2c = 44 bytes
 *  dmitry: struct EventPokeExtraData
 */
typedef struct {
    /* +0x00 */ uint32_t le_unk0;
    /* +0x04 */ uint16_t le_ot_tid;
    /* +0x06 */ uint16_t le_ot_sid;
    /* +0x08 */ uint16_t le_unk1;
    /* +0x0a */ uint16_t le_location_met;
    /* +0x0c */ uint16_t le_unk2;
    /* +0x0e */ uint16_t ot_name[8];
    /* +0x1e */ uint8_t encounter_type;
    /* +0x1f */ uint8_t ability;
    /* +0x20 */ uint16_t le_pokeball_item;
    /* +0x22 */ uint8_t unk3[10];
} special_pokemon_info_t;

Note: special_pokemon_info_t cannot contain PID because ability, gender, shininess, spinda spots all depend on PID. So PID must be generated/inferred from the data given. Unsure if it's random each time, or if the same gifted pokemon gives the same PID. The le_unk1 and le_unk2 change PV somehow, since I can see nature and characteristics changes. Nothing seems to grant ribbons, marks or pokerus.

Routes

typedef enum {
    /* 0x00 */ ROUTE_IMAGE_FIELD_AND_TREES,
    /* 0x01 */ ROUTE_IMAGE_FOREST_AND_TREES,
    /* 0x02 */ ROUTE_IMAGE_SUBURBS,
    /* 0x03 */ ROUTE_IMAGE_URBAN,
    /* 0x04 */ ROUTE_IMAGE_MOUNTAIN,
    /* 0x05 */ ROUTE_IMAGE_CAVE,
    /* 0x06 */ ROUTE_IMAGE_LAKE,
    /* 0x07 */ ROUTE_IMAGE_BEACH,
} route_image_index_t;

/*
 *  size: 0xbe = 190 bytes
 *  dmitry: struct RouteInfo
 */
typedef struct {
    /* +0x00 */ pokemon_summary_t pokemon_summary;
    /* +0x10 */ uint16_t pokemon_nickname[11];
    /* +0x26 */ uint8_t pokemon_happiness;
    /* +0x27 */ uint8_t route_image_index;
    /* +0x28 */ uint16_t route_name[21];
    /* +0x52 */ pokemon_summary_t route_pokemon[3];
    /* +0x82 */ uint16_t le_route_pokemon_steps[3];
    /* +0x88 */ uint8_t route_pokemon_percent[3];
    /* +0x8b */ uint8_t padding;
    /* +0x8c */ uint16_t le_route_items[10];
    /* +0xa0 */ uint16_t le_route_item_steps[10];
    /* +0xb4 */ uint8_t route_item_percent[10];
} route_info_t;

/*
 *  size: 0x6ac = 1708 bytes
 *  dmitry: struct SpecialRoute
 */
typedef struct {
    /* +0x0000 */ uint8_t item_info[6];
    /* +0x0006 */ uint8_t route_image_index;
    /* +0x0007 */ uint8_t padding_1;
    /* +0x0008 */ pokemon_summary_t special_pokemon;
    /* +0x0018 */ special_pokemon_info_t special_pokemon_extra;
    /* +0x0044 */ uint16_t le_special_pokemon_steps;
    /* +0x0046 */ uint8_t special_pokemon_percent;
    /* +0x0047 */ uint8_t padding_2;
    /* +0x0048 */ uint16_t le_special_item;
    /* +0x004a */ uint16_t le_special_item_steps;
    /* +0x004c */ uint8_t special_item_percent;
    /* +0x004d */ uint8_t padding_3[3];
    /* +0x0050 */ uint16_t route_name[21];
    /* +0x007a */ uint8_t pokemon_event_number;
    /* +0x007b */ uint8_t item_event_number;
    /* +0x007c */ uint8_t special_pokemon_sprite_data[0x170]; // should be 0x180 bytes, truncated
    /* +0x01ec */ uint8_t special_pokemon_name_image[0x140];
    /* +0x032c */ uint8_t special_area_icon[0xc0];
    /* +0x03ec */ uint8_t special_area_name_image[0x140];
    /* +0x052c */ uint8_t special_item_name_image[0x180];
} special_route_info_t;

Logs

/*
 *  size: 0x88 = 136 bytes
 *  dmitry: struct EventLogItem
 *  Modified from dmitry's version
 */
typedef struct {
    /* 0x00 */ uint32_t be_time;
    /* 0x04 */ uint32_t le_unk0;
    /* 0x08 */ uint16_t le_unk2;
    /* 0x0a */ uint16_t le_our_species;
    /* 0x0c */ uint16_t le_other_species;
    /* 0x0e */ uint16_t le_extra;
    /* 0x10 */ uint16_t other_trainer_name[8];
    /* 0x20 */ uint16_t our_pokemon_name[11];
    /* 0x36 */ uint16_t other_pokemon_name[11];
    /* 0x4c */ uint16_t route_name[21];
    /* 0x76 */ uint8_t  route_image_index;
    /* 0x77 */ uint8_t  pokemon_friendship;
    /* 0x78 */ uint16_t be_our_watts;
    /* 0x7a */ uint16_t be_other_watts;
    /* 0x7c */ uint32_t be_steps;
    /* 0x80 */ uint32_t be_other_steps;
    /* 0x84 */ uint8_t  event_type;
    /* 0x85 */ uint8_t  our_pokemon_flags;
    /* 0x86 */ uint8_t  other_pokemon_flags;
    /* 0x87 */ uint8_t  padding;
} event_log_item_t;


typedef enum {
    /* 0x00 */ EVENT_TYPE_EMPTY_ENTRY,
    /* 0x01 */ EVENT_TYPE_PEER_PLAY_1,
    /* 0x02 */ EVENT_TYPE_PEER_PLAY_2,
    /* 0x03 */ EVENT_TYPE_PEER_PLAY_3,
    /* 0x04 */ EVENT_TYPE_PEER_PLAY_4,
    /* 0x05 */ EVENT_TYPE_PEER_PLAY_5,
    /* 0x06 */ EVENT_TYPE_PEER_PLAY_6,
    /* 0x07 */ EVENT_TYPE_PEER_PLAY_7,
    /* 0x08 */ EVENT_TYPE_PEER_PLAY_8,
    /* 0x09 */ EVENT_TYPE_PEER_PLAY_9,
    /* 0x0a */ EVENT_TYPE_PEER_PLAY_10,
    /* 0x0b */ EVENT_TYPE_ITEM_DOWSED,
    /* 0x0c */ EVENT_TYPE_SPECIAL_ITEM_DOWSED,
    /* 0x0d */ EVENT_TYPE_POKEMON_CAUGHT,
    /* 0x0e */ EVENT_TYPE_SPECIAL_POKEMON_CAUGHT,
    /* 0x0f */ EVENT_TYPE_POKEMON_RAN,
    /* 0x10 */ EVENT_TYPE_POKEMON_LOST,
    /* 0x11 */ EVENT_TYPE_POKEMON_FOUND_ITEM,
    /* 0x12 */ EVENT_TYPE_MOOD_HAPPY,
    /* 0x13 */ EVENT_TYPE_MOOD_RUNNING,
    /* 0x14 */ EVENT_TYPE_MOOD_LOOKING_AWAY,
    /* 0x15 */ EVENT_TYPE_MOOD_BORED,
    /* 0x16 */ EVENT_TYPE_MOOD_GO_HOME,
    /* 0x17 */ EVENT_TYPE_POKEMON_JOINED,
    /* 0x18 */ EVENT_TYPE_WALK_ENDED,
    /* 0x19 */ EVENT_TYPE_WALK_STARTED,
    /* 0x1a */ EVENT_TYPE_PLAYED_ALOT,
    /* 0x1b */ EVENT_TYPE_FELL_ASLEEP,
    /* 0x1c */ EVENT_TYPE_ITEM_GIFTED,
} event_log_type_t;

IR


/*
 *  size: 0x88 = 136 bytes
 */
typedef struct {
    /* +0x00 */ uint8_t  cmd;
    /* +0x01 */ uint8_t  extra;
    /* +0x02 */ uint16_t le_checksum;
    /* +0x04 */ uint32_t le_session_id;
    /* +0x08 */ uint8_t  payload[128];
} pw_packet_t;

Audio


/*
 *  size: 0x02 = 2 bytes
 */
typedef struct {
    /* +0x00 */ uint8_t info;       // ? used in calculating note duration
    /* +0x01 */ uint8_t period_idx; // [7] = negative duration?, [6:0] = index into period table
} pw_sound_frame_t;

/*
 *  size: 0x03 = 3 bytes
 */
typedef struct {
    /* 0x00 */ uint16_t offset; // byte offset into SOUND_DATA for start of sound
    /* 0x02 */ uint8_t  length; // number of bytes this sound effect uses
    /* 0x03 */ uint8_t  pad;
} pw_sound_info_t;

enum sound_type {
    SOUND_NAVIGATE_MENU = 0,
    SOUND_NAVIGATE_BACK = 1,
    SOUND_CURSOR_MOVE = 2,
    SOUND_POKERADAR_FOUND_SOMETHING = 3,
    SOUND_SELECTION_MISS = 4,
    SOUND_DOWSING_FOUND_ITEM = 5,
    SOUND_POKEMON_CAUGHT = 7,
    SOUND_POKEMON_ENCOUNTER = 10,
    SOUND_MINIGAME_FAIL = 14,
    SOUND_POKEBALL_THROW = 15,
}

Notes:

  • What does pw_sound_frame_t store exactly? what's info and why does period_idx seem to be used to calculate a negative(?) duration?
  • It would be interesting to see what the missing sounds are. m8 has a wav file, maybe they're mystery gift/ir stuff.

EEPROM Map

This map has been taken from Dmitry's article and has been modified/corrected as more information has been found. For things that have been changed since dmitry's article, see the changed column.

nameaddrsizecommentschanged?
NINTENDO0x00008"nintendo" string as a magic marker. if rom does not find this at boot, it will consider the walker empty and uninitialized
PERSONALISATION0x00088some value written during personalization. never read.
0x001098???
WATCHDOG_RESETS0x00721number of watchdog resets
0x007313???
FACTORY_DATA_10x00802factory-provided adc calibration data. (reliable data format, copy at 0x0180)Y
UNIQUE_IDENTITY_DATA_10x008340struct uniqueidentitydata. provisioned at game pairing time (reliable data format, copy at 0x0183)Y
LCD_COMMANDS_10x00ac64struct lcdconfigcmds. provisioned at game pairing time (reliable data format, copy at 0x01ac)Y
IDENTITY_DATA_10x00ed104struct identitydata. provisioned at walk start time (reliable data format, copy at 0x01ed)Y
HEALTH_DATA_10x015624struct healthdata. provisioned at walk start time (reliable data format, copy at 0x0256)Y
COPY_MARKER_10x016f1struct copymarker. used at walk init time (reliable data format, copy at 0x26f)Y
0x017016unusedY
FACTORY_DATA_20x01802factory-provided adc calibration data. (reliable data format, copy at 0x0080)Y
UNIQUE_IDENTITY_DATA_20x018340struct uniqueidentitydata. provisioned at game pairing time (reliable data format, copy at 0x0083)Y
LCD_COMMANDS_20x01ac64struct lcdconfigcmds. provisioned at game pairing time (reliable data format, copy at 0x00ac)Y
IDENTITY_DATA_20x01ed104struct identitydata. provisioned at walk start time (reliable data format, copy at 0x00ed)Y
HEALTH_DATA_20x025624struct healthdata. provisioned at walk start time (reliable data format, copy at 0x0156)Y
COPY_MARKER_20x026f1struct copymarker. used at walk init time (reliable data format, copy at 0x16f)Y
0x027016unusedY
IMG_DIGITS0x0280416numeric character images: "0123456789:-/", 8x16 each, in this order
IMG_WATTS0x042064watt symbol image 16x16
IMG_BALL0x046016pokeball 8x8
IMG_BALL_LIGHT0x047016pokeball light grey 8x8 (used for event pokemon)
0x04808unused
IMG_ITEM0x048816item symbol 8x8
IMG_ITEM_LIGHT0x049816item symbol light grey 8x8 (used for event items)
IMG_MAP_SMALL0x04a816tiny map icon 8x8 (used for "special map" reception)
IMG_CARD_SUITS0x04b864card faces: heart, spade, diamond, club, 8x8 each (used for "stamp" reception)
IMG_ARROWS0x04f8192arrows (up down left right), each in 3 configs (normal, offset, inverted) 8x8 each
IMG_MENU_ARROW_LEFT0x05b832left arrow for menu 8x16
IMG_MENU_ARROW_RIGHT0x05d832right arrow for menu 8x16
IMG_MENU_ARROW_RETURN0x05f832"return" symbol for menu 8x16
0x061840unused
0x063816symbol for "have more message" in the bottom right of messages. orred into last 8 columns (thus 16 bytes). applied after 0x0648
0x06488symbol for "have more messages" in the bottom right of messages. each byte here is anded with each col of last 8 in the message. both bitplanes (so you can make it black or keep as is). applied before 0x0638
0x065016medicine vial (?) icon 8x8
IMG_LOW_BATTERY0x066016low battery icon 8x8
IMG_TALK_FACES0x0670576large talk bubbles from bottom right with pokemon feeling icon (exclamation, heart, music note, smile, neutral face, ellipsis) 24x16 each, 6 of them
IMG_TALK_EXCLAMATION0x08b096large talk bubble from bottom left with exclamation point in it 24x16
IMG_MENU_TITLE_POKERADAR0x0910320"poké radar" menu heading in a box. 80x16
IMG_MENU_TITLE_DOWSING0x0a50320"dowsing" menu heading in a box. 80x16
IMG_MENU_TITLE_CONNECT0x0b90320"connect" menu heading in a box. 80x16
IMG_MENU_TITLE_TRAINER_CARD0x0cd0320"trainer card" menu heading in a box. 80x16
IMG_MENU_TITLE_INVENTORY0x0e10320"pokémon & items" menu heading in a box. 80x16
IMG_MENU_TITLE_SETTINGS0x0f50320"settings" menu heading in a box. 80x16
IMG_MENU_ICON_POKERADAR0x109064"poke-radar" icon for main menu 16x16
IMG_MENU_ICON_DOWSING0x10d064"dowsing" icon for main menu 16x16
IMG_MENU_ICON_CONNECT0x111064"connect" icon for main menu 16x16
IMG_MENU_ICON_TRAINER_CARD0x115064"trainer card" icon for main menu 16x16
IMG_MENU_ICON_INVENTORY0x119064"pokemon & items" icon for main menu 16x16
IMG_MENU_ICON_SETTINGS0x11d064"settings" icon for main menu 16x16
IMG_PERSON0x121064"person" icon for trainer card screen 16x16
IMG_TRAINER_NAME0x1250320trainer's name rendered as an image 80x16
IMG_ROUTE_SMALL0x139064small route image for "trainer card" screen 16x16
IMG_STEPS_FRAME0x13d0160"steps" in frame for second screen of trainer card 40x16
IMG_TIME_FRAME0x1470128"time" in frame for second screen of trainer card 32x16
IMG_DAYS_FRAME0x14f0160"days" in frame for second screen of trainer card 40x16
IMG_TOTAL_DAYS_FRAME0x1590256"total days:" in frame for second screen of trainer card 64x16
IMG_SOUND_FRAME0x1690160"sound" in frame for preferences screen 40x16
IMG_SHADE_FRAME0x1730160"shade" in frame for preferences screen 40x16
IMG_SPEAKER_OFF0x17d096speaker icon with no waves (no sound) for preferences screen 24x16
IMG_SPEAKER_LOW0x183096speaker icon with one wave (low sound) for preferences screen 24x16
IMG_SPEAKER_HIGH0x189096speaker icon with two waves (high sound) for preferences screen 24x16
IMG_CONTRAST_DEMONSTRATOR0x18f032contrast demonstrator (drawn a bunch of times over) 8x16
IMG_TREASURE_LARGE0x1910192large treasure chest icon for item view 32x24
0x19d0192large map scroll thingie 32x24
IMG_PRESENT_LARGE0x1a90192large present icon for item view 32x24
IMG_DOWSING_BUSH_DARK0x1b5064small bush dark-colored, for dowsing 16x16
IMG_DOWSING_BUSH_LIGHT0x1b9064small bush light-colored, for dowsing 16x16
TEXT_LEFT0x1bd0128"left: " string on white background for dowsing. 32x16Y
0x1c5096blank image 16x24
IMG_RADAR_BUSH0x1cb0192bush dark 32x24Y
IMG_RADAR_BUBBLE_ONE0x1d7064word bubble with one exclamation point (for poke hunting) 16x16
IMG_RADAR_BUBBLE_TWO0x1db064word bubble with two exclamation points (for poke hunting) 16x16
IMG_RADAR_BUBBLE_THREE0x1df064word bubble with three exclamation points (for poke hunting) 16x16Y
IMG_RADAR_CLICK0x1e3064three lines radiating from bottom left (for bush we just clicked) 16x16
IMG_RADAR_ATTACK_HIT0x1e70128skewed small 7-pointed star (attack) 16x32
IMG_RADAR_CRITICAL_HIT0x1ef0128skewed large 7-pointed star (critical hit attack) 16x32
IMG_RADAR_APPEAR_CLOUD0x1f70192cloud "for pokemon appeared" 32x24
IMG_RADAR_HP_BLIP0x203016"hp" item (4 of these make up an hp bar) 8x8
IMG_RADAR_CACH_EFFECT0x204016a little 5-pointed star image for when we catch something 8x8
TEXT_RADAR_ACTION0x2050768"attack/evade/catch" directions placard for battles 96x32
IMG_POKEWALKER_BIG0x2350256pokewalker image, blank screen, 32x32
IMG_IR_ARCS0x245032ir xmit icon (like wifi arcs) 8x16
IMG_MUSIC_NOTE0x247016music note icon 8x8
0x248016blank icon 8x8
IMG_HOURS_FRAME0x2490160"hours" in a pretty frame. appears unused 40x16
TEXT_CONNECTING0x2530384"connecting..." string for comms 96x16
TEXT_NO_TRAINER0x26b0384"no trainer found" string for comms 96x16Y
TEXT_CANNOT_COMPLETE0x2830768"cannot complete thisconnection" string for comms 96x32
TEXT_CANNOT_CONNECT0x2b30384"cannot connect" string for comms 96x16
TEXT_TRAINER_UNAVAILABLE0x2cb0768"other trainer isunavailable" s60tring for comms 96x32
TEXT_ALREADY_RECV_EVENT0x2fb0768"already received this event" string for comms 96x32Y
TEXT_CANNOT_CONNECT_AGAIN0x32b0768"canont connect to trainer again" string for comms 96x32Y
TEXT_COULD_NOT_RECV0x35b0384"could not receive..." string for comms 96x32Y
TEXT_HAS_ARRIVED0x38b0384"has arrived!" string for comms 96x16Y
TEXT_HAS_LEFT0x3a30384"has left." string for comms 96x16
TEXT_RECV0x3bb0384"received!" string for comms 96x16Y
TEXT_COMPLETED0x3d30384"completed!" string for comms 96x16
TEXT_SPECIAL_MAP0x3eb0384"special map" string for comms 96x16Y
TEXT_STAMP0x4030384"stamp" string for comms 96x16
TEXT_SPECIAL_ROUTE0x41b0384"special route" string for comms 96x16Y
TEXT_NEED_WATTS0x4330384"need more watts." string 96x16
TEXT_NO_POKEMON_HELD0x44b0384"no pokemon held!" string 96x16
TEXT_NOTHING_HELD0x4630384"nothing held!" string 96x16
TEXT_DISCOVER_ITEM0x47b0384"discover an item!" string 96x16
TEXT_FOUND0x4930384"found!" string 90x16
TEXT_NOTHING_FOUND0x4ab0384"nothing found!" string 90x16
TEXT_ITS_NEAR0x4c30384"it's near!" string 90x16
TEXT_FAR_AWAY0x4db0384"it's far away..." string 90x16Y
TEXT_FIND_POKEMON0x4f30384"find a pokemon!" string 90x16Y
TEXT_FOUND_SOMETHING0x50b0384"found something!" string 90x16
TEXT_GOT_AWAY0x5230384"it got away..." string 90x16Y
TEXT_APPEARED0x53b0384"appeared!" string 90x16
TEXT_WAS_CAUGHT0x5530384"was caught!" string 90x16Y
TEXT_FLED0x56b0384"fled..." string 96x16Y
TEXT_TOO_STRONG0x5830384"was too strong." string 96x16
TEXT_ATTACKED0x59b0384"attached!" string 96x16
TEXT_EVADED0x5b30384"evaded!" string 96x16
TEXT_CRITICAL_HIT0x5cb0384"a critical hit!" string 96x16
TEXT_SPACES0x5e30384" " (yes a bunch of spaces) string 96x16
TEXT_THREW_BALL0x5fb0384"threw a poke ball." string 96x16Y
TEXT_ALMOST_HAD0x6130384"almost had it!" string 96x16
TEXT_STARE_DOWN0x62b0384"stare down!" string 96x16
TEXT_LOST0x6430384"lost!" string 96x16
TEXT_PEER_HAS_ARRIVED0x65b0384"has arrived" (for walker to walker) string 96x16Y
TEXT_HAD_ADVENTURES0x6730384"had adventures!" string 96x16
TEXT_PLAY_BATTLED0x68b0384"play-battled." string 96x16
TEXT_WENT_RUN0x6a30384"went for a run." string 96x16
TEXT_WENT_WALK0x6bb0384"went for a walk." string 96x16
TEXT_RECV_GIFT0x6d30384"played a bit." string 96x16
TEXT_RECV_GIFT0x6eb0384"here's a gift..." string 96x16Y
TEXT_CHEERED0x7030384"cheered!" string 96x16
TEXT_VERY_HAPPY0x71b0384"is very happy!" string 96x16
TEXT_FUN0x7330384"is having fun!" string 96x16
TEXT_FEEL_GOOD0x74b0384"is feeling good!" string 96x16
TEXT_HAPPY0x7630384"is happy." string 96x16
TEXT_SMILING0x77b0384"is smiling." string 96x16
TEXT_CHEERFUL0x7930384"is cheerful." string 96x16
TEXT_PATIENT0x7ab0384"is being patient." string 96x16
TEXT_SITTING0x7c30384"sits quietly." string 96x16
TEXT_TURN_LOOK0x7db0384"turned to look." string 96x16
TEXT_LOOKING_AROUND0x7f30384"is looking around." string 96x16Y
TEXT_LOOKING_HERE0x80b0384"is looking this way." string 96x16
TEXT_DAYDREAMING0x8230384"is daydreaming." string 96x16
TEXT_INTERACT_FOUND_SOMETHING0x83b0384"found something." string 96x16
TEXT_WHAT0x8530384"what?" string 96x16
TEXT_JOINED0x86b0384"joined you!" string 96x16
TEXT_REWARD0x8830384"reward" string 96x16
TEXT_GOOD_JOB0x89b0384"good job!" string 96x16
TEXT_SWITCH0x8b30320"switch?" string 80x16
0x8c7064???
SOUND_OFFSET0x8cb064offsets into SOUND_DATA that contain the sounds data, array of pw_sound_info_t[16]Y
SOUND_DATA0x8cf0528sound data, array of pw_sound_frame_t[264]Y
ROUTE_INFO0x8f00190struct routeinfo - current route data
IMG_ROUTE_LARGE0x8fbe192current "area" we are strolling in graphic 32x24
TEXT_ROUTE_NAME0x907e320current "area" we are strolling in textual name 80x16
IMG_POKEMON_SMALL_ANIMATED0x91be384current pokemon animated sprite for "held items and pokemon" screen, fights, etc. 32 x 24 x 2 frames
IMG_POKEMON_LARGE_ANIMATED0x933e1536current pokemon large nimated sprite for main screen 64 x 48 x 2 frames
TEXT_POKEMON_NAME0x993e320cur pokemon name image 80x16
IMG_ROUTE_POKEMON_SMALL_ANIMATED0x9a7e1152route available pokemon selected by the same animated small sprites 32 x 24 x 2 frames x 3 pokemon
IMG_ROUTE_POKEMON_LARGE_ANIMATED0x9efe1536large animated image (like at 0x933e) but of the third (option c) available pokemon on this route. used for "joined your walk" situation 64 x 48 x 2 frame
TEXT_POKEMON_NAMES0xa4fe960available pokemon name images 80x16 x3 pokemon
TEXT_ITEM_NAMES0xa8be3840available item names as images. 96x16 x 10 images (one per item)Y
0xb7be66???
RECEIVED_BITFIELD0xb8001bitfield of special things received. 0x01 - "heart" stamp received, 0x02 - "spade" stamp received, 0x04 - "diamond" stamp received, 0x08 - "club" stamp received, 0x10 - "special map" received, 0x20 - walker contains an event pokemon (gifted or caught), 0x40 - walker contains event item (gifted or dowsed), 0x80 - walker has received a "special route"
0xb8013unused
0xb804576data for "special map received". format unknown. possibly used by the ds games, but no evidence of this found in the games.
EVENT_POKEMON_BASIC_DATA0xba4416gifted event poke, or radar-caught event poke. Basic data struct PokemonSummaryY
EVENT_POKEMON_EXTRA_DATA0xba5444extra data. struct eventpokeextradata
IMG_EVENT_POKEMON_SMALL_ANIMATED0xba80384small sprite 32 x 24 x 2 frames
TEXT_EVENT_POKEMON_NAME0xbc00320name image 80x16
EVENT_ITEM0xbd408gifted event item, or dowsed event item. item data. 6 bytes of zeroes, then u16 item, LEY
TEXT_EVENT_ITEM_NAME0xbd48384item name image 96x16
0xbec856unused
SPECIAL_ROUTE_STRUCT0xbf003260"special route" info (struct specialroute):Y
0xbf0066 bytes of zeroes (part of item struct but unused by DS or walker)Y
ROUTE_IMAGE_IDXNAME0xbf061enum routeimageidx
0xbf071unused
SPECIAL_POKEMON_BASIC_DATA0xbf0816special route-available pokemon basic data. struct pokemonsummary
SPECIAL_POKEMON_EXTRA_DATA0xbf1844special route-available pokemon extra data. struct eventpokeextradata
SPECIAL_POKEMON_STEPS_REQUIRED0xbf442min steps to encounter this poke on the route. u16 le
SPECIAL_POKEMON_PERCENT_CHANCE0xbf461percent chance to encounter this poke on route after step minimum met
0xbf471unused
SPECIAL_ITEM0xbf482special route-available item. u16 le
SPECIAL_ITEM_STEPS_REQUIRED0xbf4a2min steps dowse this item. u16 le
SPECIAL_ITEM_PERCENT_CHANCE0xbf4c1percent chance to dowse this item on route after step minimum met
0xbf4d3unused
SPECIAL_ROUTE_NAME_NINTENDOENC0xbf5042routename u16[21]
SPECIAL_POKEMON_EVENT_INDEX0xbf7a1"event index" for catching this route's special pokemon (1-127)Y
SPECIAL_ITEM_EVENT_INDEX0xbf7b1"event index" for dowsing this route's special item (1-127)Y
IMG_SPECIAL_POKEMON_SMALL_ANIMATED0xbf7c1920special route pokemon animates small sprite. 32 x 24 x 2 frames. should be 0x180 bytes big, but it 0x170. no idea why but confirmed
TEXT_SPECIAL_POKEMON_NAME0xc6fc320special route pokemon name image 80x16
IMG_SPECIAL_ROUTE_IMAGE0xc83c192special routes's large image for home screen, like 0x8fbe is for a normal route 32x24
TEXT_SPECIAL_ROUTE_NAME_SMALL0xc8fc320special routes's textual name 80x16
TEXT_SPECIAL_ROUTE_NAME0xca3c384special route item textual name 96x16
0xcbbc68unused
TEAM_DATA_STRUCT0xcc00548struct teamdata on our whole team, so that any walkers we peer play with transfer it to their ds game and we can be battled in the trainer house
0xce2492also written at walk start time as part of the above. probably just to keep the write a multiple of 0x80 bytes
0xce808unused
0xce881if low bit set, game will give player a starf berry once per savefile. used when 99999 steps reached
0xce891unused
0xce8a2current watts written to eeprom by cmd 0x20 before replying (likely so remote can read them directly). u16 be
CAUGHT_POKEMON_SUMMARY0xce8c483x route-available pokemon we've caught so far. 3x struct pokemonsummary
OBTAINED_ITEMS0xcebc123x route-available items we've dowsed so far. 3x {u16 le item, u16 le unused}
PEER_PLAY_ITEMS0xcec84010x route-available items we've been gifted by peer play. 10x {u16 le item, u16 le unused}Y
HISTORIC_STEP_COUNT0xcef028historic step count per day. u32 each, be, [0] is yesterday, [1] is day before, etc...
EVENT_LOG0xcf0c3264event log. circularly-written, displayed in time order. 24x struct eventlogitemY
TEAM_DATA_STAGING0xd480640team data written here before walk start action. struct teamdata
STAGING_AREA0xd70010496scenario data written here before walk start action. everything that 0x8F00-0xB7FF would haveY
CURRENT_PEER_TEAM_DATA0xdc00548current peer play peer. struct teamdata. uploaded as part of peer play. later shifted to index [0] at 0xde24 list of peers
MET_PEER_DATA0xde245480peers we've met. for battle house info. newest element is first. 10x struct teamdata
0xf38c116unused
PEER_DATA_TEMP0xf400760peer play temporary data about peerY
IMG_CURRENT_PEER_POKEMON_ANIMATED_SMALL0xf400384medium pokemon animated image of pokemon we are peer-playing with (never erased) 32x24 x 2 framesY
TEXT_CURRENT_PEER_POKEMON_NAME0xf580320rendered text name of pokemon we are peer-playing with 80x16
CURRENT_PEER_DATA0xf6c056data. struct peerplaydata

IR Commands

Taken and modified from Dmitry.gr's writeup

CMDDIRNOTES
00g2wCompressed EEPROM write. Documented at length above. Writes 128 bytes on a 128-byte boundary. "extra" byte is top 8 bits of address. Bottom 8 bits will always be zero. Reply will be CMD_04
02w2w, g2wDirect EEPROM write. Documented at length above. Writes 128 bytes on a 128-byte boundary. "extra" byte is top 8 bits of address. Bottom 8 bits will always be zero. Reply will be CMD_04
04w2w, w2gACK for an EEPROM write (CMD_00, CMD_02, CMD_0A, CMD_80, CMD_82)
06?2wDirect internal memory write. "extra" byte is top 8 bits of address. First byte of payload is low byte of address. The rest of the payload will be written to internal memory at that address. Yes, this means RAM, MMIO, etc. Reply will be CMD_06
0A?2wDirect EEPROM write, random length. "extra" byte is top 8 bits of address. First byte of payload is low byte of address. The rest of the payload will be written to EEPROM at that address. Reply will be CMD_04
0Cw2w, g2wEEPROM read. Payload is a 16-bit start address, big-endian, followed by a one-byte length. Reply will be CMD_0E
0Ew2w, w2gEEPROM read reply. Payload is the data requested by CMD_0C
10w2wSent by the master walker in a peer-play scenario at start. Enclosed is 0x68 bytes of data - the "IDENTITY DATA". The expected reply from the peer is CMD_12
12w2wSent by the slave walker in a peer-play scenario in reply to CMD_10. Enclosed is 0x68 bytes of data - the "IDENTITY DATA". This data is explained later. The "master" will proceed to exchange needed data, and then will send CMD_14
14w2wSent by the master walker in a peer-play scenario after all the needed data has been exchanged. Enclosed is 0x34 bytes of data - the "PEER PLAY DATA", "extra" byte byte will be 1. Slave walker replies with CMD_14 as well, same format, "extra" byte byte will be 2. Master will then send CMD_16
16w2wSent by the master walker in a peer-play scenario. No data. Reply is also a CMD_16. Does the entire peer-play UI and awards gift item.
1Cw2wSent by the either walker during peer play when it's detected that it's "played" with this peer too recently. Shows the "Cannot connect to trainer again" error. No data.
20g2wRequests walker's "IDENTITY DATA". No data attached. Walker is expected to reply with CMD_22
22w2gData is "IDENTITY DATA", 0x68 bytes
24??Ping request. No operation other than reply with CMD_26.
26??Ping reply. Sent in reply to CMD_24
2Ag2w, w2gData is "UNIQUE ID DATA", used to set RTC. Erases the walker. Differs somehow from CMD_2C. Reply is CMD_2A, 0x28 bytes, "UNIQUE ID DATA" which is now all 0xFF. This command is actually used by the game to reset the walker
2C?2wData is "UNIQUE ID DATA", used to set RTC. Erases the walker. Differs somehow from CMD_2A. Reply is CMD_2C, 0x28 bytes, "UNIQUE ID DATA" whic is now all 0xFF
32?2wData is "IDENTITY DATA" that master sends to the slave. From it only RTC is used, if a flag is set. Reply from the walker will be CMD_34
34w2?Reply to CMD_32, no data
36?2wNo data, no reply. Shows "Cannot complete this connection" error
38?2wPerforms the "walk start" action (same as what CMA_5A does), but without the UI. Does not erase "special event" status, unlike CMD_5A which does. See CMD_5A for details.
40g2wSame as CMD_32. Data is "IDENTITY DATA" that master sends to the slave. From it only RTC is used, if a flag is set. Reply from the walker will be CMD_42
42w2gReply to CMD_40, no data
44w2gNo data, no reply. Show "cannot complete this connection"
4Eg2wNo data. Reply is CMD_50. Performs "walk end" action, erases pokemon state, shows "walk end" UI
50w2gReply to CMD_4E, no data
52?2wSame as CMD_32. Data is "IDENTITY DATA" that master sends to the slave. From it only RTC is used, if a flag is set. Reply from the walker will be CMD_54
54w2?Reply to CMD_52, no data
56?2wNo data, no reply. Shows "Cannot complete this connection" error
5Ag2wNo data. Reply is CMD_5A. Performs "walk start" action, including copying data to proper places, shows the UI
60?2wSame as CMD_32. Data is "IDENTITY DATA" that master sends to the slave. From it only RTC is used, if a flag is set. Reply from the walker will be CMD_62. Also reload our walker info from eeprom.
62w2?Reply to CMD_60, no data
64?2wNo data, no reply. Shows "Cannot complete this connection" error
66?2wNo data. Set the message to show at connection end to be "Completed". Reply is CMD_68
68w2?No data. Reply to CMD_66
80g2wCompressed EEPROM write. Documented at length above. Writes 128 bytes on a 128-byte boundary. "extra" byte is top 8 bits of address. Bottom 8 bits will always be 0x80. Reply will be CMD_04
82w2w, g2wDirect EEPROM write. Documented at length above. Writes 128 bytes on a 128-byte boundary. "extra" byte is top 8 bits of address. Bottom 8 bits will always be 0x80. Reply will be CMD_04
9C?2w, w2?No data. Show "Could not receive..." error. Reply is CMD_9C
9E?2w, w2?No data. Show "Could not receive..." error. Reply is CMD_9E. Sent by walker in reply to CMD_A0, CMD_A2, CMD_A4, CMD_A6, CMD_A8, CMD_AA, CMD_AC, CMD_AE
A0 A2 A4 A6 A8 AA AC AE?2w, w2?Use byte 0x5A of the most recently received "IDENTITY DATA" as event index. Check if we've participated. If so, reply with an empty CMD_9E, if not, reply with the same CMD as we received, 17 bytes. First 16 will be "EVENT BITMAP", last will be the event index we just checked for.
B8 BA BC BE?2wNo data. Award the user a stamp. In order they are: heart, spade, diamond, club. Replies are CMD_C8, CMD_CA, CMD_CC, CMD_CE respectively
C0?2w, w2?No data. Award the user a "special map" This seems to do nothing but show an icon in the UI, and show the "Special map received" message. Reply is also an empty CMD_C0
C2?2w, w2?No data. Award the user an "event pokemon". Details later. Reply is also an empty CMD_C2
C4?2w, w2?No data. Award the user an "event item". Details later. Reply is also an empty CMD_C4
C6?2w, w2?No data. Move the user to an "event route". Details later. Reply is also an empty CMD_C6
C8 CA CC CEw2?Replies to CMD_B8, CMD_BA, CMD_BC, CMD_BE respectively. No data.
D0?2wNo data. Same as CMD_C0, except also grant the user all 4 stamps
D2?2wNo data. Same as CMD_C2, except also grant the user all 4 stamps
D4?2wNo data. Same as CMD_C4, except also grant the user all 4 stamps
D6?2wNo data. Same as CMD_C6, except also grant the user all 4 stamps
D8?2wNo data. Show "Cannot complete this connection" error. No reply.
F0?2w, w2?Not yet fully understood. Data is 0x71 bytes of "ENROLL DATA" Some sort of enroll action. The only path to code that writes te EEPROM's "UNIQUE ID DATA" and "LCD INIT DATA". Reply is also a CMD_F0, with 0x28 bytes of data - a copy of the "UNIQUE ID DATA"
F4?2wImmediate disconnect. No reply.
F8w2g, w2wPart of connection initiation as explained above. No data. Sent by slave walker to master walker or game after getting CMD_FA
FAg2w, w2wPart of connection initiation as explained above. No data. Sent by game or master walker to slave walker after seeing an advertising byte 0xFC on IR
FE?2w, w2?Not yet fully understood. Writes the 8 data bytes to EEPROM at offset 8. Never seen in the wild. Reply is an empty CMD_FE

Manipulating the Pokewalker

Programming the Pokewalker

Useful resources

The E8a Emulator uses NMIB, Test, E7_0, E7_1, E7_2, RESB pins to debug and program.

H8/38602R Group Hardware Manual Section 6.3.1 on boot mode programming: Allows programming over the UART. MCU sends one byte of 0x00 to indicate it's ready to rx data. Host then sends 0x55 as an ack. Host sends a programming control program to the MCU addr (0xFB80-0xFF7F on a H8/38602R), control then goes to this program. Serial comms are still up but general regs and SP need to be initialised by program. To exit, hold reset, set NMI, release reset. Test and NMI need to be constant during the operation.

For a flowchart, see page 107 (PDF page 141).