Click here to Skip to main content
15,886,016 members
Articles / Programming Languages / C

Create Many-to-one Mapping in C

Rate me:
Please Sign up or sign in to vote.
4.67/5 (2 votes)
3 Sep 2016CPOL2 min read 10.2K   2   3
How to create many-to-one mapping in C

We recently ported a device firmware from a platform of very limited hardware resources (32K RAM, 4M NOR) to a more capable one (256M RAM, 256M NAND). The device supports dynamic plugging of different modules with analogy/digital I/O channels on them. It is the time when a module is plugged that device firmware receives an interrupt, and access the module firmware to finish configuration and perform according state machine change.

Due to the limited resources on the old platform, we compile these module firmware (let’s say we support 60+ different modules) separately from the main device firmware. When a module is plugged, we search a linked list on flash to locate the module firmware, and dynamically load it to RAM. Since hardware resources are no longer a worry now, one change we have made to improve performance is to build all module firmware into main device firmware at compile time, and load it to RAM once at system startup. And instead of traversing through the linked list in flash, we need to find the specific function entry point in RAM to call for the plugged module.

We reuse the same C code for each module. The entry point of each module is located in its own source file, e.g., cRIO_9215.c. And some “ME-TOO” modules work in a similar way so they share the same firmware code.

C
// cRIO_921x.c
// Entry point of firmware code shared by modules 9215, 9216.
void cRIO_921x_main(tCartridgeCmd cmd, u8* memory, void* param, tStatus* status)
{
    ..
}

// cRIO_9263.c
// Entry point of firmware code for module 9263.
void cRIO_9263_main(tCartridgeCmd cmd, u8* memory, void* param, tStatus* status)
{
    ..
}

One developer in my team was assigned this task. He came up with something like below, quite a natural one. I bet it’s the first thought for most of us.

screenshot

It works. All I need to do is to go through this 200+ lines of code, and check if there is any module missing or if one is using a wrong handler. Meanwhile, I need to keep my eyes wide open to make sure it is at the right place to “break”.

Frankly I can accept this, if this is a once-for-all change and we will never add new modules in future. Unfortunately, that’s not the case. New module requests keep coming from marketing at almost every release.

So I’d like to come up with a better solution which is more maintainable, and less code to touch when there comes a new module support.

So we created a new solution where a map is created from the module list to their sole handler. A preliminary prototype is given below. A string of 128 characters is used as the key to this map, so it can contain around 20+ modules for a single handler. That’s pretty safe in the near future. If it’s not, then compiler will be happy to throw an error anyway. To add a new module, just add to an appropriate key in the table if it’s “ME-TOO”. Otherwise, append a new line to the table. It’s less likely to make an error, and easier for future reviewers to finish their jobs.

C++
#include <stdio.h>
#include <string.h>

void cRIO9201_main(void) { printf("cRIO9201_main\n"); }
void cRIO9203_main(void) { printf("cRIO9203_main\n"); }
void cRIO9205_main(void) { printf("cRIO9205_main\n"); }
void cRIOParallelDI_main(void) { printf("cRIOParallelDI_main\n"; }

typedef void(tCartridgeARMHandler)(void);
typedef char tModuleList[128];
typedef struct
{
    tModuleList _modules;
    tCartridgeARMHandler *_handler;
}tArmHandlerMap;

// This is the ONLY thing we need to change
// for a new module
static tArmHandlerMap _handlerMap[] =
{
    {"9201, 9221", cRIO9201_main},
    {"9203", cRIO9203_main},
    {"9205, 9206", cRIO9205_main},
    {"9411, 9421, 9422, 9423, 9435, 9436, 9437", cRIOParallelDI_main}
};

tCartridgeARMHandler* getArmHandler(int handlerID)
{
    unsigned int i;
    char id[10];
    // Not so safe, but the variant we have at the moment
    sprintf(id, "%d", handlerID);
    unsigned int count = sizeof(_handlerMap) / sizeof(_handlerMap[0]);
    for (i = 0; i < count; ++i)
    {
        if (strstr(_handlerMap[i]._modules, id))
            return _handlerMap[i]._handler;
    }
    return NULL;
}

int main()
{
    getArmHandler(9201)();
    getArmHandler(9203)();
    getArmHandler(9435)();

    getchar();
    return 0;
}

Image 2 Image 3

This article was originally posted at https://tonywearme.wordpress.com/2016/08/27/__trashed

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead National Instruments
China China
Senior software engineer at National Instruments, to implement various Ethernet-based industrial protocols, e.g., EtherCAT. Favorite languages are C/C++ and Python. For fun, I like watching films (sci-fi, motion), walking, and various reading.

Comments and Discussions

 
Questionss Pin
zhanghao big13-Dec-16 2:47
zhanghao big13-Dec-16 2:47 
Suggestioncheck your code on the website Pin
Maxdaic31-Aug-16 14:49
Maxdaic31-Aug-16 14:49 
GeneralRe: check your code on the website Pin
Eric Z (Jing)31-Aug-16 20:39
Eric Z (Jing)31-Aug-16 20:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.