wiki:802.11/wlan_exp/app_notes/tutorial_token_mac/CPU_HIGH

Alterations to CPU_HIGH

In this section, we will describe and discuss the changes needed to the high-level MAC code to realize the design. The main concept of TokenMAC is that the token should rotate among members of the network. This inherently requires knowledge of the membership of the network so that that it can be determined who should be given the token and for how long they should have it. In the 802.11 Reference Design, knowledge of network membership (or "association") belongs to the AP. As such, the AP project is well-suited to being modified with the behavior of managing token passing. In a sense, the AP becomes a sort of "traffic cop" and halts traffic from certain associations while enabling traffic to others.

Additionally, we will need to make some small changes to the MAC High Framework to deal with some new inter-processor communication (IPC) messages with CPU_LOW.

Specific Changes

Code Common to CPU_HIGH and CPU_LOW

Changes should be made to wlan_mac_ipc_util.h in the project SDK workspace zip.


We need to define two new types of IPC messages between CPU_LOW and CPU_HIGH. The first, which we will call TOKEN_NEW_RESERVATION, will primarily be used by an AP when it decrees that a token reservation period now belongs to one of the devices on its network. The second, which we will call TOKEN_END_RESERVATION, will primarily be used by an AP's CPU_LOW project to indicate to the AP that the current reservation period has ended and it should move on to the next device in its association table. Add the following snippet of code to wlan_mac_ipc_util.h:

#define IPC_MBOX_TOKEN_NEW_RESERVATION  20
#define IPC_MBOX_TOKEN_END_RESERVATION  21

typedef struct{
    u32 res_duration;
    u8  addr[6];
    u16 reserved;
} ipc_token_new_reservation;

typedef enum {TOKEN_DURATION_COMPLETE, TOKEN_TIMEOUT, TOKEN_OFFER_REJECTION} token_end_reservation_reason_t;

typedef struct{
    token_end_reservation_reason_t reason;
} ipc_token_end_reservation;

The values of 20 and 21 are arbitrary. The key part is that you choose numbers that do not overlap with any of the other definitions that are prepended by IPC_MBOX_. It is these definitions that the processors use to determine what type of IPC message is currently being received. Next, ipc_token_new_reservation and ipc_token_end_reservation are structs that we will use to more easily fill in and process IPC payloads.


Access Point (AP)

Changes should be made to wlan_mac_ap.c in the project SDK workspace zip.


We need to create a function that, when called, knows how to issue a new token for a reservation period to a device on the network. Note: the AP itself needs to be able to transmit, so it should include itself as one of the devices that get issued a token. Add the following function to the AP code:

void set_new_reservation(){

#define DEFAULT_RESERVATION_DURATION_USEC 20000

    interrupt_state_t curr_interrupt_state;

    static dl_entry* next_station_info_entry = NULL;
    dl_entry* curr_station_info_entry;

    station_info* curr_station_info;

    wlan_ipc_msg       ipc_msg_to_low;
    ipc_token_new_reservation ipc_payload;

    ipc_msg_to_low.msg_id            = IPC_MBOX_MSG_ID(IPC_MBOX_TOKEN_NEW_RESERVATION);

    //The below chunk of code is just to make sure that we pad an extra u32 word if the
    //ipc_token_new_reservation struct is not 32-bit aligned.
    if( (sizeof(u32)*(sizeof(ipc_token_new_reservation)/sizeof(u32))) ==  sizeof(ipc_token_new_reservation) ){
        ipc_msg_to_low.num_payload_words = (sizeof(ipc_token_new_reservation)/sizeof(u32));
    } else {
        ipc_msg_to_low.num_payload_words = (sizeof(ipc_token_new_reservation)/sizeof(u32)) + 1;
    }

    ipc_msg_to_low.payload_ptr       = (u32*)(&ipc_payload);

    //For safety, we will go ahead and disable interrupts while we are processing this function. This function
    //iterates through the doubly-linked list of associated stations. If that list were to be modified by an interrupt
    //context while this function is running, there may be unexpected results. By disabling interrupts, we know
    //that we can trust the doubly-linked list for this entire function context
    curr_interrupt_state = wlan_mac_high_interrupt_stop();

    curr_station_info_entry = next_station_info_entry;

    // Loop through all associated stations
    if(curr_station_info_entry == NULL){
        // It's the AP's reservation
        next_station_info_entry = my_bss_info->associated_stations.first;

        //SEND IPC for AP

        memcpy( ipc_payload.addr, my_bss_info->bssid, 6 );
        ipc_payload.res_duration = DEFAULT_RESERVATION_DURATION_USEC;
        ipc_mailbox_write_msg(&ipc_msg_to_low);

        curr_station_info_entry = next_station_info_entry;

    } else {
        // It's a STA's reservation
        curr_station_info = (station_info*)(curr_station_info_entry->data);
        if( wlan_mac_high_is_valid_association(&my_bss_info->associated_stations, curr_station_info) ){
            if(curr_station_info_entry == my_bss_info->associated_stations.last){
                // We've reached the end of the table, so we wrap around to the beginning
                next_station_info_entry = NULL;
            } else {
                next_station_info_entry = dl_entry_next(curr_station_info_entry);
            }

            //SEND IPC for curr_station_info

            memcpy( ipc_payload.addr, curr_station_info->addr, 6 );
            ipc_payload.res_duration = DEFAULT_RESERVATION_DURATION_USEC;
            ipc_mailbox_write_msg(&ipc_msg_to_low);

            curr_station_info_entry = next_station_info_entry;

        } else {
            // This curr_station_info is invalid. Perhaps it was removed from
            // the association table
            next_station_info_entry = NULL;
        } // END if(is_valid_association)
    }

    wlan_mac_high_interrupt_restore_state(curr_interrupt_state);

}

