aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--docs/notes.md58
-rw-r--r--wireshark/pictochat.lua18
3 files changed, 62 insertions, 15 deletions
diff --git a/.gitignore b/.gitignore
index bbc750e..b5424e0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,4 +17,5 @@
# copyrighted files
roms/
+copyright/
diff --git a/docs/notes.md b/docs/notes.md
index 5da8efe..3473ee4 100644
--- a/docs/notes.md
+++ b/docs/notes.md
@@ -81,10 +81,12 @@ sufficiently advanced local multiplayer emulation.
source: <https://git.pipeframe.xyz/fork/melonDS>
+[masscat-nifi]: <https://web.archive.org/web/20090202194241/http://masscat.afraid.org/ninds/proto_info.php>
+
- melonDS @ Config > Wifi settings "Local multiplayer features do not use the same network protocols as online play"
- comment @ src/Wifi.cpp:46 "multiplayer host TX sequence"
- references to `RFTransfer_Type{2,3}` @ <https://www.problemkaputt.de/gbatek.htm#dswifirfchip>
-- nintendo ds ni-fi protocol @ <https://web.archive.org/web/20090202194241/http://masscat.afraid.org/ninds/proto_info.php>
+- nintendo ds ni-fi protocol @ [masscat-nifi]
- melonDS emulates actual 802.11b frames
- the protocol does not appear to be encrypted:
@@ -92,7 +94,8 @@ source: <https://git.pipeframe.xyz/fork/melonDS>
the string `lork` is visible as plain text in the hexdump (offset 0x0056),
which appears to be some kind of 16-bit encoding of the username set on the
- emulator used to capture these packets
+ emulator used to capture these packets (this is likely UCS-2 and not UTF-16
+ as suggested by [masscat-nifi] which specifies UCS-2).
- The messages are not sent as single packets. The Ni-Fi protocol appears to set
up a constant stream, and messages are sent across multiple frames.
- A full height filled-in message results in 64 packets (with Wireshark filter
@@ -114,7 +117,8 @@ source: <https://git.pipeframe.xyz/fork/melonDS>
![](../assets/pictochat-msg-height-1-4.png)
![](../assets/pictochat-msg-height-5-draw.png)
-- Message content is likely only cropped when displaying
+- In addition to being cropped before sending, the message border appears to
+ mask the drawing:
![](../assets/pictochat-msg-crop.png)
![](../assets/pictochat-msg-crop-lork2.png)
@@ -132,12 +136,14 @@ source: <https://git.pipeframe.xyz/fork/melonDS>
(except the bottom and corners) that can not be filled in. The bottom
border is correctly displayed for received messages, but the edit field has
an additional row of pixels that directly touch the message border on the
- bottom.
+ bottom which is not visible in the received version of the message (i.e. is
+ being masked).
- When any message is cloned, additional pixels that were masked on the top
screen become visible again in the edit field. This includes the bottom row
of pixels, as well as the two rows of pixels shown in the single line
message picture.
- - The drawable area (including obstructed top-left corner) is 228x80 pixels
+ - The **apparent** drawable area (including obstructed top-left corner) is
+ 228x80 pixels.
Observed package counts (no resends) for messages of different sizes:
|draw area|display height|packet#|
@@ -158,10 +164,9 @@ Notable:
- Messages that draw below line 1 while keeping line 1 empty can't be cropped
to utilize line 1 as the username label is in the way. The captured packet
counts suggest that the content of line 1 is still sent (although empty).
-- The messages are cropped twice:
- * (destructive) *before* sending, as suggested by the packet counts
- * (non-destructive or display only) when displayed in the message log on
- the top screen
+- The messages are cropped *before* sending, as suggested by the packet counts
+- The message content is masked when displayed in the message log on the top
+ screen
### Message content
@@ -175,9 +180,9 @@ Notable:
0xe004 at offset 0x0026, while resends have a value of 0xf000 instead.
- There are a lot of messages with length 0xaa (170), these appear to include a
random 32-bit value at offset 0x0046.
-- The message content (suspected bitmap-like format) appears to be sent
- unencrypted (patterns of 0x0 and 0x1 nibbles clearly visible in hexdump).
-- 0x004d - 0x00ec appears to be used to send the actual message content:
+- The message content appears to be sent unencrypted (patterns of 0x0 and 0x1
+ nibbles clearly visible in hexdump).
+- Offset 0x004d - 0x00ec appears to be used to send the actual message content:
![](../assets/pictochat-msg-crop-lork2.png)
![](../assets/ws-msg-fill-top.png)
@@ -272,6 +277,32 @@ type 2 exclusively.
(Bottom Wireshark window is the room host, top window shows type != 2 Ni-Fi
messages from the system that joined later)
+## Drawing format
+
+- The drawings appear to be split into 8x8 sprite tiles. TODO: pixel order
+ within tiles + TODO: sprite ordering (likely both reading order).
+
+### Palette
+
+|idx|hex|
+|-|-|
+|0|transparent (white)|
+|1|`#000000` <b style="color: #000000">■</b>|
+|2|`#d3cbc3` <b style="color: #d3cbc3">■</b>|
+|3|`#eb00eb` <b style="color: #eb00eb">■</b>|
+|4|`#fb008a` <b style="color: #fb008a">■</b>|
+|5|`#fb0028` <b style="color: #fb0028">■</b>|
+|6|`#fb4900` <b style="color: #fb4900">■</b>|
+|7|`#fba200` <b style="color: #fba200">■</b>|
+|8|`#e3f300` <b style="color: #e3f300">■</b>|
+|9|`#82fb00` <b style="color: #82fb00">■</b>|
+|a|`#10fb20` <b style="color: #10fb20">■</b>|
+|b|`#00fbba` <b style="color: #00fbba">■</b>|
+|c|`#00c3fb` <b style="color: #00c3fb">■</b>|
+|d|`#0079fb` <b style="color: #0079fb">■</b>|
+|e|`#0030fb` <b style="color: #0030fb">■</b>|
+|f|`#2800fb` <b style="color: #2800fb">■</b>|
+
## Unsure/notes
- Is the endianness of the DS properly emulated?
@@ -290,5 +321,6 @@ messages from the system that joined later)
* resolution
* pixel ordering
* palette color indices (pixels are 1 nibble)
-- what types of pictochat packets are there?
+- what types of pictochat packets are there? (i.e. how are room join/leave
+ events broadcast?)
diff --git a/wireshark/pictochat.lua b/wireshark/pictochat.lua
index ff09783..56300c3 100644
--- a/wireshark/pictochat.lua
+++ b/wireshark/pictochat.lua
@@ -15,7 +15,13 @@ pc.fields.host = ProtoField.ether("pictochat.host", "Room host")
pc.fields.src = ProtoField.ether("pictochat.src", "Source")
pc.fields.dst = ProtoField.ether("pictochat.dst", "Destination")
+-- Content offset appears to be some kind of offset for indicating where to
+-- store the current frame's data in a larger buffer. Messages sent in multiple
+-- parts increment this value by 160 for each new original (pictochat.resend ==
+-- 2) message.
pc.fields.content_offset = ProtoField.uint16("pictochat.content_offset", "Content offset")
+-- This appears to be the actual message content (the drawing) sent as an array
+-- of 8x8 tiles.
pc.fields.content = ProtoField.bytes("pictochat.content", "Content")
pc.fields.sequence = ProtoField.uint16("pictochat.sequence", "Packet sequence")
@@ -36,7 +42,10 @@ function pc.dissector(buffer, pinfo, tree)
pc_tree:add_le(pc.fields.msg_type, buffer(0x00, 2))
pc_tree:add_le(pc.fields.resend, buffer(0x02, 2))
+ pc_tree:add(pc.fields.unknown, buffer(0x04, 6))
pc_tree:add_le(pc.fields.length, buffer(0x0a, 2))
+ pc_tree:add(pc.fields.unknown, buffer(0x0c, 2))
+ pc_tree:add(pc.fields.unknown, buffer(0x0e, 2))
pc_tree:add_le(pc.fields.dst, buffer(0x10, 6))
pc_tree:add_le(pc.fields.src, buffer(0x16, 6))
pc_tree:add_le(pc.fields.host, buffer(0x1c, 6))
@@ -46,12 +55,16 @@ function pc.dissector(buffer, pinfo, tree)
pinfo.cols.dst = tostring(pc_dst_field())
pinfo.cols.info = pc_msg_type_field().display .. ", " .. pc_resend_field().display
- pc_tree:add_le(pc.fields.unknown, buffer(0x22, 2))
+ pc_tree:add_le(pc.fields.unknown, buffer(0x22, 2)) -- counting
pc_tree:add_le(pc.fields.unknown, buffer(0x24, 2))
+ pc_tree:add_le(pc.fields.resend, buffer(0x26, 2))
+ pc_tree:add(pc.fields.unknown, buffer(0x28, 6))
+ pc_tree:add(pc.fields.unknown, buffer(0x2e, 4))
local msg_type = pc_msg_type_field()()
if msg_type == 0 then -- type = Normal (TODO: this should be 'message = drawing')
pc_tree:add_le(pc.fields.content_offset, buffer(0x32, 2))
+ pc_tree:add_le(pc.fields.unknown, buffer(0x34, 2))
local content_length = pc_length_field()() - 50 -- TODO: why 50?
buffer = buffer(0x36)
@@ -60,7 +73,8 @@ function pc.dissector(buffer, pinfo, tree)
pc_tree:add_le(pc.fields.sequence, buffer(0x00, 2))
pc_tree:add_le(pc.fields.resend, buffer(0x02, 2)) -- copy
- pc_tree:add(pc.fields.unknown, buffer(0x04, 4))
+ pc_tree:add(pc.fields.unknown, buffer(0x04, 2))
+ pc_tree:add(pc.fields.unknown, buffer(0x06, 2))
end