Embedded Developer - Total Phase

Page 6

//////////

•• •• •• •

6

Next, we really started to get fancy. We added more and more fields to the data structure in the script, such as callbacks to validation functions for fields that hold IP addresses. We added callbacks to configuration functions, which trigger whenever certain fields are modified. A similar approach handled security for specific fields and users. Some fields are stored in RAM, others in non-volatile memory, and still others aren’t stored at all, but are actually calculated at run-time. All were covered by the script. By the end of the project, the code generation script was 2,000 lines long, and directly generated 20,000 lines of code across 23 files. Indirectly, the code also feeds into Doxygen, and a tool called Gperf (which we’ll touch on more later), to generate even more code for us. What would have been a maintenance nightmare turned into something more flexible and powerful than originally imagined. The team was free to work on the hard problems, and had the luxury of saying “no problem!” to customer change requests. Finally, by being able to look at a high-level representation of the source code, we were able to spot logic errors early in software development. After solving the problem of storing the data, we moved on to the next challenge. We needed to retrieve that data over multiple network interfaces: Web, Telnet, SNMP, and Modbus. The data lived in a large C struct with 250 members. Each member of the struct held the data for a field. For programming convenience, there were accessor functions to read and write the data. Each (automatically generated) accessor function referenced a struct member, like in the example below:

That worked great for the web application, where we hard-coded references to accessor functions to build up pages. However, we also needed to support Telnet, SNMP and Modbus. Queries on those interfaces originated from users on the network, and could read or write any combination of data fields. To make the problem more complicated, those three network interfaces have very different keys to identify the data fields. The Telnet interface uses a text key, SNMP uses Object Identifiers, or OIDs, and Modbus breaks up the 4-byte IP address field into two 2-byte words, identified by integers. The table below shows the different keys:

Since Modbus keys, called “Registers”, are sequential integers, we simply created an array to map registers to functions. We also used a helper function to convert the various data types into the 2-byte words that Modbus needed. The first parameter to the helper function is the accessor function, and the second is an offset. Our array maps Register 88 to get_modbus_register(get_ WIFI_IP_ADDRESS(), 0) and Register 89 to get_ modbus_register(get_WIFI_IP_ADDRESS(), 1). Of course, that array was another task for our codegeneration script. That left Telnet and SNMP. Clearly, two indexes were needed to return data for those network queries. Indexes are typically built in RAM, but our embedded device has only 128 kilobytes of RAM. Also, indexes require CPU cycles to find the requested data fields. Unfortunately, with our 150 MHz processor, we didn’t have many cycles to spare. A typical implementation was not going to work for this application. We needed a solution that used little or no RAM and as few CPU cycles as possible.


Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.