Wireless Embedded Systems (0120442x) Node Programming
description
Transcript of Wireless Embedded Systems (0120442x) Node Programming
![Page 1: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/1.jpg)
Network Kernel Architectures and Implementation
(01204423)
Node Programming
Chaiporn [email protected]
Department of Computer EngineeringKasetsart University
![Page 2: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/2.jpg)
2
Outline Microcontroller programming
Software development cycle Hardware platforms
IWING-MRF IWING-JN
IWING's MoteLib
![Page 3: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/3.jpg)
3
IWING-MRF MoteRadio
transceiver
8-bit AVR Microcontroller
USB Connector(for
reprogramming and power)
Analog/Digital sensor
connectors
External battery
connector
UART connector
s
Morakot Saravanee, Chaiporn Jaikaeo, 2010. Intelligent Wireless Network Group (IWING), KU
![Page 4: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/4.jpg)
IWING-JN Mote
Analog/Digital sensor
connectorsUART
connectors
Wireless microcontrollermodule with PCB
antenna
![Page 5: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/5.jpg)
5
Microcontrollerflash
memory
BSL
Typical Development Process For microcontrollers with bootstrap
loader (BSL) installedSource code (C/Asm)
Cross Compiler/Assembler
Machine codeSerial/USB
![Page 6: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/6.jpg)
6
Build Simple App Let's build a simple application How to know whether our program is
running? Make mote output something What can be used as output?
![Page 7: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/7.jpg)
7
IWING-MRF Schematic Available on course's homepage
![Page 8: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/8.jpg)
8
IWING-MRF – Blinking LED Task: turn a LED on and off
repeatedly Idea
Configure Port D's Pin 5 (PD5) for output
Repeatedly set the pin logic level to 0 and 1
Add some delay before toggling pin level
![Page 9: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/9.jpg)
9
IWING-MRF C Code – blink.c
How to add delay? Can the code be made shorter?
#include <avr/io.h>
main(){ DDRD |= (1 << 5); // Make PD5 output while (1) { // Set pin logic to low PORTD &= ~(1 << 5);
// Add some delay
// Set pin logic to high PORTD |= (1 << 5); }}
![Page 10: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/10.jpg)
10
Compiling Make an ELF binary by running cross
compiler
Note: blink.elf is not a Windows or Linux executable!
Translate the object file into ihex format
$ avr-gcc -mmcu=atmega328p –o blink.elf blink.c
$ avr-objcopy -j .text -j .data –O ihex blink.elf blink.hex
![Page 11: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/11.jpg)
11
Flashing Code Into Mote Plug mote into a USB port Activate boot-loader
Press and release RESET while holding USER/B.L.
Make sure it is recognized by your PC
Invoke chip programmer$ avrdude -p atmega328p -c usbasp -U flash:w:blink.hex
$ lsusbBus 003 Device 049: ID 16c0:05dc Bus 001 Device 003: ID 046d:c03d Logitech, Inc.
![Page 12: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/12.jpg)
12
IWING-MRF's Boot Loader
![Page 13: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/13.jpg)
13
Creating Makefile
To compile
To download program to flash (will compile if needed)
make
make flash
Tab character
![Page 14: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/14.jpg)
14
IWING's MoteLib
SoftwareHardware
Morakot Saravanee, Patra Poome, Chaiporn Jaikaeo, 2009. Intelligent Wireless Network Group (IWING), KU
![Page 15: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/15.jpg)
15
Hardware Abstraction
IWING-MRF Hardware
IWING-MRF API Implementation
![Page 16: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/16.jpg)
16
Hardware Abstraction
IWING-JN Hardware
IWING-JN API Implementation
![Page 17: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/17.jpg)
17
Mote and Network Emulator
Virtual Mote
![Page 18: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/18.jpg)
18
Programming Model MoteLib provides event-based
programming environment
Idle loop
Radio event handler
Sensor event handler
Timer event handler
Boot event handler
Handled by MoteLib Handled by developer
![Page 19: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/19.jpg)
19
Example Turn red LED on and off repeatedly
every 500 ms#include <motelib/system.h>#include <motelib/led.h>#include <motelib/timer.h>
Timer t;
void fired(Timer *t) { ledToggle(0);}
void boot() { timerCreate(&t); timerStart(&t, TIMER_PERIODIC, 500, fired);}
![Page 20: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/20.jpg)
20
Example: Creating Makefile
# Platform to build the code forPLATFORM = iwing-mrf
# Required target without extensionTARGET = blink
# Include MoteLib's main make rulesinclude $(MOTELIB_DIR)/Makerules
![Page 21: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/21.jpg)
21
Example: Build and Flash App Build your application
Program the mote with
make
make flash
![Page 22: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/22.jpg)
22
MoteLib API Residing in $(MOTELIB_DIR)/include
motelib/system.h motelib/led.h motelib/timer.h motelib/button.h motelib/sensor.h motelib/actor.h motelib/radio.h motelib/uart.h
Complete API documentation can be found here http://www.cpe.ku.ac.th/~cpj/motelib/
![Page 23: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/23.jpg)
23
System API (motelib/system.h) Provides boot() function signature Provides various function
declarations for node ID and network ID inquiry
Should be included in every MoteLib application
![Page 24: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/24.jpg)
24
LED API (motelib/led.h) Turn LED#2 on
Turn LED#1 off
Toggle LED#0
Use LEDs to display binary value
ledSet(2,1);
ledSet(1,0);
ledToggle(0);
ledSetValue(5);
![Page 25: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/25.jpg)
25
Timer API (motelib/timer.h) Define and initialize a timer
Start the timer with 1-second timeout; trigger only once; call function fired when triggered
Start the timer with 1-second timeout; trigger periodically
Timer t;timerCreate(&t);
timerStart(&t, TIMER_ONESHOT, 1000, fired);
timerStart(&t, TIMER_PERIODIC, 1000, fired);
![Page 26: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/26.jpg)
26
Timer API (cont'd) Defining callback
void fired(Timer *t){ // do something}
![Page 27: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/27.jpg)
27
Button API (motelib/button.h) Set handler to monitor button event
Usually called in boot()
Handler example
buttonSetHandler(handler);
void handler(ButtonStatus s){ if (s == BUTTON_PRESSED) // do something if (s == BUTTON_RELEASED) // do something}
![Page 28: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/28.jpg)
28
Programming Practice button-count.c
Counts how many times the USER button has been pressed
Then shows the number (only 3 LSBs) on the LEDs
Count to 7 and wrap around to 0
![Page 29: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/29.jpg)
29
Sensor API (motelib/sensor.h) Read digital input from input#0
Request analog reading (asynchronous) from input#3
uint16_t x = sensorReadDigital(SENSOR_0);
sensorRequestAnalog(SENSOR_3, dataReady);:
void dataReady(uint16_t value){ // value stores sensor reading}
![Page 30: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/30.jpg)
30
Actor API (motelib/actor.h) Activate output #2 (set logic to High)
Deactivate output #3 (set logic to Low)
actorSetState(ACTOR_2,1);
actorSetState(ACTOR_3,0);
![Page 31: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/31.jpg)
31
Measures light and temperature
Sensor Board
Sensor Power Supply
Light Sensor
Temperature Sensor
![Page 32: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/32.jpg)
32
IWING-MRF Schematic
![Page 33: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/33.jpg)
33
IWING-JN Schematic
![Page 34: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/34.jpg)
34
Sensor Reading Procedure Step 1: Turn on sensor power Step 2: Request analog reading Step 3: Wait until value is available Step 4: Turn off sensor power
![Page 35: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/35.jpg)
Split-Phase Operations
Request
Data
Blocking
SensorController
Synchronous Operation Asynchronous Operation
SensorController
Request
Ready
Ack
Read
Data
![Page 36: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/36.jpg)
36
Example: sense-light.c Every 100 ms, measure light and
display the value on LEDs Light value is in range 0 – 1023 Need to scale down to 0 – 7
![Page 37: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/37.jpg)
37
Example#include <motelib/system.h>#include <motelib/led.h>#include <motelib/timer.h>#include <motelib/sensor.h>#include <motelib/actor.h>
Timer t;
void readDone(uint16_t value);void readLight(Timer *t);
void boot(){ timerCreate(&t); timerStart(&t, TIMER_PERIODIC, 100, readLight);}
void readLight(Timer *t){ actorSetState(ACTOR_0, 1); sensorRequestAnalog(SENSOR_1, readDone);}
void readDone(uint16_t value){ ledSetValue(value/128); actorSetState(ACTOR_0, 0);}
![Page 38: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/38.jpg)
38
Programming Practice Modify sense-light.c so that light
is sampled 4 times in each measurement Average value is displayed on LEDs
![Page 39: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/39.jpg)
39
Creating a Reading Task Event-based code
can be difficult to read and maintain
Idea Make a reading
task that runs forever
Other tasks can also be added to run concurrently
Start timer
Wait until timer expired
Create timer
Turn on sensors
Request reading
Wait until data ready
Complete 4 samples?
Compute and display average
Turn off sensors
![Page 40: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/40.jpg)
40
Synchronous Operations MoteLib provides various checks to
support synchronous operation E.g.,
timerExpired(t) Determines whether timer t has already
expired Only works for one-shot timer
sensorAnalogWaiting(s) Returns true if the system still waits for
sensor s sensorAnalogResult(s)
Returns the most recent value of sensor s
![Page 41: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/41.jpg)
41
First Attempt#include <motelib/system.h>#include <motelib/led.h>#include <motelib/timer.h>#include <motelib/sensor.h>#include <motelib/actor.h>
Timer t;void readLightTask();
void boot(){ readLightTask();}
void readLightTask(){ uint8_t i; uint16_t sum = 0;
timerCreate(&t);
while (1) { timerStart(&t, TIMER_ONESHOT, 100, NULL); while (!timerExpired(&t)) ; actorSetState(ACTOR_0, 1); for (i = 0; i < 4; i++) { sensorRequestAnalog(SENSOR_1, NULL); while (sensorAnalogWaiting(SENSOR_1)) ; sum += sensorAnalogResult(SENSOR_1); } ledSetValue(sum/4/128); actorSetState(ACTOR_0, 0); }}
Will this work?
![Page 42: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/42.jpg)
42
Problem with Event-based Model
Threads: sequential code flowEvents: unstructured code flow
Very much like programming with GOTOs
![Page 43: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/43.jpg)
43
Events Require One Stack Four event handlers, one stack
Eventhandler 1Eventhandler 2Eventhandler 3
Stack is reused for every event handler
Eventhandler 4
![Page 44: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/44.jpg)
44
Problem with Multithreading Four threads, each with its own stack
Thread 1 Thread 2 Thread 3 Thread 4
![Page 45: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/45.jpg)
45
Emulating Concurrency Previous example wouldn't work
because of the blocking while-loop Other parts of the system will be
unresponsive Must return to MoteLib inside of the
while-loops During MoteLib's idle loop, keep
jumping into the while-loops
![Page 46: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/46.jpg)
46
Coroutines Generalized subroutines
Allow multiple entry points for suspending and resuming execution at certain locations
Can be used to implement: Cooperative multitasking Actor model of concurrency
![Page 47: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/47.jpg)
47
Routine 2
Subroutines vs. Coroutines
Routine 1
Subroutines
Routine 2Routine 1
Coroutines
call
call
returnreturn
yield yield
yield
yield
“Subroutines are a special case of coroutines.”--Donald Knuth
Fundamental Algorithms. The Art of Computer Programming
![Page 48: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/48.jpg)
48
Programming Model
MoteLib'sIdle loop
Task 2
Event handler2
Task 1
Event handler1
Handled by MoteLib Handled by developer
call
returncall
returncontinue
yield
yield
continue
![Page 49: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/49.jpg)
49
Implementation Details How to ask MoteLib to call our tasks?
MoteLib provides setLoopRoutine(), allowing a function to be called every idle loop
How to have a task yield and correctly come back to where it left?
void myroutine() { // something to be executed continuously}
void boot() { : setLoopRoutine(myroutine);}
![Page 50: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/50.jpg)
50
Implementing Continuation Each coroutine must be able to
continue from where it last yieldedRoutine 1
MainLoop
continue
yield
continue
yield
![Page 51: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/51.jpg)
51
Duff's Device Invented to optimize data transfer by
means of loop unwinding Switch cases are used like GOTO
labelsdo { *to = *from++;} while(--count > 0);
register n = (count + 7) / 8;switch(count % 8) {case 0: do { *to = *from++;case 7: *to = *from++;case 6: *to = *from++;case 5: *to = *from++;case 4: *to = *from++;case 3: *to = *from++;case 2: *to = *from++;case 1: *to = *from++; } while(--n > 0);}
![Page 52: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/52.jpg)
52
Protothreads Invented by Adam Dunkels and Oliver
Schmidt Used in the Contiki OS
Provides light-weight mechanism for concurrent programming using standard C macros and switch-case statements
Heavily inspired by Duff's Device and Simon Tatham's Coroutines in C
See http://dunkels.com/adam/pt/expansion.
html
![Page 53: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/53.jpg)
53
Protothreads Protothreads require only one stack E.g, four protothreads, each with its own
stack
Events require one stack
Protothread 1Protothread 2Protothread 3Protothread 4
Just like events
![Page 54: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/54.jpg)
54
Six-line implementation Protothreads implemented using the
C switch statement Heavily inspired by Duff's Device and
Simon Tatham's Coroutines in Cstruct pt { unsigned short lc; };
#define PT_INIT(pt) pt->lc = 0
#define PT_BEGIN(pt) switch(pt->lc) { case 0:
#define PT_EXIT(pt) pt->lc = 0; return 2
#define PT_WAIT_UNTIL(pt, c) pt->lc = __LINE__; case __LINE__: \
if(!(c)) return 0
#define PT_END(pt) } pt->lc = 0; return 1
![Page 55: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/55.jpg)
55
Revised sense-light.c//////////////////////////////PT_THREAD(readLightTask(struct pt *pt)){ static uint8_t i; static uint16_t sum = 0;
PT_BEGIN(pt);
timerCreate(&t);
while (1) { timerStart(&t, TIMER_ONESHOT, 100, NULL); PT_WAIT_UNTIL(pt, timerExpired(&t)); actorSetState(ACTOR_0, 1); for (i = 0; i < 4; i++) { sensorRequestAnalog(SENSOR_1, NULL); PT_WAIT_WHILE(pt, sensorAnalogWaiting(SENSOR_1)); sum += sensorAnalogResult(SENSOR_1); } ledSetValue(sum/4/128); actorSetState(ACTOR_0, 0); }
PT_END(pt);}
#include <motelib/system.h>#include <motelib/led.h>#include <motelib/timer.h>#include <motelib/sensor.h>#include <motelib/actor.h>#include <pt/pt.h>
struct pt readLight_pt;PT_THREAD(readLightTask(struct pt *pt));Timer t;
//////////////////////////////void scheduleTasks(){ readLightTask(&readLight_pt);}
//////////////////////////////void boot(){ setLoopRoutine(scheduleTasks);}
![Page 56: Wireless Embedded Systems (0120442x) Node Programming](https://reader035.fdocuments.in/reader035/viewer/2022062310/568164cd550346895dd6f2a6/html5/thumbnails/56.jpg)
56
Protothreads Limitations Local variables must be manually
preserved Local variables are created on stack They are destroyed when function
returns So they should be stored in an explicit
state object Or declared static, if reentrancy is not
required switch-case statements are not
allowed Cannot take advantage of multi-
processing