Views: 6,701,350 Homepage | Main | Rules/FAQ | Memberlist | Active users | Last posts | Calendar | Stats | Online users | Search 03-28-24 11:45 PM
Guest:

0 users reading wifi notes | 1 bot

Main - Development - wifi notes Hide post layouts | New reply


Arisotura
Posted on 06-06-17 11:06 AM (rev. 16 of 06-21-17 07:15 PM) Link | #180
wifi notes dump



Port 244

seems to be for forcing the side-effects of IRQs?

bit6: ??? seems to fuck up MP replies
bit7: ??? no effect on TX_SEQNO
bit12: when set, TX_SEQNO increases in an erratic way (starts slow then goes superfast)

the following code was found:
u16 curseqno = SEQNO;
PORT244 = 0x1000;
for (int tries = 100; tries >= 0; tries--)
{
if (SEQNO != curseqno) break;
}
PORT244 = 0;
then it calls the IRQ12 handler
which seems to fake an IRQ12 or something like that


Port 118 -- CMD_COUNT

"when it reaches zero, CMD packet is transferred" -- wrong. it's transferred before the timer reaches zero.

seems the transfer starts ~2ms after the counter starts decrementing
but my observations show that a LOC1 transfer also has similar delays, it fluctuates. probably depends on whenever it can find a window where nobody else is sending shit. apartment complex = quite a few wifis around, so yeah.

so chances are the transfer is meant to start immediately, or rather, as soon as possible.

CMD_COUNT is the window during which the transfer is possible. if there isn't enough time remaining when it tries to send, it marks it as failed (sets first word of TX header to 0x0005) and triggers IRQ12.

in that case, CMD_COUNT is 0xA at the time IRQ12 is triggered.

also, TXSEQNO is incremented. seems IRQ12 does that. IRQ7 also does it except when it's for the CMD ack.

if clients fail to reply, CMD transfer will keep retrying until the time runs out. final attempt is marked by IRQ12 -- any previous attempts only get IRQ1.

but seems in that case TXSEQNO is incremented upon IRQ1??

also, for CMD transfers, TXSTAT bit0 is only set when the transfer completes properly (ie. gets replies). otherwise, bit0 is cleared/not set(?), but bit1 isn't set.


Port 210 -- TX_SEQNO

incremented under the following conditions:

* when starting a transfer (except for CMD ack)
* upon IRQ1 when retrying a transfer (atleast with CMD)
* upon IRQ12



Port 008 -- TXSTATCNT

bit0-7: effect unknown, but they fuck things up
bit8-11: unknown, no effect observed
bit12: trigger IRQ1 and set TXSTAT bit8-11 to 0x4 when MP reply transfer is done (doesn't apply to default-empty replies)
bit13: trigger IRQ1 and set TXSTAT bit8-11 to 0xB when MP ack transfer is done
bit14: trigger IRQ1 and set TXSTAT bit8-11 to 0x8 when MP cmd transfer is done
bit15: trigger IRQ1 and set TXSTAT bit8-11 to 0x3 when beacon transfer is done



Port 268 -- RXTXADDR

when sending default (empty) MP reply: random, seems to be left untouched from previous RX
when sending MP ack: reads 0xFC0



Multiplayer transfer sequence

1. host sends data via CMD, clients receive it normally
2. host waits for clients to reply, clients reply automatically (which seems to be completely transparent to their operation and only needs port 094 configured), host receives client replies normally
3. host sends ack, which is automatic (albeit signalled by IRQ7), clients receive the ack like a normal packet

may not be right, but experiments with a modified NSMB ROM showed that:
* client-reply transfers don't trigger IRQ7 and don't seem to trigger IRQ1 either wrong
* the client (Luigi) wants to see the final ack

____________________
Kuribo64

Arisotura
Posted on 06-10-17 10:43 PM Link | #185
TXBUF_REPLY latching

This is how port 094 goes into 098, which is (I think) required for sending multiplayer replies.


There is code for manual latching, but a) said code needs a value already set into 098 and b) experiments hinted that manual latching wasn't required.


From what I observed, the client only sets 094 once the auth/assoc completes.


