/*---------------------------------------------------------------------------*/ static void process_run_thread_loop(void *data) { /* Yield once during bootup */ simProcessRunValue = 1; cooja_mt_yield(); contiki_init(); while(1) { simProcessRunValue = process_run(); while(simProcessRunValue-- > 0) { process_run(); } simProcessRunValue = process_nevents(); /* Check if we must stay awake */ if(simDontFallAsleep) { simDontFallAsleep=0; simProcessRunValue = 1; } /* Return to COOJA */ cooja_mt_yield(); } }
/*---------------------------------------------------------------------------*/ static void start_process_run_loop(void *data) { /* Yield once during bootup */ simProcessRunValue = 1; cooja_mt_yield(); /* Initialize random generator */ random_init(0); /* Start process handler */ process_init(); /* Start Contiki processes */ procinit_init(); /* Print startup information */ printf(CONTIKI_VERSION_STRING " started. "); if(node_id > 0) { printf("Node id is set to %u.\n", node_id); } else { printf("Node id is not set.\n"); } /* Initialize communication stack */ init_net(); /* Start serial process */ serial_line_init(); /* Start autostart processes (defined in Contiki application) */ print_processes(autostart_processes); autostart_start(autostart_processes); while(1) { /* Always pretend we have processes left while inside process_run() */ simProcessRunValue = 1; if (simDoReceiverCallback) { simDoReceiverCallback = 0; radio_call_receiver(); } simProcessRunValue = process_run(); while (simProcessRunValue-- > 0) { process_run(); } simProcessRunValue = process_nevents(); // Check if we must stay awake if (simDontFallAsleep) { simDontFallAsleep=0; simProcessRunValue = 1; } /* Yield thread when one process_run has completed */ cooja_mt_yield(); } }
/* Lock TSCH (no slot operation) */ int tsch_get_lock(void) { if(!tsch_locked) { rtimer_clock_t busy_wait_time; int busy_wait = 0; /* Flag used for logging purposes */ /* Make sure no new slot operation will start */ tsch_lock_requested = 1; /* Wait for the end of current slot operation. */ if(tsch_in_slot_operation) { busy_wait = 1; busy_wait_time = RTIMER_NOW(); while(tsch_in_slot_operation) { #if CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 simProcessRunValue = 1; cooja_mt_yield(); #endif /* CONTIKI_TARGET_COOJA || CONTIKI_TARGET_COOJA_IP64 */ } busy_wait_time = RTIMER_NOW() - busy_wait_time; } if(!tsch_locked) { /* Take the lock if it is free */ tsch_locked = 1; tsch_lock_requested = 0; if(busy_wait) { /* Issue a log whenever we had to busy wait until getting the lock */ TSCH_LOG_ADD(tsch_log_message, snprintf(log->message, sizeof(log->message), "!get lock delay %u", (unsigned)busy_wait_time); ); }
/*---------------------------------------------------------------------------*/ static int radio_send(const void *payload, unsigned short payload_len) { int radiostate = simRadioHWOn; if(!simRadioHWOn) { /* Turn on radio temporarily */ simRadioHWOn = 1; } if(payload_len > COOJA_RADIO_BUFSIZE) { return RADIO_TX_ERR; } if(payload_len == 0) { return RADIO_TX_ERR; } if(simOutSize > 0) { return RADIO_TX_ERR; } /* Copy packet data to temporary storage */ memcpy(simOutDataBuffer, payload, payload_len); simOutSize = payload_len; /* Transmit */ if (simOutSize > 0) { PRINTF("COOJA: sending %d bytes @ %lu\n", simOutSize, clock_time()); } while(simOutSize > 0) { cooja_mt_yield(); } simRadioHWOn = radiostate; /* FIXME: this doesn't work */ cooja_mt_yield(); /* duplicate packets here */ if (clock_seconds() >= failure_delay[simMoteID]) { if (!--packet_duplicate[simMoteID]) { PRINTF("COOJA: sending %d bytes @ %lu (twice)\n", payload_len, clock_time()); radio_send(payload, payload_len); } } return RADIO_TX_OK; }
/*---------------------------------------------------------------------------*/ static void rtimer_thread_loop(void *data) { while(1) { rtimer_arch_check(); /* Return to COOJA */ cooja_mt_yield(); } }
/*---------------------------------------------------------------------------*/ static int send_one_packet(struct net_buf *buf, mac_callback_t sent, void *ptr) { int ret; int last_sent_ok = 0; #if NULLRDC_ENABLE_RETRANSMISSIONS rtimer_clock_t target_time; uint8_t tx_attempts = 0; uint8_t max_tx_attempts; if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) > 0) { max_tx_attempts = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS); } else { max_tx_attempts = NULLRDC_MAX_RETRANSMISSIONS + 1; } #endif /* NULLRDC_ENABLE_RETRANSMISSIONS */ packetbuf_set_addr(buf, PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); #if NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW packetbuf_set_attr(buf, PACKETBUF_ATTR_MAC_ACK, 1); #endif /* NULLRDC_802154_AUTOACK || NULLRDC_802154_AUTOACK_HW */ if(NETSTACK_FRAMER.create_and_secure(buf) < 0) { /* Failed to allocate space for headers */ PRINTF("nullrdc: send failed, too large header\n"); ret = MAC_TX_ERR_FATAL; } else { #if NULLRDC_802154_AUTOACK int is_broadcast; uint8_t dsn; dsn = ((uint8_t *)packetbuf_hdrptr())[2] & 0xff; NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen()); is_broadcast = packetbuf_holds_broadcast(); if(NETSTACK_RADIO.receiving_packet() || (!is_broadcast && NETSTACK_RADIO.pending_packet())) { /* Currently receiving a packet over air or the radio has already received a packet that needs to be read before sending with auto ack. */ ret = MAC_TX_COLLISION; } else { if(!is_broadcast) { RIMESTATS_ADD(reliabletx); } #if NULLRDC_ENABLE_RETRANSMISSIONS while(1) { /* Transmit packet and check status */ tx_attempts++; #endif /* NULLRDC_ENABLE_RETRANSMISSIONS */ switch(NETSTACK_RADIO.transmit(packetbuf_totlen(buf))) { case RADIO_TX_OK: if(is_broadcast) { ret = MAC_TX_OK; } else { rtimer_clock_t wt; /* Check for ack */ wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)) { #if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); #endif /* CONTIKI_TARGET_COOJA */ } ret = MAC_TX_NOACK; if(NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet() || NETSTACK_RADIO.channel_clear() == 0) { int len; uint8_t ackbuf[ACK_LEN]; if(AFTER_ACK_DETECTED_WAIT_TIME > 0) { wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTED_WAIT_TIME)) { #if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); #endif /* CONTIKI_TARGET_COOJA */ } } if(NETSTACK_RADIO.pending_packet()) { len = NETSTACK_RADIO.read(ackbuf, ACK_LEN); if(len == ACK_LEN && ackbuf[2] == dsn) { /* Ack received */ RIMESTATS_ADD(ackrx); ret = MAC_TX_OK; } else { /* Not an ack or ack not for us: collision */ ret = MAC_TX_COLLISION; } } } else { PRINTF("nullrdc tx noack\n"); } } break; case RADIO_TX_COLLISION: ret = MAC_TX_COLLISION; break; default: ret = MAC_TX_ERR; break; } #if NULLRDC_ENABLE_RETRANSMISSIONS if(is_broadcast) { #if !NULLRDC_ENABLE_RETRANSMISSIONS_BCAST break; #else /* NULLRDC_ENABLE_RETRANSMISSIONS_BCAST */ if(ret != MAC_TX_COLLISION) { /* Retry broadcast frame only upon collision */ break; } #endif /* NULLRDC_ENABLE_RETRANSMISSIONS_BCAST */ } else { /* Frame is unicast. Do not retry unless NO_ACK or COLLISION */ if((ret != MAC_TX_NOACK) && (ret != MAC_TX_COLLISION)) { break; } } /* Do not retry if max attempts reached. */ if(tx_attempts >= max_tx_attempts) { PRINTF("nullrdc: max tx attempts reached\n"); break; } /* Block-wait before retrying the frame. */ target_time = RTIMER_NOW() + (RTIMER_SECOND * NULLRDC_TX_RETRY_DELAY_MS / 1000); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), target_time)) { /* Wait */ } /* Attempt a new frame (re)transmission */ } #endif /* NULLRDC_ENABLE_RETRANSMISSIONS */ } #else /* ! NULLRDC_802154_AUTOACK */ switch(NETSTACK_RADIO.send(buf, packetbuf_hdrptr(buf), packetbuf_totlen(buf))) { case RADIO_TX_OK: ret = MAC_TX_OK; break; case RADIO_TX_COLLISION: ret = MAC_TX_COLLISION; break; case RADIO_TX_NOACK: ret = MAC_TX_NOACK; break; default: ret = MAC_TX_ERR; break; } #endif /* ! NULLRDC_802154_AUTOACK */ } if(ret == MAC_TX_OK) { last_sent_ok = 1; } #if ! NULLRDC_ENABLE_RETRANSMISSIONS mac_call_sent_callback(buf, sent, ptr, ret, 1); #else mac_call_sent_callback(buf, sent, ptr, ret, tx_attempts); #endif /* !NULLRDC_ENABLE_RETRANSMISSIONS */ return last_sent_ok; }
/*---------------------------------------------------------------------------*/ static int send_one_packet(mac_callback_t sent, void *ptr) { int ret; int last_sent_ok = 0; packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); #if DISCOVERY_AWARE_RDC_802154_AUTOACK || DISCOVERY_AWARE_RDC_802154_AUTOACK_HW packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); #endif /* DISCOVERY_AWARE_RDC_802154_AUTOACK || DISCOVERY_AWARE_RDC_802154_AUTOACK_HW */ if (!radio_status) { on(); } if(NETSTACK_FRAMER.create() < 0) { /* Failed to allocate space for headers */ PRINTF("RDC: send failed, too large header\n"); ret = MAC_TX_ERR_FATAL; } else { #ifdef NETSTACK_ENCRYPT NETSTACK_ENCRYPT(); #endif /* NETSTACK_ENCRYPT */ #if DISCOVERY_AWARE_RDC_802154_AUTOACK int is_broadcast; uint8_t dsn; dsn = ((uint8_t *)packetbuf_hdrptr())[2] & 0xff; NETSTACK_RADIO.prepare(packetbuf_hdrptr(), packetbuf_totlen()); is_broadcast = linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_null); if(NETSTACK_RADIO.receiving_packet() || (!is_broadcast && NETSTACK_RADIO.pending_packet())) { /* Currently receiving a packet over air or the radio has already received a packet that needs to be read before sending with auto ack. */ ret = MAC_TX_COLLISION; } else { if(!is_broadcast) { RIMESTATS_ADD(reliabletx); } switch(NETSTACK_RADIO.transmit(packetbuf_totlen())) { case RADIO_TX_OK: if(is_broadcast) { ret = MAC_TX_OK; } else { rtimer_clock_t wt; /* Check for ack */ wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)) { #if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); #endif /* CONTIKI_TARGET_COOJA */ } ret = MAC_TX_NOACK; if(NETSTACK_RADIO.receiving_packet() || NETSTACK_RADIO.pending_packet() || NETSTACK_RADIO.channel_clear() == 0) { int len; uint8_t ackbuf[ACK_LEN]; if(AFTER_ACK_DETECTED_WAIT_TIME > 0) { wt = RTIMER_NOW(); watchdog_periodic(); while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + AFTER_ACK_DETECTED_WAIT_TIME)) { #if CONTIKI_TARGET_COOJA simProcessRunValue = 1; cooja_mt_yield(); #endif /* CONTIKI_TARGET_COOJA */ } } if(NETSTACK_RADIO.pending_packet()) { len = NETSTACK_RADIO.read(ackbuf, ACK_LEN); if(len == ACK_LEN && ackbuf[2] == dsn) { /* Ack received */ RIMESTATS_ADD(ackrx); ret = MAC_TX_OK; } else { /* Not an ack or ack not for us: collision */ ret = MAC_TX_COLLISION; } } } else { PRINTF("RDC tx noack\n"); } } break; case RADIO_TX_COLLISION: ret = MAC_TX_COLLISION; break; default: ret = MAC_TX_ERR; break; } } #else /* ! DISCOVERY_AWARE_RDC_802154_AUTOACK */ switch(NETSTACK_RADIO.send(packetbuf_hdrptr(), packetbuf_totlen())) { case RADIO_TX_OK: ret = MAC_TX_OK; break; case RADIO_TX_COLLISION: ret = MAC_TX_COLLISION; break; case RADIO_TX_NOACK: ret = MAC_TX_NOACK; break; default: ret = MAC_TX_ERR; break; } #endif /* ! DISCOVERY_AWARE_RDC_802154_AUTOACK */ } if (!linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_null) && ret == MAC_TX_OK) { send_flag = 1; to_modifier+=10; } if(ret == MAC_TX_OK) { last_sent_ok = 1; } mac_call_sent_callback(sent, ptr, ret, 1); return last_sent_ok; }