...

Table of Page Contents

Scanning...

Coding for Space

Coding safety critical systems and systems like satellites requires high quality of your code.

Here follows some rules we like to follow:

The Power of Ten Rules

All about coding (in C) in ten rules :-)

  1. Restrict to simple control flow constructs.
  2. Give all loops a fixed upper-bound.
  3. Do not use dynamic memory allocation after initialization.
  4. Limit functions to no more than 60 lines of text.
  5. Use minimally two assertions per function on average.
  6. Declare data objects at the smallest possible level of scope.
  7. Check the return value of non-void functions, and check the validity of function parameters.
  8. Limit the use of the preprocessor to file inclusion and simple macros.
  9. Limit the use of pointers. Use no more than two levels of dereferencing per expression.
  10. Compile with all warnings enabled, and use one or more source code analyzers.

See rules and explanation at http://spinroot.com/p10/ and the original paper written by G. Holzmann from NASA/JPL.


Cyclomatic index

A way to analyze (non documented) code is by calculate the Cyclomatic index. Many C suites has built in Cyclomatic Index calculator which indicates is has a value.

Cyclomatic index is calculated pr function.

If the index is to high the code is considered to complicated (loops,if;while,...) and need to be rewritten. Values above 10 should raise your eyebrows.

Tools like pmccabe(on linux) can do the stuff

pmccabe -v *c

look for cyclomatic values greater than 10

and for function lenght more than 80 lines

For AIS1 on AAUSAT function task_rs232_cmd_line has Cyclomatix index 77 (39 for the modified index). And it is nearly impossible to maintain - (cite:Jens)

The SPI isr (for getting ais bitstream from adf7021) has 29 - which is also much to much .

  pmccabe -v *c | sort -n -r 

  will give you the functions at top


From AIS1:
Modified McCabe Cyclomatic Complexity
|   Traditional McCabe Cyclomatic Complexity
|       |    # Statements in function
|       |        |   First line of function
|       |        |       |   # lines in function
|       |        |       |       |  filename(definition line number):function
|       |        |       |       |           |

SHALL BE CHECKED AND REWRITTEN 
39      77      293     93      420     task_rs232_cmd_line.c(93): vTaskCom
34      44      145     215     239     ais1_csp_debug.c(215): ais_debug_iface
29      29      83      146     155     drv_spi.c(146): ISR
27      27      60      98      91      ais_filter_match.c(98): ais_filter_match
25      25      82      303     147     drv_spi.c(303): ISR
19      27      75      277     170     ais_sm.c(277): ais_state_loop_standard
19      19      43      662     90      server.c(662): do_cleaning
13      13      50      269     82      server.c(269): exp_config_filter_service
12      12      41      352     65      server.c(352): ais1_fp_service
11      11      45      28      96      bit_destuff.c(29): bit_destuffng
11      11      37      104     76      task_flasher.c(104): flashQInit
11      11      30      191     54      task_flasher.c(191): save_frame
SHALL BE CHECKED
10      10      25      755     36      server.c(755): check_before_launch
9       9       43      253     87      bit_destuff.c(254): bit_destuffngg
9       9       19      199     31      ais_flash.c(199): ais_store_get_current_seq
9       18      49      41      90      task_csp.c(41): vTaskCSP
9       11      25      150     45      ais_flash.c(150): ais_store_write_next
8       8       35      182     70      bit_destuff.c(183): bit_destuff
8       8       28      99      45      uniqaisbuf.c(99): uniq_aisQ_putt
8       13      39      132     68      task_csp.c(132): vTaskCSP_AIS_STORE
8       11      37      155     63      server.c(155): set_exp_by_ref
8       10      42      68      78      ais_flash.c(68): ais_store_read
7       9       23      237     47      ais_flash.c(237): ais_store_get_count
7       7       39      447     68      task_ais.c(447): test_for_new_experiment
7       7       27      126     51      bit_destuff.c(127): destuff
7       7       20      141     27      ringbuf.c(141): ringbuf_put_next
7       7       11      39      18      ais_flash.c(39): ais_store_calc_max_nr_frames
OK FROM HERE APPROX
6       8       30      418     53      server.c(418): ais1_fp_radio_service
6       7       28      219     49      server.c(219): match_filter_service
6       6       92      400     205     drv_adf7021.c(400): adf_set_rx_mode_org
6       6       74      197     202     drv_adf7021.c(197): adf_set_rx_mode
6       6       43      615     85      task_ais.c(615): vTaskAISRx
6       6       32      127     41      drv_adf7021.c(127): adf_read_reg
6       6       31      523     35      server.c(523): csp_port_status
6       6       26      98      28      drv_adf7021.c(98): adf_write_reg
6       6       15      73      24      crc16_ccitt.c(73): crc_itu16_check
6       6       13      290     35      task_flasher.c(290): vTaskFlash2
6       6       11      134     14      ais1.c(134): reset_cause_i
6       6       11      120     13      ais1.c(120): reset_cause
6       10      54      71      78      ais1_csp_debug.c(71): ais1_radio_control
5       5       33      472     50      server.c(472): csp_port_beacon