The RX start IRQ handler stores 098 somewhere, then clears bit15 of it, then waits until it's done receiving shit (by checking RFPINS bit0-1), sets bit6 of 244 to 1 then 0, then sets 228 to 8 then 0, then puts the previous 098 value back into it via latching.

weird.


So, potential places auto-latching could occur:
* RX start
* RX end
* maybe only when receiving a multiplayer data frame
* when messing with 244/228? haven't observed anything

____________________
Kuribo64

Arisotura
Posted on 06-13-17 09:57 AM (rev. 4 of 06-14-17 12:36 PM) Link | #192
so upon RX end, it checks the status of the MP reply packet

if TXheader[0] has bit0 set, or if the value in 098 isn't ((packetaddr>>1)|0x8000), it disconnects



unformatted finding dump
// MP REPLY
//
// all this happens when AID_LOW matches the packet's client bitmask (might cause spurious interrupts when receiving regular data frames? or does it check the destination addr?)
//
// transfer start is signalled by IRQ7 always, no matter what 098 is set to. no IRQ12.
// TXSEQNO is always incremented upon that IRQ7
// the reply packet is only sent if 098 has bit15 set, tho.
// TXBUSY doesn't say shit.
// RFSTATUS is 8 and RFPINS is 0046.
// if TXSTATCNT bit12 is set: IRQ1 happens and TXSTAT is set to 0x0401
// txheader[0] is updated to xx01 but that seems to happen when receiving the next frame, right before 094 is latched
// 094 is latched into 098 and reset to zero, seems to happen upon IRQ0
// 098 is untouched after transfer

// frame 0208 and 0228 -> C

// TXSTATCNT bit0-11 fuck things up


oh also, it seemed that RXCNT bit15 also controls sending (wasn't possible to send shit when it was cleared)

____________________
Kuribo64

Arisotura
Posted on 06-15-17 11:33 PM (rev. 2 of 06-17-17 11:46 PM) Link | #196
interesting

seems if no reply is configured when one is needed, it sends an empty reply frame

the rxheader[0] type for the empty reply frame is 0xF, type for non-empty frames is 0xE


also, when sending a MP reply, the hardware sets the header duration field, dunno the exact formula tho, but it depends on the reply size

____________________
Kuribo64

Arisotura
Posted on 10-17-17 02:18 AM (rev. 2 of 07-25-23 07:41 PM) Link | #397
MP retry mechanism

after each round: (after ack is sent)
txheader[2] is updated, bits are cleared when the corresponding client responded fine
if the packet needs to be resent, the clients that responded fine aren't polled again (client mask in the frame body isn't updated on the host side tho, but clients do receive the new mask)

seems the frame body client mask is copied to txheader[2] at the beginning, regardless of what the initial value is

SEQNO is incremented normally for retries, as if they were separate transmits

____________________
Kuribo64

Arisotura
Posted on 01-02-18 02:46 PM (rev. 7 of 01-04-18 10:54 PM) Link | #478
theory on txheader[4]:

the byte there would be incremented after sending a packet

which would be fitting with what GBAtek describes

needs verifying


so, txheader[4]

values >1 cause the sequence number not to be changed

this seems to be a retry counter, but it works differently for MP replies

LOC1/2/3

seems it's not incremented at all.

maybe setting a bit somewhere can change that?

CMD

the byte is incremented after each send attempt, upon the ack IRQ1. it is not incremented when the transmission is successful on first try

maybe reset to zero? but doesn't seem so.

it stops incrementing when it reaches 0xFF

values above 2 don't seem to cause transmit errors...? it's still sending, might be setting some error/whatever bits somewhere tho?

the sequence number for the ack is always taken from TX_SEQNO (and causing it to be incremented)