Take a minute and read through what that code snippet is doing. Every time it is called, it will move on to the next member of the association table doubly-linked list and send an IPC message to CPU_LOW indicating the address of that member along with a duration of time the token reservation for that member should last. The #define for DEFAULT_RESERVATION_DURATION_USEC indicates this duration. After every loop through of the association table, it will issue an IPC message to CPU_LOW using its own BSSID as the address in the IPC payload. This indicates that the medium is now reserved for the AP itself.


The next thing we need to do is figure out when we should call our new set_new_reservation() function. We should definitely call it once at boot in main() to get the process started (at which point, no stations will be associated and that function would simply formally start the first token reservation period for the AP). But when should we call it next? We should call it whenever the current reservation period is complete. We'd expect this time to come DEFAULT_RESERVATION_DURATION_USEC microseconds after the previous call, so we could set up a periodic schedule and call our function at regular intervals. However, its entirely possible that a station is unable to accept a token for a reservation period, so we may wish to terminate the current reservation period early and move on to the next station's reservation. The AP itself has no idea when this even occurs since it is within the domain of CPU_LOW. So, rather than worry about scheduling the next call of set_new_reservation(), we can instead teach the MAC High Framework how to call that function when it receives an IPC message from CPU_LOW indicating that the current reservation period is over. We'll do this with a simple function callback. Add the following two lines to the main() function of the AP:

    wlan_mac_high_set_token_new_reservation_callback((function_ptr_t)set_new_reservation);
    set_new_reservation();

The safest place to add these lines is just before the while(1) clause at the end of the main() function. wlan_mac_high_set_token_new_reservation_callback does not exist yet; we will add it in the next section with our changes to the MAC High Framework. Basically, this line of code lets the AP delegate responsibility for calling set_new_reservation to the MAC High Framework.


MAC High Framework

Changes should be made to wlan_mac_high.c in the project SDK workspace zip.


The first thing we need to do implement the callback structure that we assumed in our AP modifications. First, we should add a new top-level global to wlan_mac_high.c at the top of the file:

volatile function_ptr_t      token_new_reservation_callback;

This variable will serve to hold the pointer to a function that should be called when the framework wants the AP to issue a new token reservation. For safety, we should explicitly set this function pointer to the nullCallback at boot so calling this function pointer does not crash the CPU. To do this, add the following line to wlan_mac_high_init():

token_new_reservation_callback = (function_ptr_t)nullCallback;

Finally, we should create a function that allows the AP code (or whatever other high-level project) assign the new callback. Add this function to the MAC High Framework:

void wlan_mac_high_set_token_new_reservation_callback(function_ptr_t callback){
    token_new_reservation_callback = callback;
}

We have now implemented the wlan_mac_high_set_token_new_reservation_callback() function that we called in our AP modifications.


Finally, we need to actually call the token_new_reservation_callback() function pointer. We need to establish a contract with CPU_LOW. Specifically, we will assume that every time the AP sends down a TOKEN_NEW_RESERVATION IPC message to CPU_LOW, there will be a response of a TOKEN_END_RESERVATION IPC message at some point after that event. In other words, CPU_HIGH will not be responsible for determining when any given reservation period is over. We will assume CPU_LOW will tell CPU_HIGH when a new token reservation period should be issued. As such, we just need to call token_new_reservation_callback() whenever we get a TOKEN_END_RESERVATION IPC message from CPU_LOW. This is an easy modification to make. In wlan_mac_high_process_ipc_msg(), there is a big switch statement that handled every type of IPC message ID. All we need to do as add new cases to this switch:

        case IPC_MBOX_TOKEN_NEW_RESERVATION:
            // Do nothing - To remove warning about "Unknown IPC message type"
        break;

        case IPC_MBOX_TOKEN_END_RESERVATION:
            token_new_reservation_callback();
        break;


Last modified 5 years ago Last modified on Feb 4, 2016, 11:02:14 AM