Conclusion: it matters !

Other metrics is Halstead and other tools

Malloc and Free

According to Power of Ten Rules rules no 3 dynamic allocation shall not be used after initialization of your program. In some cases in can be necessary. In these situations you must check that allocations has been a success:

int *p;
  p = (int ') malloc(sizeof(int)*34);
if (p == NULL) {
  bad bad
}

A slighty better way to do it is:

if (NULL == (p = (int *)malloc(sizeof(int)*34)) ) {
}

why ? because you by just a grep malloc *c can check if check has been imposed !

You can by grep track down if alloc and free are paired

grep -n -E "PortMalloc|PortFree" *c

  -n : line numbers
  -E : reg expr

You can do it much more advanced

CSP buffers

In AAUSAT3 and AAUSAT4 CSP is used as communication protocol inside as well as outside the satellite.

TYPICAL SERVER CODE
====================

void vTaskCSP(void * pvParameters) {

csp_socket_t * sock; // Open port
csp_conn_t * conn;
csp_packet_t * packet;

sock = csp_socket(0); // Open port

csp_bind(sock, CSP_PING); // Bind service ports
csp_bind(sock, CSP_ANY); // Bind AIS ports
csp_listen(sock, 10);


while (1) {
  conn = csp_accept(sock, 2000 / portTICK_RATE_MS);
  if (conn == NULL)
    continue; // nope didnt get the connection
  packet = csp_read(conn, 1000);
  if (packet == NULL) {
    csp_close(conn);  // no data
    continue;

  // FROM HERE WE GOT ONE PACKAGE 
  csp_port_status(conn, packet); //DONE mostly TODO on way svar

}

void csp_port_status(csp_conn_t * conn, csp_packet_t * packet) {
uint8_t i = 0;
ais1_status_reply_t *reply = (ais1_status_reply_t *) &packet->data;

  reply->muxout = adf_readback_muxout();
  reply->rssi = (uint8_t) (adf_readback_rssi_running());
  packet->length = sizeof(ais1_status_reply_t);

  if (!csp_send(conn, packet, 0))
  csp_buffer_free(packet);
}

The buffer that the server received for the call is reused for sending data back.

Note that only one buffer (80B) is send back.

If the server need to send more data back extra buffers must be allocated and you must be carefull handling - delete of buffers if no succes in TX and close the connection after last TX.

...
  if (NULL ==
    (packet = csp_buffer_get(elements_in_packet * sizeof(eps_csp_temp_hist_reply_t)))
  {
     goto yt; // end-of-story for this transmit of data back
  }
  // FILL DATA IN BUFFER
  if (!csp_send(conn, packet, 0))
    csp_buffer_free(packet);
  }  
  // next buffer
  if (NULL ==
    (packet = csp_buffer_get(elements_in_packet * sizeof(eps_csp_temp_hist_reply_t)))
  {
     goto yt; // end-of-story for this transmit of data back
  }
  // FILL DATA IN BUFFER FOR 2nd TIME
  if (!csp_send(conn, packet, 0))
    csp_buffer_free(packet);
  }  

  yt: csp_close(conn);

I USE goto because it ease and de-complicate your code :-)

Doxygen

An easy way to document your code - should be used :-)