however it seems that the client doesn't receive retransmit attempts...? it doesn't receive the retransmitted frame (doesn't expose it) but does receive the ack. probably the retransmit thing is setting bit11 in the frame control, or something

REPLY

seems to be incremented upon IRQ0 (after receiving the MP cmd frame)

other than that, rules are the same as for CMD





reply:

changing port 098 between IRQ0 and IRQ7 has no effect. all the decision is taken upon IRQ0.

framectl values that trigger the autoreply: 0208, 0228, 0248

____________________
Kuribo64

Arisotura
Posted on 08-12-22 04:18 PM (rev. 63 of 09-03-22 07:42 PM) Link | #5464
NEW THEORIES ABOUT SHIT:


port 244/228:

likely some kind of receive-inhibit -- it is used (along with forcing a TXBUF_REPLY value) in Pictochat when receiving a CMD frame with a client mask of zero

presumably it is meant for CMD frames that aren't destined to the current client -- yup, the code checks the client bitmask before doing that thing

quick test shows no effect when receiving beacons. it's likely these ports are specific to local multiplayer.

seems to be some sort of receive inhibit for MP replies.

procedure:
* port 244: bit6 is set then cleared
* port 228: set to 8 then 0

when doing so, if port 094 is set: CMD frame is ignored, no reply is sent at all
on next CMD frame (provided the ports aren't touched again): the REPLY frame for the previous CMD is sent (unless a new REPLY frame was configured in the meantime), seqno seems to be forced to 0x0630, framectl bit11 is set. TODO: see if more adjustments are done

TODO: only works sometimes??


port 244 seems to inhibit the transfer of a MP reply, only if one is configured in port 098 AND if port 244 is used while (RFPINS & 3) != 3 (at that point, RFPINS=0044 and RFSTATUS=8).

if a reply is configured in port 098, it is not transferred, but register 094 is still latched into 098.
otherwise, the default empty reply is sent normally.

TODO: seems to cause oddball IRQ1?

just messing with port 244 is enough to observe this effect. port 228 doesn't seem to have an effect?

messing with port 244 at another time seems to have other weird effects, likely dependent on timing.

port 228 has no observed effect.


TXBUF_CMD bit14:

based on observations, inhibits automatic SEQNO filling-in and adjustment when sending a CMD frame. there might be more to it.

RESEARCH NOTES:

applies to the CMD frame: sequence number is left as-is (not filled in automatically) and not incremented.
sequence number for the ack is filled in and incremented normally.
both frames are received by the client normally.

(also worth noting: when the CMD slot fails to transmit at all, SEQNO is still incremented by one)
(SEQNO incremented: on CMD IRQ7 (unless told otherwise), on ack IRQ1, on IRQ12 when completely failing to send?)

I haven't observed any effect when setting bit12 or bit13 in TXBUF_CMD.

similarly, bit12/13/14 in TXBUF_REPLY don't seem to do shit either.


similarly: if txheader[04] is 1 or more:
* seqno isn't updated for the CMD frame (but it is updated for the ack frame)
* bit11 in CMD frame control is set (only on receiver side, original frame control is unchanged) (which isn't the case with TXSLOT_CMD.bit14)
* ack frame control is normal
* both frames are received normally by the client
* seems to have a harder time sending when txheader[04] is 3 or more?? just fails when it's 7? might be based on W_TX_RETRY_COUNT
* takes priority over TXSLOT_CMD.bit14

txheader[04] is incremented upon IRQ1 it seems -- CMD auto-retry attempts just rely on that

W_TX_ERR_COUNT isn't updated when clients fail to reply



W_TX_HDR_CNT bit2 only disables the filling-in of the packet seqno. the SEQNO register is still updated as normal. frame control isn't affected either.
W_TX_HDR_CNT bit0 breaks CMD transfers (presumably due to bad duration value?) -- the CMD is transferred but not the ack



frame retransmit details:

* when a duplicate CMD frame is received (as in, has same seqno as the last CMD frame): it is received and stored in the RX buffer, and the reply is triggered, but the frame isn't exposed to software (RX cursor isn't updated, RX-end IRQ isn't fired, RX header isn't created either)

* hardware knows what the last CMD frame's seqno is, even if other frames are received before the retransmit. TODO: figure out how it works. does it work for all sorts of frames, or only CMD frames? only multiplayer frames?
* tests hint that hardware does keep track of the last CMD frame seqno

* RX-end IRQ may be skipped, but RX-start IRQ probably still fires (at that point in time it can't tell that the frame is going to be a duplicate). yup, RX start still fires. RX start likely fires for all frames regardless of what they contain (since the hardware can't determine whether to reject them at this point)



what says a given frame is a multiplayer frame:

* for a CMD frame: destination MAC is required to be 03:09:BF:00:00:00
* any other broadcast MAC seems to result in the frame being apparently sent (IRQs are thrown on host side) but ignored by the client (possibly fromDS data frames just aren't supposed to be broadcast to everybody, that or there's a RXFILTER bit for this? yes, bit2)
* non-broadcast MACs seem to cause the frame to be treated like a regular frame? client tries to send something (IRQ7 triggered) twice, but host receives nothing, maybe it's trying and failing to send regular acks in response? -- non-broadcast MAC might cause the hardware to expect to receive an ack which it's not getting or which is conflicting with the CMD functionality
* the above happens regardless of what AID_LOW is set to
* earlier observations hinted that the frame control didn't have to be 0228, some other values worked too

* valid CMD types: 0208, 0228, 0248
* valid REPLY types: 0118, 0158 (empty frame)


* similarly, for REPLY frames, the destination MAC must be 03:09:BF:00:00:10 and framectl must be 0118 or 0158 (anything else is ignored by the host). source MAC does not matter.
* can be assumed that ACKs require framectl=0218 and MAC=03:09:BF:00:00:03
* seems that REPLY frames are replaced with a dummy blank if the specified frame is too big for the given duration? yes

* in RXheader[0]: the frame types C/D/E/F are specific to MP frames. for example, a FromDS data frame only gets type C if the destination MAC is 03:09:BF:00:00:00.
* actually, I managed to receive a frame with FC=0218 and RXheader[0]=801C. so it appears these types aren't based on the frame control at all (except for E/F, to tell apart the empty-reply type), but on the destination MAC.
* types E/F for MP replies are based on the framectl's subtype value, not on the actual frame length. not sure if it specifically checks for type5 or just checks bit2 of the subtype field (more likely the latter)

types E/F are given if a frame's third MAC address is 03:09:BF:00:00:10.
types C/D are given if a frame's first MAC address is 03:09:BF:00:00:00/03.
this, regardless of anything else.
the first one (E/F) has priority over the second one.

there seems to be special handling for data-frame subtypes 1 and 5 when having types E/F? these can't be received outside of a CMD frame transfer, and aren't even acknowledged.

type F seems to be specifically given to data-frame subtype 5.





CMD transfer details:

TX header status is updated to 0005 upon the CMD IRQ1 (5 when clients failed to respond, or when there's any error in general)
same deal for txheader[04]

hardware will refuse to send a CMD frame is AID_LOW is nonzero not really but it fucks things up if the host's AID_LOW is included in the frame's client mask



REPLY transfer details:

reply isn't transferred if it's too big for the reply window specified in the CMD frame. instead, default-empty reply is sent.
TODO: work out how this works? window 0xD6 allows max packet size 0x1C, 0xD8 allows max 0x1E.
reply is not transferred if (preamble + (length * 4)) > reply window
(assume length*8 instead of length*4 for 1Mbps transfer rate)
TODO: does this raise any transmit error anywhere? or does it just ignore port 098? it doesn't seem to touch the frame's TX header at all

actually: in that situation, all is done as normal, except:
* txheader[04] is left unchanged
* the frame isn't sent, default-empty reply is sent instead


clients cannot receive other clients' frames at all (they don't seem to even be received, as opposed to being received but ignored)



// MP error counters at 1D0:
// incremented upon ack IRQ7
// only for host (not incremented on client side)
// a 8bit read counts as a 16bit read!

// client bits cleared in txheader[02] when successful
// (txheader[02] updated to tell which clients failed to respond, updated as ACK is sent, presumably upon ack IRQ7?)
// (original txheader[02] does not matter)
// idk what txheader[06] is for
// missing MP replies aren't considered a RX error (not incrementing in 1C4 or 1Bx)

side note: 0x04808278 contains the seqno of the last received frame.




IEEE duration

* in MP ack frames: it is always zero

* in MP reply frames: it is set depending on how much time is left

for example: say the IEEE duration on the CMD frame is set to: 0xF0 + ((clienttime + 0xA) * nclients)

and it's sent to one client

the hardware would set the duration on the first reply to 0xF0 + (4 * (clienttime - time_taken)) (clienttime being the reply window for the client, time_taken being how long the reply frame actually lasted, ie preamble+len*4)

(values assuming short preamble and 2MB/s rate)

if there are more clients: the added duration per client seems to be (clienttime + 0xC)

for control frames with subtype A: duration/AID field is set to 0xC000 | W_AID_FULL.



RX filtering

hardware 'ignores' frames that don't match the RX filtering criteria (and some other rules): in this case, the frame is simply not exposed to software, by not updating the RX-buffer write cursor and not raising the RX-end IRQ.

unknown if ignored frames still count towards certain statistics?


RXFILTER

* bit0: receive beacons with mismatched BSSID, receive data frame retransmits (FC.bit11 set) (only if frame BSSID-matches or bit11 is set), possibly others too
* bit1: receive non-MP-ack data frames with FC=0x18 (subtype 1)
* bit2: receive non-MP-CMD data frames with FC=0x28 (subtype 2)
* bit3: receive data subtype 3
* bit4: receive data subtype 5
* bit5: receive data subtype 6
* bit6: receive data subtype 7
* bit7: receive MP acks
* bit8: receive empty MP replies (non-MP FC=0158 ignores this bit)
* bit9: receive non-beacon management frames with mismatched BSSID
* bit10: same function as bit9
* bit11: receive control/data frames with mismatched BSSID
* bit12: (GBAtek) "Update W_RXBUF_WRCSR after IEEE header" -- no effect observed on IRQs
* bit 13-15 don't exist

frames with a destination MAC other than W_MACADDR or broadcast, are always ignored. NOTE: the hardware always checks the frame's first address field and considers that to be the frame's destination MAC, regardless of the frame type.

similarly, non-broadcast frames require the second address field to be the sender's MAC, otherwise the hardware fails to correctly acknowledge the received frame.

BSSID check knows to look for the correct address field based on frame type. requires exact BSSID match, no 'broadcast' BSSID or anything.

bit8=0 causes empty MP replies to not be exposed, but they still count as a valid reply.

management subtype 9 is ignored/can't be sent.

control subtypes B..F are either not sent or ignored.

data subtypes 0 and 4 are always received
data subtypes 1 and 2 are special-cased when in a MP frame (if the destination MAC is one of the MP broadcast MACs)
data subtypes 8..F can't be sent

retransmit detection seems to be based on seqno (and maybe also FC.bit11?).
there's different retransmit handling for MP CMD frames. the hardware seems to keep track of the last CMD-frame seqno specifically, and doesn't seem to be controllable by RXFILTER.bit0.


RXFILTER2

filters data frames based on their FromDS/ToDS bits

* bit0: ignore FC=00x8 (fromSTA/toSTA)
* bit1: ignore FC=01x8 (fromSTA/toDS)
* bit2: ignore FC=02x8 (fromDS/toSTA)
* bit3: ignore FC=03x8 (fromDS/toDS)
* bit4-15 don't exist

bit1=1 causes MP replies not to be exposed, but they still count as a valid reply.
bit2=1 causes a MP client to attempt sending something? but it doesn't seem to send anything valid -- counts as an error on the host side.



ANOTHER NOTE OF INTEREST

when receiving a beacon frame with matching BSSID, USCOUNTER is set to the beacon's timestamp plus an offset

where offset = ((received frame length * 4) - 76) -- (or 8 for a TX rate of 1MB/s)



TO BE REVERSE-ENGINEERED

* is it possible to clear the TXBUF bit15 (or change the register at all) after starting a transfer? YES. FFS. it does weird shit tho.
* the unknown TXBUF bits

____________________
Kuribo64

Arisotura
Posted on 08-31-22 08:32 PM (rev. 6 of 09-02-22 11:04 PM) Link | #5506
NOTES about power/timers/etc

* W_POWER_US does NOT work on DSi!!!!!!
* POWCNT2's wifi bit does work fine, tho. wifi ports and WIFIWAITCNT read as zero. USCOUNT etc stop counting.
* DSi: SCFG_WL has no effect on DS wifi's general operation
* DSi: GPIO_WIFI prolly controls the wifi clock, atleast on DWM-W024 boards
* if clock/power are cut off in the middle of transmit/receive: the hardware just freezes, and resumes operation whenever power/clock are restored. EXCEPTION: on DSi, it doesn't like it if you turn off POWCNT2 while sending (registers work again when turning it back on, but it won't send shit).

* if multiple TX slots are enabled and power-down is engaged: current TX slot is finished first. next ones are discarded (TXBUSY set to 0).

* incoming frames are always received fully before being ignored or anything.

____________________
Kuribo64

Arisotura
Posted on 09-03-22 02:01 PM (rev. 2 of 09-03-22 03:49 PM) Link | #5513
RX status/errors:

* RXSTAT registers are always incremented when receiving something, even if the frame ends up being ignored
* TODO: is there a separate RXSTAT register for when a frame is NOT ignored?

* if the write address reaches or goes past RXBUF_READCSR while incrementing (including wraparound): 'RX buffer full' stat is incremented, packet is aborted

* RXCNT bit15 doesn't completely disable RX (still getting RX-start IRQ, seems to be treated as a RX-buffer-full error)
* RXCNT bit15 also affects TX (impossible to send shit, just does nothing at all)

____________________
Kuribo64

Arisotura
Posted on 09-03-22 05:36 PM Link | #5514
unknown registers:

port 0D8 affects reception of data frames (and maybe more?)

____________________
Kuribo64

Arisotura
Posted on 09-04-22 05:27 PM (rev. 5 of 09-08-22 08:06 AM) Link | #5516
the IEEE duration field:

* transfers via LOCn seem to forcibly set the duration field to zero
* MP reply transfers set the duration field automatically, TODO: figure it out

* when receiving a frame with a nonzero duration value: W_CONTENTFREE is set to the frame's duration field upon IRQ0 or so
(or it is added or something? setting W_CONTENTFREE before IRQ0 causes the value to be different)

* it isn't possible to send shit when W_CONTENTFREE is nonzero -- TODO: investigate this
* attempts at sending will wait for W_CONTENTFREE to be zero
* receiving shit is likely not possible while W_CONTENTFREE is nonzero

* MP-reply frames cannot be received outside of a MP-cmd exchange, apparently

____________________
Kuribo64

Arisotura
Posted on 09-18-22 10:21 PM (rev. 2 of 09-18-22 10:23 PM) Link | #5538
TXBUF_TIM:

register for presumably autofilling the TIM in sent beacons


* TIM structure: https://en.wikipedia.org/wiki/Traffic_indication_map
- element ID (05)
- length (05 or more)
- DTIM count
- DTIM period
- bitmap control (offset/broadcast)
- bitmap: one bit per connected client, for which the host has buffered data waiting


it is likely that the DTIM count is automatically set based on W_LISTENCOUNT or something of that sort.


it is also possible that the bitmap is automatically set by hardware? probably not when using regular TX slots, since it would have no way to tell which client MAC is which ID... but this might make sense during MP comm, where the bitmap could be inferred from the client bitmap in CMD frames (and whether there's a CMD frame waiting to be sent)


clients might also be able to automatically read the TIM from a beacon and react to it?


this overall doesn't seem very important, but prolly useful to power saving and such...

also need to determine the general timings of things, when sending frames is possible or not possible...

____________________
Kuribo64

Arisotura
Posted on 07-25-23 06:20 PM Link | #6109
hey, fun discovery (and might prove useful for betterer wifi, too)

y'know, the body of the MP ack frame

*(u16*)&ack[0xC + 0x18] = 0x0033; // ???
*(u16*)&ack[0xC + 0x1A] = clientfail;

so the second halfword is the bitmask of clients that failed to reply

but the first halfword, the mystery value, I just figured out

it is the CMD_COUNT value at the time the ack is sent (in practice, it tends to be the value observed upon IRQ7 minus 3 or so)

____________________
Kuribo64


Main - Development - wifi notes Hide post layouts | New reply

Page rendered in 0.168 seconds. (2048KB of memory used)
MySQL - queries: 28, rows: 99/99, time: 0.020 seconds.
[powered by Acmlm] Acmlmboard 2.064 (2018-07-20)
© 2005-2008 Acmlm, Xkeeper, blackhole89 et al.