diff --git a/doc/example-packet-drv.c b/doc/example-packet-drv.c new file mode 100644 index 000000000..0c617ccc2 --- /dev/null +++ b/doc/example-packet-drv.c @@ -0,0 +1,138 @@ +/* + * This is an example of how to write a network device driver ("packet + * driver") for Contiki. A packet driver is a regular Contiki process + * that does two things: + * # Checks for incoming packets and delivers those to the TCP/IP stack + * # Provides an output function that transmits packets + * + * The output function is registered with the Contiki TCP/IP stack, + * whereas incoming packets must be checked inside a Contiki process. + * We use the same process for checking for incoming packets and for + * registering the output function. + */ + +/* + * We include the "contiki-net.h" file to get all the network functions. + */ +#include "contiki-net.h" + +/*---------------------------------------------------------------------------*/ +/* + * We declare the process that we use to register with the TCP/IP stack, + * and to check for incoming packets. + */ +PROCESS(example_packet_driver_process, "Example packet driver process"); +/*---------------------------------------------------------------------------*/ +/* + * Next, we define the function that transmits packets. This function + * is called from the TCP/IP stack when a packet is to be transmitted. + * The packet is located in the uip_buf[] buffer, and the length of the + * packet is in the uip_len variable. + */ +u8_t +example_packet_driver_output(void) +{ + let_the_hardware_send_the_packet(uip_buf, uip_len); +} +/*---------------------------------------------------------------------------*/ +/* + * This is the poll handler function in the process below. This poll + * handler function checks for incoming packets and delivers them to + * the TCP/IP stack. + */ +static void +pollhandler(void) +{ + /* + * We assume that we have some hardware device that notifies us when + * a new packet has arrived. We also assume that we have a function + * that pulls out the new packet (here called + * check_and_copy_packet()) and puts it in the uip_buf[] buffer. The + * function returns the length of the incoming packet, and we store + * it in the global uip_len variable. If the packet is longer than + * zero bytes, we hand it over to the TCP/IP stack. + */ + uip_len = check_and_copy_packet(); + + /* + * The function tcpip_input() delivers the packet in the uip_buf[] + * buffer to the TCP/IP stack. + */ + if(uip_len > 0) { + tcpip_input(); + } + + /* + * Now we'll make sure that the poll handler is executed repeatedly. + * We do this by calling process_poll() with this process as its + * argument. + * + * In many cases, the hardware will cause an interrupt to be executed + * when a new packet arrives. For such hardware devices, the interrupt + * handler calls process_poll() (which is safe to use in an interrupt + * context) instead. + */ + process_poll(&example_packet_driver_process); +} +/*---------------------------------------------------------------------------*/ +/* + * Here we shutdown the hardware in case the process exits. + */ +static void +exithandler(void) +{ + shutdown_the_hardware(); +} +/*---------------------------------------------------------------------------*/ +/* + * Finally, we define the process that does the work. + */ +PROCESS_THREAD(example_packet_driver_process, ev, data) +{ + /* + * This process has a poll handler, so we declare it here. Note that + * the PROCESS_POLLHANDLER() macro must come before the PROCESS_BEGIN() + * macro. + */ + PROCESS_POLLHANDLER(pollhandler()); + + /* + * This process has an exit handler, so we declare it here. Note that + * the PROCESS_EXITHANDLER() macro must come before the PROCESS_BEGIN() + * macro. + */ + PROCESS_EXITHANDLER(exithandler()); + + /* + * The process begins here. + */ + PROCESS_BEGIN(); + + /* + * We start with initializing the hardware. + */ + initialize_the_hardware(); + + /* + * Register the driver. This will cause any previously registered driver + * to be ignored by the TCP/IP stack. + */ + tcpip_set_outputfunc(example_packet_driver_output); + + /* + * Now we'll make sure that the poll handler is executed initially. We do + * this by calling process_poll() with this process as its argument. + */ + process_poll(&example_packet_driver_process); + + /* + * And we wait for the process to exit. + */ + PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_EXIT); + + /* + * Here ends the process. + */ + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/doc/example-packet-service.c b/doc/example-packet-service.c deleted file mode 100644 index 3c26c39d1..000000000 --- a/doc/example-packet-service.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * This is an example of how to write a network device driver ("packet - * service") for Contiki. A packet service is a regular Contiki - * service that does two things: - * # Checks for incoming packets and delivers those to the TCP/IP stack - * # Provides an output function that transmits packets - * - * The output function is registered with the Contiki service - * mechanism, whereas incoming packets must be checked inside a - * Contiki process. We use the same process for checking for incoming - * packets and for registering the service. - * - * NOTE: This example does not work with the uip-fw module (packet - * forwarding with multiple interfaces). It only works with a single - * interface. - */ - -/* - * We include the "contiki-net.h" file to get all the network - * functions. - */ -#include "contiki-net.h" - -/*---------------------------------------------------------------------------*/ -/* - * We declare the process that we use to register the service, and to - * check for incoming packets. - */ -PROCESS(example_packet_service_process, "Example packet service process"); -/*---------------------------------------------------------------------------*/ -/* - * This is the poll handler function in the process below. This poll - * handler function checks for incoming packets and delivers them to - * the TCP/IP stack. - */ -static void -pollhandler(void) -{ - /* - * We assume that we have some hardware device that notifies us when - * a new packet has arrived. We also assume that we have a function - * that pulls out the new packet (here called - * check_and_copy_packet()) and puts it in the uip_buf[] buffer. The - * function returns the length of the incoming packet, and we store - * it in the global uip_len variable. If the packet is longer than - * zero bytes, we hand it over to the TCP/IP stack. - */ - uip_len = check_and_copy_packet(); - - /* - * The function tcpip_input() delivers the packet in the uip_buf[] - * buffer to the TCP/IP stack. - */ - if(uip_len > 0) { - tcpip_input(); - } - - /* - * Now we'll make sure that the poll handler is executed - * repeatedly. We do this by calling process_poll() with this - * process as its argument. - * - * In many cases, the hardware will cause an interrupt to be - * executed when a new packet arrives. For such hardware devices, - * the interrupt handler calls process_poll() (which is safe to use - * in an interrupt context) instead. - */ - process_poll(&example_packet_service_process); -} -/*---------------------------------------------------------------------------*/ -/* - * Next, we define the function that transmits packets. This function - * is called from the TCP/IP stack when a packet is to be - * transmitted. The packet is located in the uip_buf[] buffer, and the - * length of the packet is in the uip_len variable. - */ -static void -send_packet(void) -{ - let_the_hardware_send_the_packet(uip_buf, uip_len); -} -/*---------------------------------------------------------------------------*/ -/* - * Now we declare the service. We call the service - * example_packet_service because of the name of this file. The - * service should be an instance of the "packet service" service, so - * we give packet_service as the second argument. Finally we give our - * send_packet() function as the last argument, because of how the - * packet_service interface is defined. - * - * We'll register this service with the Contiki system in the process - * defined below. - */ -SERVICE(example_packet_service, packet_service, { send_packet }); -/*---------------------------------------------------------------------------*/ -/* - * Finally, we define the process that does the work. - */ -PROCESS_THREAD(example_packet_service_process, ev, data) -{ - /* - * This process has a poll handler, so we declare it here. Note that - * the PROCESS_POLLHANDLER() macro must come before the - * PROCESS_BEGIN() macro. - */ - PROCESS_POLLHANDLER(pollhandler()); - - /* - * The process begins here. - */ - PROCESS_BEGIN(); - - /* - * We start with initializing the hardware. - */ - initialize_the_hardware(); - - /* - * Register the service. This will cause any other instances of the - * same service to be removed. - */ - SERVICE_REGISTER(example_packet_service); - - /* - * Now we'll make sure that the poll handler is executed - * initially. We do this by calling process_poll() with this - * process as its argument. - */ - process_poll(&example_packet_service_process); - - /* - * And we wait for either the process to exit, or for the service to - * be removed (by someone else). - */ - PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_EXIT || - ev == PROCESS_EVENT_SERVICE_REMOVED); - - /* - * And we always end with explicitly removing the service. - */ - SERVICE_REMOVE(example_packet_service); - - /* - * Here endeth the process. - */ - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ diff --git a/doc/example-service.c b/doc/example-service.c deleted file mode 100644 index 41ee4f7ab..000000000 --- a/doc/example-service.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This file is an example of how to implement a service in - * Contiki. The header file example-service.h defines a service called - * "example_service", which we implement in this file. - * - * This example shows how to define an instance of a service, and how - * to write the service's controlling process. - * - * See the file example-use-service.c for an example of how to call a - * service. - */ - -#include - -#include "example-service.h" -#include "contiki.h" - -/*---------------------------------------------------------------------------*/ -/* - * We start by implementing all the functions that the service - * offers. In this case, there is only a single function (called - * example_function()) and we implement it here. We give it the name - * example() and declare it with the "static" keyword to keep the - * scope local to this file. - */ -static void -example(void) { - printf("Example service called\n"); -} -/*---------------------------------------------------------------------------*/ -/* - * This is the instantiation of the service called - * "example_service". The service interface is defined in the header - * file example-service.h. - * - * This statement defines the name of this implementation of the - * service - example_service_implementation - and defines the - * functions that actually implement the functions offered by the - * service. In this example, the service consists of a single function - * called "example_function()". We implement this function in the - * function called "example()" defined above. - * - */ -SERVICE(example_service_implementation, /* The name of this instance - of the service - used with - SERVICE_REGISTER(). */ - example_service, /* The name of the serivce - that is instantiated. */ - { example }); /* The list of functions - required by the - service. In this case, we - only have one function. */ - -/* - * All services needs a controlling process. The controlling process - * registers the service with the system when it starts, and is also - * notified if the service is removed or replaced. - * - * We simply call the process "example_service_process" and gives it a - * similar textual name. - */ -PROCESS(example_service_process, "Example service process"); - -/* - * For this example, we use a timer to remove the service after a - * certain time. We declare the timer here. - */ -static struct etimer timer; - -/* - * Finally, we implement the controlling process. - */ -PROCESS_THREAD(example_service_process, ev, data) -{ - - /* - * A process thread starts with PROCESS_BEGIN() and ends with - * PROCESS_END(). - */ - PROCESS_EXITHANDLER(goto exit); - PROCESS_BEGIN(); - - /* - * We register the service instance with a SERVICE_REGISTER() - * statement. - */ - printf("Registering example service\n"); - SERVICE_REGISTER(example_service_implementation); - - /* - * We set a timer for four seconds and wait for it to expire - or - * for the process to receive an event which requests it to exit. - * - * The only purpose for the timer is to demonstrate how a service is - * removed - it is not something that is commonly done. - */ - etimer_set(&timer, 4 * CLOCK_SECOND); - PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_SERVICE_REMOVED || - etimer_expired(&timer)); - - /* - * And we remove the service before the process ends. This is a - * *very* important step - if the process exits and is unloaded - * without first removing its services, the system may crash! - */ - printf("Removing example service\n"); - - /* - * And finally the process ends. - */ - exit: - SERVICE_REMOVE(example_service_implementation); - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ diff --git a/doc/example-service.h b/doc/example-service.h deleted file mode 100644 index 0f9806425..000000000 --- a/doc/example-service.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is an example of how to define a service in Contiki. The - * example shows how to define a service interface, and how to give - * the service a name. - */ -#ifndef __EXAMPLE_SERVICE_H__ -#define __EXAMPLE_SERVICE_H__ - -#include "sys/service.h" - -/* - * This is how we define the service interface, and give the service a - * name. The name of this particular service is "example_service" and - * the interface consists of a single function, called - * example_function(). - */ -SERVICE_INTERFACE(example_service, -{ - void (* example_function)(void); - /* More functions can be added here, line by line. */ -}); - -/* - * We must also give the service a textual name. We do this by using a - * special #define statment - we define a macro with the same name as - * the service, but postfixed with "_name". - * - * The textual name is used when looking up services. The name must be - * unique within the system. - */ -#define example_service_name "Example service" - -#endif /* __EXAMPLE_SERVICE_H__ */ diff --git a/doc/example-use-service.c b/doc/example-use-service.c deleted file mode 100644 index 003f7a310..000000000 --- a/doc/example-use-service.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file contains an example of how to call a service. - * - * This program implements a process that calls the service defined in - * example-service.h every second. - */ - -#include - -#include "contiki.h" - -/* - * We must include the header file for the service. - */ -#include "example-service.h" - -/* - * All Contiki programs must have a process, and we declare it here. - */ -PROCESS(example_use_service_process, "Use example"); - -/* - * The program is to call the service once every second, so we use an - * event timer in order to run every second. - */ -static struct etimer timer; - -/*---------------------------------------------------------------------------*/ -/* - * Here we implement the process. - */ -PROCESS_THREAD(example_use_service_process, ev, data) -{ - /* - * A process thread starts with PROCESS_BEGIN() and ends with - * PROCESS_END(). - */ - PROCESS_BEGIN(); - - /* - * We loop for ever, calling the service once every second. - */ - while(1) { - - /* - * We set a timer that wakes us up once every second. - */ - etimer_set(&timer, CLOCK_SECOND); - PROCESS_YIELD_UNTIL(etimer_expired(&timer)); - - /* - * We call the service. If the service is not registered, the - * SERVICE_CALL() statement does nothing. If we need to know if - * the service exists, we can use the SERVICE_FIND() function. - */ - printf("use example: calling example\n"); - SERVICE_CALL(example_service, example_function()); - } - - /* - * And finally the process ends. - */ - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ diff --git a/doc/examples.txt b/doc/examples.txt index 6978201f5..f570f2b64 100644 --- a/doc/examples.txt +++ b/doc/examples.txt @@ -1,10 +1,7 @@ /** \example example-program.c */ -/** \example example-service.c */ -/** \example example-service.h */ -/** \example example-use-service.c */ /** \example example-pollhandler.c */ /** \example example-list.c */ -/** \example example-packet-service.c */ +/** \example example-packet-drv.c */ /** \example example-psock-server.c */ /** \example test-abc.c */