diff --git a/INSTALL.md b/INSTALL.rst similarity index 87% rename from INSTALL.md rename to INSTALL.rst index bb04e8368..e68a46ed8 100644 --- a/INSTALL.md +++ b/INSTALL.rst @@ -9,7 +9,9 @@ certain optional features. To configure CSP to build with the AVR32 toolchain for FreeRTOS and output the compiled libcsp.a and header files to the install directory, issue: - ./waf configure --toolchain=avr32- --with-os=freertos --prefix=install +.. code-block:: bash + + ./waf configure --toolchain=avr32- --with-os=freertos --prefix=install When compiling for FreeRTOS, the path to the FreeRTOS header files must be specified with `--with-freertos=PATH.` @@ -23,4 +25,6 @@ where CHIP is one of 'socketcan', 'at91sam7a1', 'at91sam7a3' or 'at90can128'. To build and copy the library to the location specified with --prefix, use: - ./waf build install +.. code-block:: bash + + ./waf build install diff --git a/README.md b/README.rst similarity index 100% rename from README.md rename to README.rst diff --git a/doc/example.md b/doc/example.md deleted file mode 100644 index ab25aaf07..000000000 --- a/doc/example.md +++ /dev/null @@ -1,124 +0,0 @@ -Client and server example -========================= - -The following examples show the initialization of the protocol stack and examples of client/server code. - -Initialization Sequence ------------------------ - -This code initializes the CSP buffer system, device drivers and router core. The example uses the CAN interface function csp_can_tx but the initialization is similar for other interfaces. The loopback interface does not require any explicit initialization. - -``` c -#include -#include - -/* CAN configuration struct for SocketCAN interface "can0" */ -struct csp_can_config can_conf = {.ifc = "can0"}; - -/* Init buffer system with 10 packets of maximum 320 bytes each */ -csp_buffer_init(10, 320); - -/* Init CSP with address 1 */ -csp_init(1); - -/* Init the CAN interface with hardware filtering */ -csp_can_init(CSP_CAN_MASKED, &can_conf) - -/* Setup default route to CAN interface */ -csp_route_set(CSP_DEFAULT_ROUTE, &csp_can_tx, CSP_HOST_MAC); - -/* Start router task with 500 word stack, OS task priority 1 */ -csp_route_start_task(500, 1); -``` - -Server ------- - -This example shows how to create a server task that listens for incoming connections. CSP should be initialized before starting this task. Note the use of `csp_service_handler()` as the default branch in the port switch case. The service handler will automatically reply to ICMP-like requests, such as pings and buffer status requests. - -``` c -void csp_task(void *parameters) { - /* Create socket without any socket options */ - csp_socket_t *sock = csp_socket(CSP_SO_NONE); - - /* Bind all ports to socket */ - csp_bind(sock, CSP_ANY); - - /* Create 10 connections backlog queue */ - csp_listen(sock, 10); - - /* Pointer to current connection and packet */ - csp_conn_t *conn; - csp_packet_t *packet; - - /* Process incoming connections */ - while (1) { - /* Wait for connection, 10000 ms timeout */ - if ((conn = csp_accept(sock, 10000)) == NULL) - continue; - - /* Read packets. Timout is 1000 ms */ - while ((packet = csp_read(conn, 1000)) != NULL) { - switch (csp_conn_dport(conn)) { - case MY_PORT: - /* Process packet here */ - default: - /* Let the service handler reply pings, buffer use, etc. */ - csp_service_handler(conn, packet); - break; - } - } - - /* Close current connection, and handle next */ - csp_close(conn); - } -} -``` - -Client ------- - -This example shows how to allocate a packet buffer, connect to another host and send the packet. CSP should be initialized before calling this function. RDP, XTEA, HMAC and CRC checksums can be enabled per connection, by setting the connection option to a bitwise OR of any combination of `CSP_O_RDP`, `CSP_O_XTEA`, `CSP_O_HMAC` and `CSP_O_CRC`. - -``` c -int send_packet(void) { - - /* Get packet buffer for data */ - csp_packet_t *packet = csp_buffer_get(data_size); - if (packet == NULL) { - /* Could not get buffer element */ - printf("Failed to get buffer element\\n"); - return -1; - } - - /* Connect to host HOST, port PORT with regular UDP-like protocol and 1000 ms timeout */ - csp_conn_t *conn = csp_connect(CSP_PRIO_NORM, HOST, PORT, 1000, CSP_O_NONE); - if (conn == NULL) { - /* Connect failed */ - printf("Connection failed\\n"); - /* Remember to free packet buffer */ - csp_buffer_free(packet); - return -1; - } - - /* Copy message to packet */ - char *msg = "HELLO"; - strcpy(packet->data, msg); - - /* Set packet length */ - packet->length = strlen(msg); - - /* Send packet */ - if (!csp_send(conn, packet, 1000)) { - /* Send failed */ - printf("Send failed\\n"); - csp_buffer_free(packet); - } - - /* Close connection */ - csp_close(conn); - - return 0 -} -``` - diff --git a/doc/example.rst b/doc/example.rst new file mode 100644 index 000000000..b82a055e0 --- /dev/null +++ b/doc/example.rst @@ -0,0 +1,123 @@ +Client and server example +========================= + +The following examples show the initialization of the protocol stack and examples of client/server code. + +Initialization Sequence +----------------------- + +This code initializes the CSP buffer system, device drivers and router core. The example uses the CAN interface function csp_can_tx but the initialization is similar for other interfaces. The loopback interface does not require any explicit initialization. + +.. code-block:: c + + #include + #include + + /* CAN configuration struct for SocketCAN interface "can0" */ + struct csp_can_config can_conf = {.ifc = "can0"}; + + /* Init buffer system with 10 packets of maximum 320 bytes each */ + csp_buffer_init(10, 320); + + /* Init CSP with address 1 */ + csp_init(1); + + /* Init the CAN interface with hardware filtering */ + csp_can_init(CSP_CAN_MASKED, &can_conf) + + /* Setup default route to CAN interface */ + csp_route_set(CSP_DEFAULT_ROUTE, &csp_can_tx, CSP_HOST_MAC); + + /* Start router task with 500 word stack, OS task priority 1 */ + csp_route_start_task(500, 1); + +Server +------ + +This example shows how to create a server task that listens for incoming connections. CSP should be initialized before starting this task. Note the use of `csp_service_handler()` as the default branch in the port switch case. The service handler will automatically reply to ICMP-like requests, such as pings and buffer status requests. + +.. code-block:: c + + void csp_task(void *parameters) { + /* Create socket without any socket options */ + csp_socket_t *sock = csp_socket(CSP_SO_NONE); + + /* Bind all ports to socket */ + csp_bind(sock, CSP_ANY); + + /* Create 10 connections backlog queue */ + csp_listen(sock, 10); + + /* Pointer to current connection and packet */ + csp_conn_t *conn; + csp_packet_t *packet; + + /* Process incoming connections */ + while (1) { + /* Wait for connection, 10000 ms timeout */ + if ((conn = csp_accept(sock, 10000)) == NULL) + continue; + + /* Read packets. Timout is 1000 ms */ + while ((packet = csp_read(conn, 1000)) != NULL) { + switch (csp_conn_dport(conn)) { + case MY_PORT: + /* Process packet here */ + default: + /* Let the service handler reply pings, buffer use, etc. */ + csp_service_handler(conn, packet); + break; + } + } + + /* Close current connection, and handle next */ + csp_close(conn); + } + } + +Client +------ + +This example shows how to allocate a packet buffer, connect to another host and send the packet. CSP should be initialized before calling this function. RDP, XTEA, HMAC and CRC checksums can be enabled per connection, by setting the connection option to a bitwise OR of any combination of `CSP_O_RDP`, `CSP_O_XTEA`, `CSP_O_HMAC` and `CSP_O_CRC`. + +.. code-block:: c + + int send_packet(void) { + + /* Get packet buffer for data */ + csp_packet_t *packet = csp_buffer_get(data_size); + if (packet == NULL) { + /* Could not get buffer element */ + printf("Failed to get buffer element\\n"); + return -1; + } + + /* Connect to host HOST, port PORT with regular UDP-like protocol and 1000 ms timeout */ + csp_conn_t *conn = csp_connect(CSP_PRIO_NORM, HOST, PORT, 1000, CSP_O_NONE); + if (conn == NULL) { + /* Connect failed */ + printf("Connection failed\\n"); + /* Remember to free packet buffer */ + csp_buffer_free(packet); + return -1; + } + + /* Copy message to packet */ + char *msg = "HELLO"; + strcpy(packet->data, msg); + + /* Set packet length */ + packet->length = strlen(msg); + + /* Send packet */ + if (!csp_send(conn, packet, 1000)) { + /* Send failed */ + printf("Send failed\\n"); + csp_buffer_free(packet); + } + + /* Close connection */ + csp_close(conn); + + return 0 + } diff --git a/doc/history.md b/doc/history.rst similarity index 98% rename from doc/history.md rename to doc/history.rst index 71a761fdb..de153ee1f 100644 --- a/doc/history.md +++ b/doc/history.rst @@ -14,4 +14,4 @@ This is the known list of satellites or organisations that uses CSP. * EuroLuna * NUTS * Hawaiian Space Flight Laboratory - + * GomSpace GOMX-3 diff --git a/doc/interfaces.md b/doc/interfaces.rst similarity index 73% rename from doc/interfaces.md rename to doc/interfaces.rst index b7c8c7b0b..0f05c6b35 100644 --- a/doc/interfaces.md +++ b/doc/interfaces.rst @@ -5,29 +5,29 @@ This is an example of how to implement a new layer-2 interface in CSP. The examp CSP interfaces are declared in a `csp_iface_t` structure, which sets the interface nexthop function and name. A maximum transmission unit can also be set, which forces CSP to drop outgoing packets above a certain size. The fifo interface is defined as: -``` c -#include -#include +.. code-block:: c -csp_iface_t csp_if_fifo = { - .name = "fifo", - .nexthop = csp_fifo_tx, - .mtu = BUF_SIZE, -}; -``` + #include + #include + + csp_iface_t csp_if_fifo = { + .name = "fifo", + .nexthop = csp_fifo_tx, + .mtu = BUF_SIZE, + }; Outgoing traffic ---------------- The nexthop function takes a pointer to a CSP packet and a timeout as parameters. All outgoing packets that are routed to the interface are passed to this function: -``` c -int csp_fifo_tx(csp_packet_t *packet, uint32_t timeout) { - write(tx_channel, &packet->length, packet->length + sizeof(uint32_t) + sizeof(uint16_t)); - csp_buffer_free(packet); - return 1; -} -``` +.. code-block:: c + + int csp_fifo_tx(csp_packet_t *packet, uint32_t timeout) { + write(tx_channel, &packet->length, packet->length + sizeof(uint32_t) + sizeof(uint16_t)); + csp_buffer_free(packet); + return 1; + } In the fifo interface, we simply transmit the header, length field and data using a write to the fifo. CSP does not dictate the wire format, so other interfaces may decide to e.g. ignore the length field if the physical layer provides start/stop flags. @@ -38,22 +38,22 @@ Incoming traffic The interface also needs to receive incoming packets and pass it to the CSP protocol stack. In the fifo interface, this is handled by a thread that blocks on the incoming fifo and waits for packets: -``` c -void * fifo_rx(void * parameters) { - csp_packet_t *buf = csp_buffer_get(BUF_SIZE); - /* Wait for packet on fifo */ - while (read(rx_channel, &buf->length, BUF_SIZE) > 0) { - csp_new_packet(buf, &csp_if_fifo, NULL); - buf = csp_buffer_get(BUF_SIZE); - } -} -``` +.. code-block:: c + + void * fifo_rx(void * parameters) { + csp_packet_t *buf = csp_buffer_get(BUF_SIZE); + /* Wait for packet on fifo */ + while (read(rx_channel, &buf->length, BUF_SIZE) > 0) { + csp_new_packet(buf, &csp_if_fifo, NULL); + buf = csp_buffer_get(BUF_SIZE); + } + } A new CSP buffer is preallocated with csp_buffer_get(). When data is received, the packet is passed to CSP using `csp_new_packet()` and a new buffer is allocated for the next packet. In addition to the received packet, `csp_new_packet()` takes two additional arguments: -``` c -void csp_new_packet(csp_packet_t *packet, csp_iface_t *interface, CSP_BASE_TYPE *pxTaskWoken); -``` +.. code-block:: c + + void csp_new_packet(csp_packet_t *packet, csp_iface_t *interface, CSP_BASE_TYPE *pxTaskWoken); The calling interface must be passed in `interface` to avoid routing loops. Furthermore, `pxTaskWoken` must be set to a non-NULL value if the packet is received in an interrupt service routine. If the packet is received in task context, NULL must be passed. 'pxTaskWoken' only applies to FreeRTOS systems, and POSIX system should always set the value to NULL. @@ -64,17 +64,17 @@ Initialization In order to initialize the interface, and make it available to the router, use the following function found in `csp/csp_interface.h`: -``` c -csp_route_add_if(&csp_if_fifo); -``` +.. code-block:: c + + csp_route_add_if(&csp_if_fifo); This actually happens automatically if you try to call `csp_route_add()` with an interface that is inknown to the router. This may however be removed in the future, in order to ensure that all interfaces are initialised before configuring the routing table. The reason is, that some products released in the future may ship with an empty routing table, which is then configured by a routing protocol rather than a static configuration. In order to setup a manual static route, use the follwing example where the default route is set to the fifo interface: -``` c -csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_fifo, CSP_NODE_MAC); -``` +.. code-block:: c + + csp_route_set(CSP_DEFAULT_ROUTE, &csp_if_fifo, CSP_NODE_MAC); All outgoing traffic except loopback, is now passed to the fifo interface's nexthop function. @@ -83,13 +83,13 @@ Building the example The fifo examples can be compiled with: -``` bash -% gcc csp_if_fifo.c -o csp_if_fifo -I/include -L/build -lcsp -lpthread -lrt -``` +.. code-block:: bash + + % gcc csp_if_fifo.c -o csp_if_fifo -I/include -L/build -lcsp -lpthread -lrt The two named pipes are created with: -``` bash -% mkfifo server_to_client client_to_server -``` +.. code-block:: bash + + % mkfifo server_to_client client_to_server diff --git a/doc/libcsp.rst b/doc/libcsp.rst new file mode 100644 index 000000000..4ea6c2607 --- /dev/null +++ b/doc/libcsp.rst @@ -0,0 +1,19 @@ +.. CSP Documentation master file. + +********************** +CubeSat Space Protocol +********************** + +.. toctree:: + :maxdepth: 3 + + ../README + history + structure + interfaces + memory + protocolstack + topology + mtu + example + diff --git a/doc/memory.md b/doc/memory.rst similarity index 100% rename from doc/memory.md rename to doc/memory.rst diff --git a/doc/mtu.md b/doc/mtu.rst similarity index 98% rename from doc/mtu.md rename to doc/mtu.rst index b90932686..0ae1bc766 100644 --- a/doc/mtu.md +++ b/doc/mtu.rst @@ -1,4 +1,6 @@ -# Maximum Transfer Unit +Maximum Transfer Unit +===================== + There are two things limiting the MTU of CSP. 1. The pre-allocated buffer pool’s allocation size diff --git a/doc/protocolstack.md b/doc/protocolstack.rst similarity index 99% rename from doc/protocolstack.md rename to doc/protocolstack.rst index 3619409ab..91918fd01 100644 --- a/doc/protocolstack.md +++ b/doc/protocolstack.rst @@ -29,14 +29,17 @@ LibCSP implements two different Transport Layer protocols, they are called UDP ( The most important thing to notice is that CSP is entirely a datagram service. There is no stream based service like TCP. A datagram is defined a block of data with a specified size and structure. This block enters the transport layer as a single datagram and exits the transport layer in the other end as a sigle datagram. CSP preserves this structure all the way to the physical layer for I2C, KISS and Loopback interfaces are used. The CAN-bus interface has to fragment the datagram into CAN-frames of 8 bytes, however only a fully completed datagram will arrive at the receiver. -### UDP ### +UDP +^^^ + UDP uses a simple transmission model without implicit hand-shaking dialogues for guaranteeing reliability, ordering, or data integrity. Thus, UDP provides an unreliable service and datagrams may arrive out of order, appear duplicated, or go missing without notice. UDP assumes that error checking and correction is either not necessary or performed in the application, avoiding the overhead of such processing at the network interface level. Time-sensitive applications often use UDP because dropping packets is preferable to waiting for delayed packets, which may not be an option in a real-time system. UDP is very practical to implement request/reply based communication where a single packet forms the request and a single packet forms the reply. In this case a typical request and wait protocol is used between the client and server, which will simply return an error if a reply is not received within a specified time limit. An error would normally lead to a retransmission of the request from the user or operator which sent the request. While UDP is very simple, it also has some limitations. Normally a human in the loop is a good thing when operating the satellite over UDP. But when it comes to larger file transfers, the human becomes the bottleneck. When a high-speed file transfer is initiated data acknowledgement should be done automatically in order to speed up the transfer. This is where the RDP protocol can help. -### RDP ### +RDP +^^^ CSP provides a transport layer extension called RDP (reliable datagram protocol) which is an implementation of RFC908 and RFC1151. RDP provides a few additional features: * Three-way handshake diff --git a/doc/structure.rst b/doc/structure.rst new file mode 100644 index 000000000..4c9b515c3 --- /dev/null +++ b/doc/structure.rst @@ -0,0 +1,27 @@ +Structure +========= +The Cubesat Space Protocol library is structured as shown in the following table: + +============================= ========================================================================= +**Folder** **Description** +============================= ========================================================================= +libcsp/include/csp Main include files +libcsp/include/csp/arch Architecture include files +libcsp/include/csp/interfaces Interface include files +libcsp/include/csp/drivers Drivers include files +libcsp/src Main modules for CSP: io, router, connections, services +libcsp/src/interfaces Interface modules for CAN, I2C, KISS, LOOP and ZMQHUB +libcsp/src/drivers/can Driver for CAN +libcsp/src/drivers/usart Driver for USART +libcsp/src/arch/freertos FreeRTOS architecture module +libcsp/src/arch/macosx Mac OS X architecture module +libcsp/src/arch/posix Posix architecture module +libcsp/src/arch/windows Windows architecture module +libcsp/src/rtable Routing table module +libcsp/transport Transport module, UDP and RDP +libcsp/crypto Crypto module +libcsp/utils Utilities +libcsp/bindings/python Python wrapper for libcsp +libcsp/examples CSP examples (source code) +libasf/doc The doc folder contains the source code for this documentation +============================= ========================================================================= diff --git a/doc/topology.md b/doc/topology.rst similarity index 69% rename from doc/topology.md rename to doc/topology.rst index 2358dafd3..e629c29e1 100644 --- a/doc/topology.md +++ b/doc/topology.rst @@ -3,21 +3,22 @@ Network Topology CSP uses a network oriented terminology similar to what is known from the Internet and the TCP/IP model. A CSP network can be configured for several different topologies. The most common topology is to create two segments, one for the Satellite and one for the Ground-Station. - I2C BUS - _______________________________ - / | | | \ - +---+ +---+ +---+ +---+ +---+ - |OBC| |COM| |EPS| |PL1| |PL2| Nodes 0 - 7 (Space segment) - +---+ +---+ +---+ +---+ +---+ - ^ - | Radio - v - +---+ +----+ - |TNC| ------- | PC | Nodes 8 - 15 (Ground segment) - +---+ USB +----+ - - Node 9 Node 10 +.. code-block:: none + I2C BUS + _______________________________ + / | | | \ + +---+ +---+ +---+ +---+ +---+ + |OBC| |COM| |EPS| |PL1| |PL2| Nodes 0 - 7 (Space segment) + +---+ +---+ +---+ +---+ +---+ + ^ + | Radio + v + +---+ +----+ + |TNC| ------- | PC | Nodes 8 - 15 (Ground segment) + +---+ USB +----+ + + Node 9 Node 10 The address range, from 0 to 15, has been segmented into two equal size segments. This allows for easy routing in the network. All addresses starting with binary 1 is on the ground-segment, and all addresses starting with 0 is on the space segment. From CSP v1.0 the address space has been increased to 32 addresses, 0 to 31. But for legacy purposes, the old 0 to 15 is still used in most products.