149 lines
4.8 KiB
C
149 lines
4.8 KiB
C
/*
|
|
* 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();
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|