M.C.S hrijver
m. .s hrijverstudent.utwente.nl
ABSTRACT
In wireless sensor networking dynamic reconfiguration is important since it’s impractical to reprogram each node by hand because of their numbers and possible deployment in remote locations. This paper presents a method for loading modules into and unloading modules from the AmbientRT operating system. This is done while trying to preserve memory but without exhausting the FLASH memory. We will give an overview of the desired and real properties of the module loading and unloading and describe how loading and unloading is done.
Keywords
dynamic reconfiguration wireless sensor nodes
1. BACKGROUNDANDSIGNIFICANCE
In order to make optimal use of a deployed wireless sensor node it is desirable to be able to reconfigure it in-network without requiring physical interaction with the node. This will allow users to propagate bug fixes, have multiple uses for the same network or add net features at a later stage.
In most real-life applications it is not feasible to have physical interaction with each node because of the number of nodes and the fact that deployment of sensor nodes makes sense in environments which are otherwise hard to monitor. Examples of such applications are under the ocean [AMS06], extraterrestrial surfaces [HJL
+03] or on the battlefield [AWSC02].
2. PLATFORM
AmbientRT is an operating system targeted at wireless sensor nodes. It currently runs on so called uNodes, a WSN platform developed by Ambient Systems. These are small boards with a MSP430 microcontroller, a radio transceiver and optionally a serial port controller. A toolset for creating modules already existed but it was not possible to actually load these modules into a running kernel.
Permissiontomakedigitalorhard opiesofallorpartofthisworkfor
personalor lassroomuseisgrantedwithoutfeeprovidedthat opiesare
notmadeordistributedforprotor ommer ialadvantageandthat opies
bearthisnoti eandthefull itationontherstpage.To opyotherwise,or
republish,topostonserversortoredistributetolists,requirespriorspe i
permission.
6th Twente Student Conference on IT , Enschede 2th February, 2007
Copyright2007,UniversityofTwente,Fa ultyofEle tri alEngineering,
A node configuration consists of a set of tasks that have been predetermined to be runnable simultaneously. The process of determining this is an NP-hard problem and therefore very inconvenient to run on the (fairly slow) node itself.
Determining the feasibility of such a schedule is described in [CSB90]. Basically it involves taking a worst-case scenario where all tasks are triggered and adding up their maximum running time to see if this is within the capabilities of the CPU.
3. RELATEDWORK
This practical implementation of the proposed reconfigura- tion system builds on the AmbientRT operating system.
In AmbientRT a hard real-time scheduler is used. This scheduler manages a set of tasks which can subscribe to certain events, when one of these events is triggered the scheduler has a certain deadline period in which it must ensure the task has been executed in order to meet the hard real-time requirement. Because a task can trigger a new event itself by passing new data to a datastream, any event can trigger a large number of tasks. All tasks consist of one block of code, the events they subscribe to, their maximum execution time and their deadline periods. The feasibility of a combination of tasks is determined by checking the worst possible scenario in terms of events triggering and adding up the maximum execution time of the tasks. If this sum exceeds the available CPU cycles the ”configuration” is not deemed feasible. For a more complete description of these schedulers we refer the reader to [CSB90] and [HDJH04].
4. DEFINITIONS
In order to effectively describe the components of possible solutions a number of definitions are introduced here:
4.1 Conguration
A configuration in this context is a set of tasks which are to be loaded. Such a configuration is known to be runnable on the node.
4.2 Task
A block of code which can have subscriptions to certain
data types, generate events on certain data types and has
a list of resources it depends on. The task has three types
of dependencies, dependencies on hardware resources such
as the serial port, dependencies on data types and the at
runtime constructed dependencies on other tasks. This last
dependency list is built by checking for overlaps in resource
or data type dependencies with all other tasks.
In the context of the AmbientRT operating system a data type is a type of event sink to which certain tasks subscribe while other tasks publish data to them. System events such as timers expiring, the serial port becoming readable or the radio receiving a packet are also published through these data types. A more complete description can be found in [CSB90] or [HDJH04].
4.4 Wirelesssensornode
In this paper this refers to a uNode running AmbientRT.
While this ofcourse is by no means the only type of WSN, we used this for convenience. The uNode version used by the author is a MSP430 microcontroller equipped with 10 kilobytes of RAM, 48 kilobytes of FLASH and 2 megabits of EEPROM.
4.5 Heapspa e
In AmbientRT the heap is realized as a region of RAM memory with allocations and free space tracked by a linked list in the heap itself. This type of memory management is prone to memory fragmentation since a deallocated piece memory can get ”caught” in between two allocated pieces of memory. Moving around these allocated pieces of memory is not an option since we do not know where pointers to it are stored.
5. RESEARCHGOAL
Develop a method to load new tasks into AmbientRT and unload them afterwards. In order to achieve this first will be defined what a module consists of, next which kernel structures are to be modified and that will be implemented as a proof of concept. This does not solve the solve the problem of dynamic reconfiguration as a whole, but as over the air file transfer has already been implemented integration of those two components will.
6. FEASIBILITYCONSTRAINTS
The loading and unloading of modules should fragment the heap as little as possible. Heap space on the node is very limited, only 10 kilobytes on the current model and just 2 kilobytes on the older model.
Limited lifespan of the flash storage. Specifications for the flash storage show that it will minimally allow for 10,000 rewrite cycles and nominally 100,000 cycles [Texa]. Erase cycles are triggered when a 0 bit has to be changed into a 1 bit, from the MSP430 manual: ”The erased level of a flash memory bit is 1. Each bit can be programmed from 1 to 0 individually but to reprogram from 0 to 1 requires an erase cycle. The smallest amount of flash that can be erased is a segment.” [Texb]. While this may seem like an reasonable amount of rewriting cycles it does not allow the flash memory to be used as a working area. As such writing to the flash memory should be kept to a minimum and be used once structures are ready to be stored for a longer period. This constraint should be observed when loading modules from EEPROM to flash, modules should not always be unloaded since they may be needed later on.
To minimize writing when loading modules the flash memory is not cleared during reconfiguration and the OS keeps
Table 1: Module header magic identifier, contains ”DCLM”
ID name of the task version version of the task
code offset pointer to the code segment in the module file
code size size of the code segment
entrypoint where to start execution upon activation data offset offset to the data segment
data size size of the data segment reloc offset offset to the relocation table bss size size of the heap
datacount number of data types subcount number of subscriptions datalist offset to the data types list
dataspec offset to the data type dependency list resources offset to the resource list
subscribe offset to the subscription table
timers array of 4 timer values used to set the short timers
period upper bound for the frequency at which the task can be activated
deadline maximum period before execution after activation
cputime upper bound on the task execution time
track of which modules are loaded where. When a module is unloaded the memory allocated to is not immediately deallocated.
7. MODULES
In order to dynamically reconfigure the uNode we use modules. These modules contain one task. An overview of the module header structure is given in 1.
Modules are created using the msparse and the smelf tool.
The msparse tool parses the module description file, this file contains the scheduling properties (period, deadline and cputime), subscriptions to data types, dependencies on resources and any timers that need to be set. This information is written to a C source file which is compiled with the module sources. The smelf tool is used to process the resulting ELF file, it extracts the information generated by msparse to generate the module and determine code and data segment information from ELF headers. These tools were already included in the AmbientRT operating system.
To make the code loadable to any offset in the uNode’s memory there is a relocation table. This table is used to patch any absolute offsets within the code or data segment.
8. TECHNICALREALIZATION
The EDFI scheduler in AmbientRT has three datastructures which must be modified to load or unload tasks:
• Tasklist
• Datatype subscriber list
• Task dependencies
Timer1 ofs=1 sz=2
Serial ofs=3 sz=1
Timer0 ofs=0 sz=1 Task0
Task0 Task1 Task2
Datatypes Subscriber list
Figure 1: Data types and subscribers.
• Task deltas
Since the task list is stored as a fixed size array in flash memory on initial AmbientRT startup it has to be moved someplace else before or in the process of modification. Also since the other datastructures maintain indices into the tasklist care has to be taken that these indices are updated if a task is moved to a different place in the tasklist. This occurs when tasks are unloaded.
For each data type a list of subscribers is maintained. All the subscriptions are stored in one array, each data type has an offset into this array and a number of subscriptions.
These subscription list are used by the datamanager to see which tasks need activation when a data type is triggered, an example is shown in figure 1.
The task dependencies are used by the scheduler to deter- mine in which order tasks are to be executed. From these dependencies task deltas are generated which describe the maximum time difference between execution of tasks.
For both loading and unloading interrupts are disabled. If an interrupt would occur, this could trigger a data type.
This would in turn activate the scheduler while the task loader/unloader is still changing scheduler structures. At this point the structures obviously are in an inconsistent state and having them used by the scheduler is a bad thing.
This fact unfortunately breaks the real-time property, but it would not be trivial to resolve. The proper alternative would be to run the loader/unloader as regular task which is more difficult for two reasons:
• Being invoked from the scheduler itself the loader would return the scheduler structures differently, chang- ing these structures requires ”resetting” the scheduler.
• The upper bound on the execution time is not fixed since it depends on the number of already loaded tasks.
The high resulting maximum execution time would prevent it from running in most configurations.
Per module task a small memory zone is kept, this is used to store task local structures and is intended to minimize memory fragmentation due to the fairly large amount of
TASK01
Zone memory Task
resource dependencies datatype dependecies task dependencies task id
Figure 2: Zone memory.
small allocations that would be needed otherwise. Another advantage is that all memory can be released in one single deallocation meaning less chance of leaking memory. See 2 for an illustration.
8.1 Loading
To load a new task the following steps are taken:
• Load code body into flash memory.
• Allocate a fixed size ”zone” to allocate memory from for small task related structures.
• Create a new task list by copying the old tasklist and adding the new task.
• Create a new data types list, again by copying the old one and adding any new data types from the loaded task.
• Iterate across all other tasks checking for dependencies.
• Recalculate scheduler deltas.
• Set timers configured in module.
• Return control to the slack scheduler
In order to load a module the OS RC Load Module syscall, this syscall checks if the module actually exists and if so schedules the actual loader into slacktime. A new entry into the module array is allocated, this entry is initialized with a pointer to a 100 byte memory zone which is used for module specific structures. A allocator is chosen to prevent memory fragmentation because of the many small bits of memory needed for these structures. The loader loads the code into FLASH memory and patches the relocations into it. Memory for a new task list is allocated from the heap, the old task list is copied to it and a pointer to the new task entry at the end of the new task list is stored for further use.
If the old task list is located inside the kernel data segment
it is left as is, if not the heap space used by it is freed. In a
similar fashion the new data type list and the subscription
table are constructed, first copying the existing data types
and subscriptions and then adding any new entries from
the module. After this the dependency lists for the task
To be removed
0 1 2 3 4 5 6
1 2 6
Task depencies Builtin tasks
Module tasks
Figure 3: Remapping indices.
are constructed, this is done by searching the data type and resource dependency lists of all other tasks and if they depend on a resource or data type used by the newly loaded module add them to the dependency list. After this any timers requested by the module are set and the scheduler is told to recalculate the deltas.
8.2 Unloading
• Create a new task list by copying the old task list but omitting the task to be removed.
• Recreate the subscriber list omitting any references to the task just removed and decreasing indices to tasks with a task index higher than the task just removed by one.
• Similarly walk through the dependency lists updating task indices, however if a reference to the task just removed there most likely is something wrong. There is another task that expects input from the task just removed. While we can fix the reference this does mean the application unloading the module has broken another module by depriving it of it’s input.
• Free the memory zone allocated to the task.
• Recalculate scheduler deltas.
• Remove the task from the loaded modules list.
The initial part of unloading is fairly similar to loading, a new task list is allocated only with one task entry less and the old task list is copied there excluding the to be removed module task. After this the subscriber list is fixed, any entries pointing to the removed task have to be removed as well and any entries pointing to indices above the removed task are to be decreased by one. This is necessary since for all tasks ”above” the removed task the indices have changed.
A similar thing is done for the task dependencies, but only for the other module tasks. This is shown in figure 3, once task number 5 is removed task 6 will become the new task with index 5 but the task dependency list of task 4 still has a reference to task index 6. Then the only thing left is to free the zone memory and remove the module from the loaded module list.
8.3 Testing
In order to test the loader/unloader two modules are written. These are blue.dlm and red.dlm, which - very surprisingly - respectively flash the blue and the red led.
These modules are used to test loading one module, loading two modules, unloading one module which is not the last one in the task list and unloading both modules. In order to upload the modules a small tool was developed that transfers files to the uNodes’ filesystem using the serial port.
To control loading and unloading of the modules the shell was extended with commands to list the filesystem, load a module, unload a module and show the list of loaded modules.
9. CONCLUSION
A method was presented to load and unload modules on the AmbientRT operating system. Several choices have been made with respect to how memory should be used where the focus was put on using RAM for the more volatile structure to avoid straining the FLASH memory and the more static elements being loaded to FLASH memory.
The largest problem implementing the loader and unloader was the total lack of debugging facilities. Especially when modifying scheduler structures it was to hard determine what went wrong. Those modifications are very prone to crashing or freezing the entire uNode resulting in no output and a lot of guess work to find out what happened.
9.1 Futurework
The flash memory management is somewhat naive, unload- ing the largest module is not the best choice by any means.
It is not unthinkable that this large module is required in most of the configurations and thus unloading it is a bad thing. Better strategies would require knowledge of all the configurations that are likely to be used on a given node and use this to not just unload the largest but also try to find one which isn’t likely to be used in the future.
This implementation doesn’t provide persistency of config- uration across reboots. This could easily be achieved by keeping track of the currently loaded modules in EEPROM and load those modules upon booting.
10. ACKNOWLEDGEMENTS
The author would like to thank Stefan Octavian Dulman for providing me with this assignment, Tjerk Hofmeijer for helping me with my questions on AmbientRT and Ambient Systems for providing a hardware platform to test code on.
REFERENCES