Lesson 1
provides and uses interfaces
A component provides and uses interfaces.
The provided interfaces are intended to represent the functionality that the component provides to its user in its specification
The used interfaces represent the functionality the component needs to use them to perform its job in its implementation.
Interfaces are bidirectional: they specify a set of commands, which are functions to be implemented by the interface's provider, and a set of events, which are functions to be implemented by the interface's user. For a component to call the commands in an interface, it must implement the events of that interface.
A single component may use or provide multiple interfaces and multiple instances of the same interface.
The set of interfaces which a component provides together with the set of interfaces that a component uses is considered that component's signature.
BlinkC -> MainC.Boot; BlinkC.Timer0 -> Timer0; BlinkC.Timer1 -> Timer1; BlinkC.Timer2 -> Timer2;
= 等号是把提供接口等同于它的实现
-> 箭头是将使用接口与提供实现的接口导通起来, 而=是将提供接口与module中的实现等同起来
Configurations and Modules
Modules provide the implementations of one or more interfaces.
Configurations are used to assemble other components together, connecting interfaces used by components to interfaces provided by others.
Lesson 2
As most mote platforms do not have hardware-based memory protection, there is no separation between a "user" address space and a "system" address space; there is only one address space that all components share. This is why many TinyOS components try to keep their state private and avoid passing pointers: since there is no hardware protection, the best way to keep memory uncorrupted is to share it as little as possible.
Datatype
Rather than the standard C names of int, long, or char, TinyOS code uses more explicit types, which declare their size. In reality, these map to the basic C types, but do so differently for different platforms.
TinyOS code avoids using int, for example, because it is platform-specific. For example, on mica and Telos motes, int is 16 bits, while on the IntelMote2, it is 32 bits.
Additionally, TinyOS code often uses unsigned values heavily, as wrap-arounds to negative numbers can often lead to very unintended consequences. The commonly used types are:
8 bits | 16 bits | 32 bits | 64 bits | |
signed | int8_t | int16_t | int32_t | int64_t |
unsigned | uint8_t | uint16_t | uint32_t | uint64_t |
There is also a bool type. You can use the standard C types, but doing so might raise cross-platform issues. Also, uint32_t is often easier to write than unsigned long.
Most platforms support floating point numbers (float almost always, double sometimes), although their arithmetic is in software rather than hardware.
Interface
Invoking an interface command requires the call keyword, and invoking an interface event requires the signal keyword. BlinkC does not provide any interfaces, so its code does not have any signal statements (也就是说如果provide interface的话,需要用signal来区分它使用interface的event和提供的interface的event。 use interface的event需要加signal)
TinyOS Execution Model: Tasks
So far, all of the examples we've looked at have been direct function calls. System components, such as the boot sequence or timers, signal events to a component, which takes some action (perhaps calling a command) and returns. In most cases, this programming approach works well. Because sync code is non-preemptive, however, this approach does not work well for large computations.
A component needs to be able to split a large computation into smaller parts, which can be executed one at a time. Also, there are times when a component needs to do something, but it's fine to do it a little later. Giving TinyOS the ability to defer the computation until later can let it deal with everything else that's waiting first.
Tasks enable components to perform general-purpose "background" processing in an application. A task is a function which a component tells TinyOS to run later, rather than now. The closest analogies in traditional operating systems are interrupt bottom halves and deferred procedure calls.
A task is declared in your implementation module using the syntax
task void taskname() { ... }
where taskname() is whatever symbolic name you want to assign to the task. Tasks must return void and may not take any arguments. To dispatch a task for (later) execution, use the syntax
post taskname();
The post operation places the task on an internal task queue which is processed in FIFO order. When a task is executed, it runs to completion before the next task is run.
Internal function
Internal functions 没有command or event modifier修饰符
Internal functions act just like C functions: they don't need the call or signal keywords.
Split-Phase Operations
操作分割成 invocation 和 completion 两个阶段。 因为等程序调用一个运行时间很长的操作时, 不会返回除非完成这个操作(造成程序阻塞)。In a split-phase system, when a program calls a long-running operation, the call returns immediately, and the called abstraction issues a callback when it completes.
好处:
- First, split-phase calls do not tie up stack memory while they are executing.
- Second, they keep the system responsive: there is never a situation when an application needs to take an action but all of its threads are tied up in blocking calls.
- Third, it tends to reduce stack utilization, as creating large variables on the stack is rarely necessary.