// Start a response, returns the partial CRC void ICACHE_FLASH_ATTR cmdResponseStart(uint16_t cmd, uint32_t value, uint16_t argc) { DBG("cmdResponse: cmd=%d val=%d argc=%d\n", cmd, value, argc); uart0_write_char(SLIP_END); cmdProtoWriteBuf((uint8_t*)&cmd, 2); resp_crc = crc16_data((uint8_t*)&cmd, 2, 0); cmdProtoWriteBuf((uint8_t*)&argc, 2); resp_crc = crc16_data((uint8_t*)&argc, 2, resp_crc); cmdProtoWriteBuf((uint8_t*)&value, 4); resp_crc = crc16_data((uint8_t*)&value, 4, resp_crc); }
// Start a response, returns the partial CRC uint16_t ICACHE_FLASH_ATTR CMD_ResponseStart(uint16_t cmd, uint32_t callback, uint32_t _return, uint16_t argc) { uint16_t crc = 0; uart0_write_char(SLIP_START); CMD_ProtoWriteBuf((uint8_t*)&cmd, 2); crc = crc16_data((uint8_t*)&cmd, 2, crc); CMD_ProtoWriteBuf((uint8_t*)&callback, 4); crc = crc16_data((uint8_t*)&callback, 4, crc); CMD_ProtoWriteBuf((uint8_t*)&_return, 4); crc = crc16_data((uint8_t*)&_return, 4, crc); CMD_ProtoWriteBuf((uint8_t*)&argc, 2); crc = crc16_data((uint8_t*)&argc, 2, crc); return crc; }
// Adds data to a response, returns the partial CRC void ICACHE_FLASH_ATTR cmdResponseBody(const void *data, uint16_t len) { cmdProtoWriteBuf((uint8_t*)&len, 2); resp_crc = crc16_data((uint8_t*)&len, 2, resp_crc); cmdProtoWriteBuf(data, len); resp_crc = crc16_data(data, len, resp_crc); uint16_t pad = (4-((len+2)&3))&3; // get to multiple of 4 if (pad > 0) { uint32_t temp = 0; cmdProtoWriteBuf((uint8_t*)&temp, pad); resp_crc = crc16_data((uint8_t*)&temp, pad, resp_crc); } }
/*---------------------------------------------------------------------------*/ static void recv_trickle(struct trickle_conn *c) { struct trickle_msg *msg; uint16_t crc; int len; msg = packetbuf_dataptr(); if(packetbuf_datalen() > 1 + TRICKLEMSG_HDR_SIZE) { /* First ensure that the old process is killed. */ process_exit(&shell_netcmd_server_process); len = packetbuf_datalen() - 1 - TRICKLEMSG_HDR_SIZE; /* Make sure that the incoming command is null-terminated. */ msg->netcmd[len] = 0; memcpy(&crc, &msg->crc, sizeof(crc)); if(crc == crc16_data(msg->netcmd, len, 0)) { /* Start the server process with the incoming command. */ process_start(&shell_netcmd_server_process, (void *)msg->netcmd); } } }
// SLIP process a packet or a bunch of debug console chars static void ICACHE_FLASH_ATTR slip_process() { if (slip_len < 1) return; if (!slip_inpkt) { // debug console stuff console_process(slip_buf, slip_len); } else { // proper SLIP packet, invoke command processor after checking CRC //os_printf("SLIP: rcv %d\n", slip_len); if (slip_len > 2) { uint16_t crc = crc16_data((uint8_t*)slip_buf, slip_len-2, 0); uint16_t rcv = ((uint16_t)slip_buf[slip_len-2]) | ((uint16_t)slip_buf[slip_len-1] << 8); if (crc == rcv) { CMD_parse_packet((uint8_t*)slip_buf, slip_len-2); } else { os_printf("SLIP: bad CRC, crc=%x rcv=%x\n", crc, rcv); #ifdef SLIP_DBG for (short i=0; i<slip_len; i++) { if (slip_buf[i] >= ' ' && slip_buf[i] <= '~') os_printf("%c", slip_buf[i]); else os_printf("\\%02X", slip_buf[i]); } os_printf("\n"); #endif } } } }
/*---------------------------------------------------------------------------*/ static int prepare(const void *payload, unsigned short payload_len) { uint8_t i; uint16_t checksum; RIMESTATS_ADD(lltx); if(tx_in_progress) { return 1; } if(payload_len > 127 || payload == NULL) { return 1; } /* Copy payload to (soft) Ttx buffer */ memcpy(tx_frame_buffer.uPayload.au8Byte, payload, payload_len); i = payload_len; #if CRC_SW /* Compute CRC */ checksum = crc16_data(payload, payload_len, 0); tx_frame_buffer.uPayload.au8Byte[i++] = checksum; tx_frame_buffer.uPayload.au8Byte[i++] = (checksum >> 8) & 0xff; tx_frame_buffer.u8PayloadLength = payload_len + CHECKSUM_LEN; #else tx_frame_buffer.u8PayloadLength = payload_len; #endif return 0; }
/*---------------------------------------------------------------------------*/ static int cc2420_prepare(const void *payload, unsigned short payload_len) { uint8_t total_len; #if CC2420_CONF_CHECKSUM uint16_t checksum; #endif /* CC2420_CONF_CHECKSUM */ GET_LOCK(); PRINTF("cc2420: sending %d bytes\n", payload_len); RIMESTATS_ADD(lltx); /* Wait for any previous transmission to finish. */ /* while(status() & BV(CC2420_TX_ACTIVE));*/ /* Write packet to TX FIFO. */ strobe(CC2420_SFLUSHTX); #if CC2420_CONF_CHECKSUM checksum = crc16_data(payload, payload_len, 0); #endif /* CC2420_CONF_CHECKSUM */ total_len = payload_len + AUX_LEN; CC2420_WRITE_FIFO_BUF(&total_len, 1); CC2420_WRITE_FIFO_BUF(payload, payload_len); #if CC2420_CONF_CHECKSUM CC2420_WRITE_FIFO_BUF(&checksum, CHECKSUM_LEN); #endif /* CC2420_CONF_CHECKSUM */ RELEASE_LOCK(); return 0; }
/*---------------------------------------------------------------------------*/ static void recv_uc(struct unicast_conn *c, const linkaddr_t *from) { struct cmd_msg *msg; uint16_t crc; int len; msg = packetbuf_dataptr(); if(packetbuf_datalen() > 1 + CMDMSG_HDR_SIZE) { /* First ensure that the old process is killed. */ process_exit(&shell_sendcmd_server_process); len = packetbuf_datalen() - 1 - CMDMSG_HDR_SIZE; /* Make sure that the incoming command is null-terminated. */ msg->sendcmd[len] = 0; memcpy(&crc, &msg->crc, sizeof(crc)); if(crc == crc16_data((unsigned char *)msg->sendcmd, len, 0)) { /* Start the server process with the incoming command. */ process_start(&shell_sendcmd_server_process, (void *)msg->sendcmd); } } }
static void send_page(struct deluge_object *obj, unsigned pagenum) { unsigned char buf[S_PAGE]; struct deluge_msg_packet pkt; unsigned char *cp; pkt.cmd = DELUGE_CMD_PACKET; pkt.pagenum = pagenum; pkt.version = obj->pages[pagenum].version; pkt.packetnum = 0; pkt.object_id = obj->object_id; pkt.crc = 0; read_page(obj, pagenum, buf); /* Divide the page into packets and send them one at a time. */ for(cp = buf; cp + S_PKT <= (unsigned char *)&buf[S_PAGE]; cp += S_PKT) { if(obj->tx_set & (1 << pkt.packetnum)) { pkt.crc = crc16_data(cp, S_PKT, 0); memcpy(pkt.payload, cp, S_PKT); packetbuf_copyfrom(&pkt, sizeof(pkt)); broadcast_send(&deluge_broadcast); } pkt.packetnum++; } obj->tx_set = 0; }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(shell_netcmd_process, ev, data) { struct trickle_msg *msg; int len; PROCESS_BEGIN(); /* Get the length of the command line, excluding a terminating NUL character. */ len = strlen((char *)data); /* Check the length of the command line to see that it is small enough to fit in a packet. We count with 32 bytes of header, which may be a little too much, but at least we are on the safe side. */ if(len > PACKETBUF_SIZE - 32) { char buf[32]; snprintf(buf, sizeof(buf), "%d", len); shell_output_str(&netcmd_command, "command line too large: ", buf); } else { packetbuf_clear(); msg = packetbuf_dataptr(); packetbuf_set_datalen(len + 1 + TRICKLEMSG_HDR_SIZE); strcpy(msg->netcmd, data); /* Terminate the string with a NUL character. */ msg->netcmd[len] = 0; msg->crc = crc16_data(msg->netcmd, len, 0); printf("netcmd sending '%s'\n", msg->netcmd); trickle_send(&trickle); } PROCESS_END(); }
// Adds data to a response, returns the partial CRC uint16_t ICACHE_FLASH_ATTR CMD_ResponseBody(uint16_t crc_in, uint8_t* data, short len) { short pad_len = len+3 - (len+3)%4; // round up to multiple of 4 CMD_ProtoWriteBuf((uint8_t*)&pad_len, 2); crc_in = crc16_data((uint8_t*)&pad_len, 2, crc_in); CMD_ProtoWriteBuf(data, len); crc_in = crc16_data(data, len, crc_in); if (pad_len > len) { uint32_t temp = 0; CMD_ProtoWriteBuf((uint8_t*)&temp, pad_len-len); crc_in = crc16_data((uint8_t*)&temp, pad_len-len, crc_in); } return crc_in; }
uint16_t ESP::request(uint16_t cmd, uint32_t callback, uint32_t _return, uint16_t argc) { uint16_t crc = 0; _serial->write(0x7E); write((uint8_t*)&cmd, 2); crc = crc16_data((uint8_t*)&cmd, 2, crc); write((uint8_t*)&callback, 4); crc = crc16_data((uint8_t*)&callback, 4, crc); write((uint8_t*)&_return, 4); crc = crc16_data((uint8_t*)&_return, 4, crc); write((uint8_t*)&argc, 2); crc = crc16_data((uint8_t*)&argc, 2, crc); return crc; }
/*---------------------------------------------------------------------------*/ static int read(void *buf, unsigned short bufsize) { int len = 0; uint16_t radio_last_rx_crc; uint8_t radio_last_rx_crc_ok = 1; len = input_frame_buffer->u8PayloadLength; if(len <= CHECKSUM_LEN) { input_frame_buffer->u8PayloadLength = 0; return 0; } else { len -= CHECKSUM_LEN; /* Check CRC */ #if CRC_SW uint16_t checksum = crc16_data(input_frame_buffer->uPayload.au8Byte, len, 0); radio_last_rx_crc = (uint16_t)(input_frame_buffer->uPayload.au8Byte[len + 1] << (uint16_t)8) | input_frame_buffer->uPayload.au8Byte[len]; radio_last_rx_crc_ok = (checksum == radio_last_rx_crc); if(!radio_last_rx_crc_ok) { RIMESTATS_ADD(badcrc); } #endif /* CRC_SW */ if(radio_last_rx_crc_ok) { /* If we are in poll mode we need to check the frame here */ if(poll_mode) { if(frame_filtering && !is_packet_for_us(input_frame_buffer->uPayload.au8Byte, len, 0)) { len = 0; } else { read_last_rssi(); } } if(len != 0) { bufsize = MIN(len, bufsize); memcpy(buf, input_frame_buffer->uPayload.au8Byte, bufsize); RIMESTATS_ADD(llrx); if(!poll_mode) { /* Not in poll mode: packetbuf should not be accessed in interrupt context */ packetbuf_set_attr(PACKETBUF_ATTR_RSSI, radio_last_rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, radio_last_correlation); } } } else { len = 0; } /* Disable further read attempts */ input_frame_buffer->u8PayloadLength = 0; } return len; }
void ESP::protoCompletedCb(void) { PACKET_CMD *cmd = (PACKET_CMD*)_proto.buf; uint16_t crc = 0, argc, len, resp_crc; uint8_t *data_ptr; argc = cmd->argc; data_ptr = (uint8_t*)&cmd->args ; crc = crc16_data((uint8_t*)&cmd->cmd, 12, crc); while(argc--){ len = *((uint16_t*)data_ptr); crc = crc16_data(data_ptr, 2, crc); data_ptr += 2; while(len --){ crc = crc16_data(data_ptr, 1, crc); data_ptr ++; } } resp_crc = *(uint16_t*)data_ptr; if(crc != resp_crc) { INFO("ARDUINO: Invalid CRC"); return; } FP<void, void*> *fp; if(cmd->callback != 0){ fp = (FP<void, void*>*)cmd->callback; return_cmd = cmd->cmd; return_value = cmd->_return; if(fp->attached()) (*fp)((void*)cmd); } else { if(cmd->argc == 0) { is_return = true; return_cmd = cmd->cmd; return_value = cmd->_return; } } }
uint16_t ESP::request(uint16_t crc_in, uint8_t* data, uint16_t len) { uint8_t temp = 0; uint16_t pad_len = len; while(pad_len % 4 != 0) pad_len++; write((uint8_t*)&pad_len, 2); crc_in = crc16_data((uint8_t*)&pad_len, 2, crc_in); while(len --){ write(*data); crc_in = crc16_data((uint8_t*)data, 1, crc_in); data ++; if(pad_len > 0) pad_len --; } while(pad_len --){ write(temp); crc_in = crc16_data((uint8_t*)&temp, 1, crc_in); } return crc_in; }
static void ICACHE_FLASH_ATTR protoCompletedCb() { uint16_t crc = 0, argc, len, resp_crc, argn = 0; uint8_t *data_ptr; PACKET_CMD *packet; packet = (PACKET_CMD*)protoRxBuf; data_ptr = (uint8_t*)&packet->args ; crc = crc16_data((uint8_t*)&packet->cmd, 12, crc); argc = packet->argc; INFO("CMD: %d, cb: %d, ret: %d, argc: %d\r\n", packet->cmd, packet->callback, packet->_return, packet->argc); while(argc--){ len = *((uint16_t*)data_ptr); INFO("Arg[%d], len: %d:", argn++, len); crc = crc16_data(data_ptr, 2, crc); data_ptr += 2; crc = crc16_data(data_ptr, len, crc); while(len --){ INFO("%02X-", *data_ptr); data_ptr ++; } INFO("\r\n\r\n"); } resp_crc = *(uint16_t*)data_ptr; INFO("Read CRC: %04X, calculated crc: %04X\r\n", resp_crc, crc); if(crc != resp_crc) { INFO("ESP: Invalid CRC\r\n"); INFO(""); return; } CMD_Exec(commands, packet); }
/*---------------------------------------------------------------------------*/ static void recv_collect(const rimeaddr_t *originator, u8_t seqno, u8_t hops) { struct collect_msg *collect_msg; rtimer_clock_t latency; int len; collect_msg = packetbuf_dataptr(); #if TIMESYNCH_CONF_ENABLED latency = timesynch_time() - collect_msg->timestamp; #else latency = 0; #endif if(waiting_for_collect) { struct { uint16_t len; uint16_t originator; uint16_t seqno; uint16_t hops; uint16_t latency; } msg; if(packetbuf_datalen() >= COLLECT_MSG_HDRSIZE) { len = packetbuf_datalen() - COLLECT_MSG_HDRSIZE; if(collect_msg->crc == crc16_data(collect_msg->data, len, 0)) { msg.len = 5 + (packetbuf_datalen() - COLLECT_MSG_HDRSIZE) / 2; rimeaddr_copy((rimeaddr_t *)&msg.originator, originator); msg.seqno = seqno; msg.hops = hops; msg.latency = latency; /* printf("recv_collect datalen %d\n", packetbuf_datalen());*/ shell_output(&collect_command, &msg, sizeof(msg), collect_msg->data, packetbuf_datalen() - COLLECT_MSG_HDRSIZE); } } } else if(waiting_for_nodes) { char buf[40]; snprintf(buf, sizeof(buf), "%d.%d, %d hops, latency %lu ms", originator->u8[0], originator->u8[1], hops, (1000L * latency) / RTIMER_ARCH_SECOND); shell_output_str(&nodes_command, "Message from node ", buf); messages_received++; } }
ICACHE_FLASH_ATTR uint16 CMD_ResponseBody(uint16_t crc_in, uint8_t* data, uint16_t len) { uint8_t temp = 0; uint16_t pad_len = len; while(pad_len % 4 != 0) pad_len++; CMD_ProtoWriteBuf((uint8_t*)&pad_len, 2); crc_in = crc16_data((uint8_t*)&pad_len, 2, crc_in); while(len --){ CMD_ProtoWrite(*data); crc_in = crc16_data((uint8_t*)data, 1, crc_in); data ++; if(pad_len > 0) pad_len --; } while(pad_len --){ CMD_ProtoWrite(temp); crc_in = crc16_data((uint8_t*)&temp, 1, crc_in); } return crc_in; }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(shell_sendcmd_process, ev, data) { struct cmd_msg *msg; int len; linkaddr_t addr; const char *nextptr; char buf[32]; PROCESS_BEGIN(); addr.u8[0] = shell_strtolong(data, &nextptr); if(nextptr == data || *nextptr != '.') { shell_output_str(&sendcmd_command, "sendcmd <node addr>: receiver must be specified", ""); PROCESS_EXIT(); } ++nextptr; addr.u8[1] = shell_strtolong(nextptr, &nextptr); snprintf(buf, sizeof(buf), "%d.%d", addr.u8[0], addr.u8[1]); shell_output_str(&sendcmd_command, "Sending command to ", buf); /* Get the length of the command line, excluding a terminating NUL character. */ len = strlen((char *)nextptr); /* Check the length of the command line to see that it is small enough to fit in a packet. We count with 32 bytes of header, which may be a little too much, but at least we are on the safe side. */ if(len > PACKETBUF_SIZE - 32) { snprintf(buf, sizeof(buf), "%d", len); shell_output_str(&sendcmd_command, "command line too large: ", buf); PROCESS_EXIT(); } packetbuf_clear(); msg = packetbuf_dataptr(); packetbuf_set_datalen(len + 1 + CMDMSG_HDR_SIZE); strcpy(msg->sendcmd, nextptr); /* Terminate the string with a NUL character. */ msg->sendcmd[len] = 0; msg->crc = crc16_data((unsigned char *)msg->sendcmd, len, 0); /* printf("sendcmd sending '%s'\n", msg->sendcmd);*/ unicast_send(&uc, &addr); PROCESS_END(); }
static void init_page(struct deluge_object *obj, int pagenum, int have) { struct deluge_page *page; unsigned char buf[S_PAGE]; page = &obj->pages[pagenum]; page->flags = 0; page->last_request = 0; page->last_data = 0; if(have) { page->version = obj->version; page->packet_set = ALL_PACKETS; page->flags |= PAGE_COMPLETE; read_page(obj, pagenum, buf); page->crc = crc16_data(buf, S_PAGE, 0); } else { page->version = 0; page->packet_set = 0; } }
// SLIP process a packet or a bunch of debug console chars static void ICACHE_FLASH_ATTR slip_process() { if (slip_len > 2) { // proper SLIP packet, invoke command processor after checking CRC //os_printf("SLIP: rcv %d\n", slip_len); uint16_t crc = crc16_data((uint8_t*)slip_buf, slip_len-2, 0); uint16_t rcv = ((uint16_t)slip_buf[slip_len-2]) | ((uint16_t)slip_buf[slip_len-1] << 8); if (crc == rcv) { cmdParsePacket((uint8_t*)slip_buf, slip_len-2); } else { os_printf("SLIP: bad CRC, crc=%04x rcv=%04x len=%d\n", crc, rcv, slip_len); for (short i=0; i<slip_len; i++) { if (slip_buf[i] >= ' ' && slip_buf[i] <= '~') { DBG("%c", slip_buf[i]); } else { DBG("\\%02X", slip_buf[i]); } } DBG("\n"); } } }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(shell_send_process, ev, data) { struct shell_input *input; int len; struct collect_msg *msg; PROCESS_BEGIN(); while(1) { PROCESS_WAIT_EVENT_UNTIL(ev == shell_event_input); input = data; len = input->len1 + input->len2; if(len == 0) { PROCESS_EXIT(); } if(len < PACKETBUF_SIZE) { packetbuf_clear(); packetbuf_set_datalen(len + COLLECT_MSG_HDRSIZE); msg = packetbuf_dataptr(); memcpy(msg->data, input->data1, input->len1); memcpy(msg->data + input->len1, input->data2, input->len2); #if TIMESYNCH_CONF_ENABLED msg->timestamp = timesynch_time(); #else msg->timestamp = 0; #endif msg->crc = crc16_data(msg->data, len, 0); /* printf("Sending %d bytes\n", len);*/ collect_send(&collect, COLLECT_REXMITS); } } PROCESS_END(); }
/*! *\brief This callback is called by the kernel when a packet is * received on the epoch-syncer broadcast channel. In here we compute * the time offsets that we use to control the epoch timing, e.g. by * delaying or anticipating the next epoch. */ static void __broadcast_recv_cb(struct broadcast_conn *ptr, const rimeaddr_t *sender) { int datalen; int distance_nr_epochs; long int now, offset; struct epoch_sync_packet packet; /* * Get the current time first-thing; this will be used in the * computation of the epoch offset */ now = clock_time(); /* * TODO: we could use the packet rssi to seed tha random number generator * * ! iff the radio operates on lower power modes: otherwise the rssi is the same * constant all the time * * if (0) { * uint16_t rssi; * * rssi = packetbuf_attr(PACKETBUF_ATTR_RSSI); * printf("rssi=0x%.4x\n", rssi); * } */ datalen = packetbuf_datalen(); if (datalen != sizeof(struct epoch_sync_packet)) { /* * xfer corruption; happens rarely. */ trace("@%d sync xfer corruption, datalen %d\n", __epoch_syncer.epoch, datalen); return; } /* * Copy the received packet into local storage * * ! the pointer returned by packetbuf_dataptr() is not necesserely aligned * wrt the mcu platform requirements, thus we cannot simply dereference * it into a 'struct epoch_sync_packet'. The msp430, in particular, can * have undefined behaviour when loading from unaligned addresses. */ memcpy(&packet, packetbuf_dataptr(), datalen); #ifdef XFER_CRC16 { uint16_t recv_crc16, crc16; /* * Compute the received packet crc with the .crc16 field zeroed */ recv_crc16 = packet.crc16; packet.crc16 = 0; crc16 = crc16_data((const unsigned char *)&packet, sizeof(struct epoch_sync_packet), 0); if (recv_crc16 != crc16) { /* * xfer corruption; happens rarely. */ trace("@%d sync xfer crc mismatch\n", __epoch_syncer.epoch); return; } } #endif /* * The packet is valid: compute the offset between our and the * other node's `time to end of epoch`. * * ! If we are sufficiently out-of-sync than this node and the * sender node are currently in different epochs and we need to * special case a bit. */ offset = 0; distance_nr_epochs = __epoch_syncer.epoch - packet.epoch; if (distance_nr_epochs > 0) { /* * We are going too fast but we don't care, we simply let slower * nodes adjust to us. * * ! don't trace the sender and return. */ printf("epoch-syncer: discarding packet from epoch %d at epoch %d\n", packet.epoch, __epoch_syncer.epoch); return; } else if (distance_nr_epochs < 0) { long int time_to_epoch_end; /* * We are going too slow ! */ if (distance_nr_epochs == -1) { assert(__epoch_syncer.epoch_end_time > now); time_to_epoch_end = (long int)__epoch_syncer.epoch_end_time - now; offset = time_to_epoch_end + packet.time_from_epoch_start; } else { offset = __epoch_syncer.epoch_interval*(packet.epoch - __epoch_syncer.epoch); } } else { long int time_from_epoch_start, time_to_epoch_end; /* * Both this node and the sender node are in the same epoch. */ if (now > __epoch_syncer.epoch_end_time) { /* * The epoch is expired but the epoch counter has not been updated yet. * If this happens there is a *bug*: something is delaying the epoch_timer `is-expired` * check in the process main loop. * * ! we can't and don't want to recover from this situation: go fix your changes in the code :) */ printf("@%d BUG epoch-syncer: packet received after end-of-epoch %ld\n", __epoch_syncer.epoch, now - (long int)__epoch_syncer.epoch_end_time); return; } /* * compute this node's `time from epoch start` and `time to epoch end` */ assert(now <= __epoch_syncer.epoch_end_time); assert(__epoch_syncer.epoch_start_time <= now); assert(__epoch_syncer.epoch_end_time >__epoch_syncer.epoch_start_time); time_from_epoch_start = now - __epoch_syncer.epoch_start_time; assert(time_from_epoch_start >= 0); assert(time_from_epoch_start < (__epoch_syncer.epoch_end_time -__epoch_syncer.epoch_start_time)); time_to_epoch_end = __epoch_syncer.epoch_end_time - now; /* * compute the `time to epoch end` offset between this node and the sender node */ offset = time_to_epoch_end - packet.time_to_epoch_end; /* * linearly interpolate to guess the eventual offset at end of this node epoch */ offset = (offset*__epoch_syncer.epoch_interval)/time_from_epoch_start; } /* update offset statistics */ __epoch_syncer.max_offset = max(offset, __epoch_syncer.max_offset); __epoch_syncer.min_offset = min(offset, __epoch_syncer.min_offset); /* * Accumulate the offsets: from this sum the `offset-average` can be computed. * This average is then used to adjust the timing of the next epoch. */ __epoch_syncer.sum_sync_offsets += offset; __epoch_syncer.nr_offsets++; #ifdef TRACK_CONNECTIONS /* trace the xfer */ connection_track(CONNECTION_TRACK_SYNC, packet.board_id16, __epoch_syncer.epoch); #endif }
static void handle_packet(struct deluge_msg_packet *msg) { struct deluge_page *page; uint16_t crc; struct deluge_msg_packet packet; memcpy(&packet, msg, sizeof(packet)); PRINTF("Incoming packet for object id %u, version %u, page %u, packet num %u!\n", (unsigned)packet.object_id, (unsigned)packet.version, (unsigned)packet.pagenum, (unsigned)packet.packetnum); if(packet.pagenum != current_object.current_rx_page) { return; } if(packet.version != current_object.version) { neighbor_inconsistency = 1; } page = ¤t_object.pages[packet.pagenum]; if(packet.version == page->version && !(page->flags & PAGE_COMPLETE)) { memcpy(¤t_object.current_page[S_PKT * packet.packetnum], packet.payload, S_PKT); crc = crc16_data(packet.payload, S_PKT, 0); if(packet.crc != crc) { PRINTF("packet crc: %hu, calculated crc: %hu\n", packet.crc, crc); return; } page->last_data = clock_time(); page->packet_set |= (1 << packet.packetnum); if(page->packet_set == ALL_PACKETS) { /* This is the last packet of the requested page; stop streaming. */ packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_PACKET_TYPE_STREAM_END); write_page(¤t_object, packet.pagenum, current_object.current_page); page->version = packet.version; page->flags = PAGE_COMPLETE; PRINTF("Page %u completed\n", packet.pagenum); current_object.current_rx_page++; if(packet.pagenum == OBJECT_PAGE_COUNT(current_object) - 1) { current_object.version = current_object.update_version; leds_on(LEDS_RED); PRINTF("Update completed for object %u, version %u\n", (unsigned)current_object.object_id, packet.version); } else if(current_object.current_rx_page < OBJECT_PAGE_COUNT(current_object)) { if(ctimer_expired(&rx_timer)) { ctimer_set(&rx_timer, CONST_OMEGA * ESTIMATED_TX_TIME + (random_rand() % T_R), send_request, ¤t_object); } } /* Deluge R.3 */ transition(DELUGE_STATE_MAINTAIN); } else { /* More packets to come. Put lower layers in streaming mode. */ packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_PACKET_TYPE_STREAM); } } }
PROCESS_THREAD(proc_epoch_syncer, ev, data) { static struct etimer send_timer; static struct etimer epoch_timer; static const struct broadcast_callbacks broadcast_cbs = {__broadcast_recv_cb, __broadcast_sent_cb}; static struct broadcast_conn conn; PROCESS_EXITHANDLER(broadcast_close(&conn)); PROCESS_BEGIN(); #ifdef TRACK_CONNECTIONS /* Log the node id */ printf("board-id64 0x%.16llx\n", board_get_id64()); #endif #ifdef XFER_CRC16 /* Log the node id */ printf("xfer crc16\n"); #endif printf("epoch interval %ld ticks\n", EPOCH_INTERVAL); /* * Alloc the two syncer events */ evt_epoch_synced = process_alloc_event(); evt_end_of_epoch = process_alloc_event(); /* * Open a `connection` on the syncer broadcasting channel */ broadcast_open(&conn, BROADCAST_CHANNEL_TIMESYNC, &broadcast_cbs); /* * init the epoch-syncer instance */ epoch_syncer_init(&__epoch_syncer); /* * This is the main syncer loop. Initially we try to sync the * epoch between nodes without concurrently running any other * algo. After a period, at which time the network is synced, * we start generating epoch events which can be * consumed by, e.g., the estimator process. */ etimer_set(&epoch_timer, __epoch_syncer.epoch_interval); __epoch_syncer.epoch_start_time = clock_time(); __epoch_syncer.epoch_end_time = etimer_expiration_time(&epoch_timer); while (1) { /* * The start of a new epoch ! */ epoch_syncer_at_epoch_start(&__epoch_syncer); clock_time_t now; clock_time_t time_to_epoch_end; now = clock_time(); assert(__epoch_syncer.epoch_end_time == etimer_expiration_time(&epoch_timer)); assert(__epoch_syncer.epoch_end_time > now); time_to_epoch_end = __epoch_syncer.epoch_end_time - now; /* * Setup a random wait time before sending the sync packet * * ! we cannot let send_timer delay the epoch_timer, especially * when the next `end-of-epoch-time` has been anticipated by a lot * (this can happen at startup) */ if (time_to_epoch_end > __epoch_syncer.epoch_sync_start) { long int send_wait; long int send_wait_rnd; long int rnd; rnd = rand(); send_wait_rnd = (unsigned)rnd % (unsigned) __epoch_syncer.epoch_sync_xfer_interval; send_wait = __epoch_syncer.epoch_sync_start + send_wait_rnd; assert(send_wait >= __epoch_syncer.epoch_sync_start); assert(send_wait <= __epoch_syncer.epoch_sync_start + __epoch_syncer.epoch_sync_xfer_interval); if (send_wait > time_to_epoch_end) send_wait = __epoch_syncer.epoch_sync_start; assert(send_wait < time_to_epoch_end); etimer_set(&send_timer, send_wait); PROCESS_WAIT_UNTIL(etimer_expired(&send_timer)); /* * Acquire the radio lock * * ! we don't use WAIT/YIELD_UNTIL() because * 1) we do not want to yield if we can acquire the lock on the first try * 2) no kernel signal is generated when the lock is released (we would `deadlock') */ do { if (!radio_trylock()) break; PROCESS_PAUSE(); } while (1); { clock_time_t now; struct epoch_sync_packet packet; /* * broadcast the sync packet * * ! We put this part into its own block since non static stack * variables/allocations in the parent block wouldn't get preserved trough * kernel calls (e.g. the PROCESS_PAUSE() a few lines above) */ #ifdef TRACK_CONNECTIONS packet.board_id16 = board_get_id16(); #endif packet.epoch = __epoch_syncer.epoch; now = clock_time(); assert(now > __epoch_syncer.epoch_start_time); assert(__epoch_syncer.epoch_end_time > now); packet.time_from_epoch_start = now - __epoch_syncer.epoch_start_time; packet.time_to_epoch_end = __epoch_syncer.epoch_end_time - now; #ifdef XFER_CRC16 /* * Compute the packet crc with the .crc16 field zeroed */ { uint16_t crc16; packet.crc16 = 0; crc16 = crc16_data((const unsigned char *)&packet, sizeof(struct epoch_sync_packet), 0); packet.crc16 = crc16; } #endif packetbuf_copyfrom(&packet, sizeof(struct epoch_sync_packet)); broadcast_send(&conn); } } else { printf("epoch-syncer: skipping sync send\n"); } /* * We cannot YIELD here: if epoch_timer has already expired there won't be * any event to wake us up. * * FIXME: if we get here and the epoch timer has fired * already print by how much we are late: this can be terribly useful * to trace bugs in the epoch sync code or the kernel. */ if (etimer_expired(&epoch_timer)) { long int now; now = clock_time(); assert(now > __epoch_syncer.epoch_end_time); } else { char do_wait; do_wait = 1; if (__epoch_syncer.sum_sync_offsets) { long int avg_offset = __epoch_syncer.sum_sync_offsets / __epoch_syncer.nr_offsets; const long int threshold = CLOCK_SECOND; if (avg_offset > threshold) { /* * if we are late don't wait until the timer expires * ! this migth give us the opportunity to re-enter the right sync_xfer_interval */ do_wait = 0; } else if (avg_offset < -threshold) { /* * we are too fast, delay end of epoch */ clock_time_t now; clock_time_t time_to_epoch_end; now = clock_time(); assert(__epoch_syncer.epoch_end_time == etimer_expiration_time(&epoch_timer)); assert(__epoch_syncer.epoch_end_time > now); time_to_epoch_end = __epoch_syncer.epoch_end_time - now; long int delay = time_to_epoch_end + (-avg_offset/2); static struct etimer delay_timer; trace("epoch-syncer: delaying end-of-epoch by %ld ticks\n", (-avg_offset/2)); etimer_set(&delay_timer, delay); __epoch_syncer.epoch_end_time += (-avg_offset/2); PROCESS_WAIT_UNTIL(etimer_expired(&delay_timer)); } } if (do_wait) { PROCESS_WAIT_UNTIL(etimer_expired(&epoch_timer)); } else { trace("epoch-syncer: not waiting for end-of-epoch\n"); } } trace("epoch-syncer: epoch %d ended\n", __epoch_syncer.epoch); #ifdef TRACK_CONNECTIONS connection_print_and_zero(CONNECTION_TRACK_SYNC, __epoch_syncer.epoch); #endif /* * Re-Set the end-of-epoch timer */ if (__epoch_syncer.epoch == EPOCHS_UNTIL_SYNCED) { /* * We have hopefully achieved sync at this point * * 1) update the epoch timings, and set the epoch timer * * 2) signal the size-estimator process that the epoch is now synced */ __epoch_syncer.epoch_interval = EPOCH_INTERVAL; __epoch_syncer.epoch_sync_start = EPOCH_SYNC_START; __epoch_syncer.epoch_sync_xfer_interval = EPOCH_SYNC_XFER_INTERVAL; etimer_stop(&epoch_timer); etimer_set(&epoch_timer, __epoch_syncer.epoch_interval); /* * The epoch timer has been re-set: update the time until the next epoch end * Increase the epoch count. * ! these operations must happen in a block which cannot block in kernel calls */ __epoch_syncer.epoch_start_time = clock_time(); __epoch_syncer.epoch_end_time = etimer_expiration_time(&epoch_timer); __epoch_syncer.epoch++; process_post(&proc_size_estimator, evt_epoch_synced, NULL); } else { /* * Re-set and adjust the epoch timer using the data received trough sync packets * (in this epoch) * * ! using re-set (instead of, e.g., restart) is important here in order to avoid * drifting */ etimer_reset(&epoch_timer); /* * The epoch timer has been re-set: update the time until the next epoch end * Increase the epoch count. * ! these operations must happen in a block which cannot block in kernel calls */ //__epoch_syncer.epoch_start_time = epoch_timer.timer.start; __epoch_syncer.epoch_start_time = clock_time(); __epoch_syncer.epoch_end_time = etimer_expiration_time(&epoch_timer); __epoch_syncer.epoch++; if (__epoch_syncer.sum_sync_offsets) { long int avg_offset = __epoch_syncer.sum_sync_offsets / __epoch_syncer.nr_offsets; const long int threshold = 1;//(CLOCK_SECOND/32);//*3; #if __CONTIKI_NETSTACK_RDC==__CONTIKI_NETSTACK_RDC_NULL const int tx_delay = 0; #elif __CONTIKI_NETSTACK_RDC==__CONTIKI_NETSTACK_RDC_CXMAC /* * When the cxmac RDC is used we must consider an added delay due to the fact that when * other nodes radios are turned off the sync packet must be re-sent. */ const int tx_delay = 8; #endif /* * estimate the avg tx delay */ avg_offset += tx_delay; trace("epoch-syncer: sync offsets %d ~ %ld < %ld < %ld\n", __epoch_syncer.nr_offsets, __epoch_syncer.min_offset + tx_delay, avg_offset, __epoch_syncer.max_offset+tx_delay); if ((avg_offset < -threshold) || (avg_offset > threshold)) { clock_time_t new_expiration_time; const long int adjust_threshold = CLOCK_SECOND/2; long int adjust; /* * feedback control the next expiration time */ adjust = -avg_offset/2; adjust = min(adjust, adjust_threshold); adjust = max(adjust, -adjust_threshold); if (adjust) etimer_adjust(&epoch_timer, adjust); new_expiration_time = etimer_expiration_time(&epoch_timer); __epoch_syncer.epoch_end_time = new_expiration_time; } } if (__epoch_syncer.epoch > EPOCHS_UNTIL_SYNCED) { /* * Signal the estimator-process that this epoch has ended */ process_post(&proc_size_estimator, evt_end_of_epoch, NULL); } } } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ int nrf24l01_read(void *buf, unsigned short bufsize) { uint8_t *framep; // uint8_t footer[2]; uint8_t len; #if RF230_CONF_CHECKSUM uint16_t checksum; #endif /* RF230_CONF_CHECKSUM */ #if RF230_CONF_TIMESTAMPS struct timestamp t; #endif /* RF230_CONF_TIMESTAMPS */ PRINTF("rf230_read: %u bytes lqi %u crc %u\n",rxframe.length,rxframe.lqi,rxframe.crc); #if DEBUG>1 for (len=0;len<rxframe.length;len++) PRINTF(" %x",rxframe.data[len]);PRINTF("\n"); #endif if (rxframe.length==0) { return 0; } #if RF230_CONF_TIMESTAMPS bomb if(interrupt_time_set) { rf230_time_of_arrival = interrupt_time; interrupt_time_set = 0; } else { rf230_time_of_arrival = 0; } rf230_time_of_departure = 0; #endif /* RF230_CONF_TIMESTAMPS */ GET_LOCK(); // if(rxframe.length > RF230_MAX_PACKET_LEN) { // // Oops, we must be out of sync. // flushrx(); // RIMESTATS_ADD(badsynch); // RELEASE_LOCK(); // return 0; // } //hal returns two extra bytes containing the checksum //below works because auxlen is 2 len = rxframe.length; if(len <= AUX_LEN) { // flushrx(); RIMESTATS_ADD(tooshort); RELEASE_LOCK(); return 0; } if(len - AUX_LEN > bufsize) { // flushrx(); RIMESTATS_ADD(toolong); RELEASE_LOCK(); return 0; } /* Transfer the frame, stripping the checksum */ framep=&(rxframe.data[0]); memcpy(buf,framep,len-2); /* Clear the length field to allow buffering of the next packet */ rxframe.length=0; // framep+=len-AUX_LEN+2; #if RADIOSTATS RF230_receivepackets++; #endif #if RF230_CONF_CHECKSUM bomb memcpy(&checksum,framep,CHECKSUM_LEN); framep+=CHECKSUM_LEN; #endif /* RF230_CONF_CHECKSUM */ #if RF230_CONF_TIMESTAMPS bomb memcpy(&t,framep,TIMESTAMP_LEN); framep+=TIMESTAMP_LEN; #endif /* RF230_CONF_TIMESTAMPS */ // memcpy(&footer,framep,FOOTER_LEN); #if RF230_CONF_CHECKSUM bomb if(checksum != crc16_data(buf, len - AUX_LEN, 0)) { PRINTF("rf230: checksum failed 0x%04x != 0x%04x\n", checksum, crc16_data(buf, len - AUX_LEN, 0)); } if(footer[1] & FOOTER1_CRC_OK && checksum == crc16_data(buf, len - AUX_LEN, 0)) { #else if (rxframe.crc) { #endif /* RF230_CONF_CHECKSUM */ #if RADIOSTATS RF230_rsigsi=hal_subregister_read( SR_RSSI ); #endif //nick packetbuf_set_attr(PACKETBUF_ATTR_RSSI, hal_subregister_read( SR_RSSI )); //nick packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, rxframe.lqi); RIMESTATS_ADD(llrx); #if RF230_CONF_TIMESTAMPS bomb rf230_time_of_departure = t.time + setup_time_for_transmission + (total_time_for_transmission * (len - 2)) / total_transmission_len; rf230_authority_level_of_sender = t.authority_level; packetbuf_set_attr(PACKETBUF_ATTR_TIMESTAMP, t.time); #endif /* RF230_CONF_TIMESTAMPS */ } else { PRINTF("rf230: Bad CRC\n"); #if RADIOSTATS RF230_receivefail++; #endif RIMESTATS_ADD(badcrc); len = AUX_LEN; } // if (?) /* Another packet has been received and needs attention. */ // process_poll(&nrf24l01_process); // } RELEASE_LOCK(); if(len < AUX_LEN) { return 0; } return len - AUX_LEN; } /*---------------------------------------------------------------------------*/ void nrf24l01_init(uint8_t mode) { rf_mode = mode; /* Initialize Hardware Abstraction Layer. */ //hal_init(); //init the spi functions spi_init(); SPI_CHIP_ENABLE(); if(RF_TX_MODE == mode) //tx mode { SPI_WRITE_REG(WRITE_REG, 0x0C); //RX_DR, TX_DS, MAX_RT interrupts enabled, CRC enabled, CRC encoding with 2bytes and as PTX //SPI_WRITE_REG(WRITE_REG+EN_AA, 0x3F); //Enable auto-acknowledge for all data pipe //SPI_WRITE_REG(WRITE_REG+EN_RXADDR, 0x01); //Enable RX address data pipe 0, reset value is 0x03 (data pipe 0 and 1) //SPI_WRITE_REG(WRITE_REG+SETUP_AW, 0x03); //Setup of address width, reset value is 0x33--5 bytes SPI_WRITE_REG(WRITE_REG+SETUP_RETR, 0xFF); //Set auto-retransmision, ARD(auto retransmit delay): 1111, ARC(auto retransmit count): 1111 //SPI_WRITE_REG(WRITE_REG+RF_CH, 0x02); //RF Channel 2 (default, not really needed) //SPI_WRITE_REG(WRITE_REG+RF_SETUP, 0x03); //Air data rate 1Mbit, -12dBm, Setup LNA //SPI_WRITE_BUF(WRITE_REG+RX_ADDR_P0, (uint8_t*)&TX_ADDRESS, ADDR_WIDTH); //Set receive address to receive aut-ACK, it is equal to TX_ADDR if enbel enhanced shock burst //SPI_WRITE_BUF(WRITE_REG+TX_ADDR, (uint8_t*)&TX_ADDRESS, ADDR_WIDTH); //Set transmit address: 0xE7E7E7E7E7 SPI_WRITE_REG(WRITE_REG+RX_PW_P0, 0x04); // 4 byte receive payload //the next 2 commands are relative with dynamic payload lenght, you need disable them if use static payload length //enable dynamic payload length, enable dynamic ACK in specific package(then you can //use command W_TX_PAYLOAD_NOACK to set a specfic package that needn't wait for ACK) SPI_WRITE_REG(WRITE_REG+DYNPD, 0x01); //as PTX, at least enable pipe 0 SPI_WRITE_REG(WRITE_REG+FEATURE, 0x05); //SPI_WRITE_REG(WRITE_REG, 0x0E); //power upr } else //rx mode { SPI_WRITE_REG(WRITE_REG, 0x0D); //RX_DR, TX_DS, MAX_RT interrupts enabled, CRC enabled, CRC encoding with 2bytes and as PRX //SPI_WRITE_REG(WRITE_REG+EN_AA, 0x3F); //Enable auto-acknowledge for all data pipes(0-5) SPI_WRITE_REG(WRITE_REG+EN_RXADDR, 0x3F); //Enable RX address for all data pipes(0-5) //SPI_WRITE_REG(WRITE_REG+SETUP_AW, 0x03); //Setup of address width, reset value is 0x33--5 bytes SPI_WRITE_REG(WRITE_REG+SETUP_RETR, 0xFF); //Set auto-retransmision, ARD(auto retransmit delay): 1111, ARC(auto retransmit count): 1111 //SPI_WRITE_REG(WRITE_REG+RF_CH, 0x02); //RF Channel 2 (default, not really needed) //SPI_WRITE_REG(WRITE_REG+RF_SETUP, 0x03); //Air data rate 1Mbit, -12dBm, Setup LNA //SPI_WRITE_BUF(WRITE_REG+RX_ADDR_P0, (uint8_t*)&TX_ADDRESS, ADDR_WIDTH); //Set receive address for pipe0 //SPI_WRITE_BUF(WRITE_REG+RX_ADDR_P1, (uint8_t*)&RX_ADDRESS, ADDR_WIDTH); //Set receive address for pipe1 //SPI_WRITE_REG(WRITE_REG+RX_ADDR_P2, 0XC3); //Set receive address for pipe2 //SPI_WRITE_REG(WRITE_REG+RX_ADDR_P3, 0XC4); //Set receive address for pipe3 //SPI_WRITE_REG(WRITE_REG+RX_ADDR_P4, 0XC5); //Set receive address for pipe4 //SPI_WRITE_REG(WRITE_REG+RX_ADDR_P5, 0XC6); //Set receive address for pipe5 SPI_WRITE_REG(WRITE_REG+RX_PW_P0, 0x04); // 4 byte receive payload for pipe 0 SPI_WRITE_REG(WRITE_REG+RX_PW_P1, 0x04); // 4 byte receive payload SPI_WRITE_REG(WRITE_REG+RX_PW_P2, 0x04); // 4 byte receive payload SPI_WRITE_REG(WRITE_REG+RX_PW_P3, 0x04); // 4 byte receive payload SPI_WRITE_REG(WRITE_REG+RX_PW_P4, 0x04); // 4 byte receive payload SPI_WRITE_REG(WRITE_REG+RX_PW_P5, 0x04); // 4 byte receive payload for pipe 5 //don't use static payload length /*SPI_WRITE_REG(WRITE_REG+RX_PW_P0, 0xFF); //data pipe 0, number of bytes: 32 SPI_WRITE_REG(WRITE_REG+RX_PW_P1, 0xFF); //data pipe 1, number of bytes: 32 SPI_WRITE_REG(WRITE_REG+RX_PW_P2, 0xFF); //data pipe 2, number of bytes: 32 SPI_WRITE_REG(WRITE_REG+RX_PW_P3, 0xFF); //data pipe 3, number of bytes: 32 SPI_WRITE_REG(WRITE_REG+RX_PW_P4, 0xFF); //data pipe 4, number of bytes: 32 SPI_WRITE_REG(WRITE_REG+RX_PW_P5, 0xFF); //data pipe 5, number of bytes: 32 */ SPI_WRITE_REG(WRITE_REG+DYNPD, 0x3F); //as PRX, enable all pipes SPI_WRITE_REG(WRITE_REG+FEATURE, 0x05); //enable dynamic payload length //SPI_WRITE_REG(WRITE_REG, 0x0F); //power upr } SPI_CHIP_DISABLE(); /* Start the packet receive process */ process_start(&nrf24l01_process, NULL); }
/*---------------------------------------------------------------------------*/ static int cc2420_read(void *buf, unsigned short bufsize) { uint8_t footer[2]; uint8_t len; #if CC2420_CONF_CHECKSUM uint16_t checksum; #endif /* CC2420_CONF_CHECKSUM */ if(!CC2420_FIFOP_IS_1) { return 0; } /* if(!pending) { return 0; }*/ pending = 0; GET_LOCK(); cc2420_packets_read++; getrxbyte(&len); if(len > CC2420_MAX_PACKET_LEN) { /* Oops, we must be out of sync. */ flushrx(); RIMESTATS_ADD(badsynch); RELEASE_LOCK(); return 0; } if(len <= AUX_LEN) { flushrx(); RIMESTATS_ADD(tooshort); RELEASE_LOCK(); return 0; } if(len - AUX_LEN > bufsize) { flushrx(); RIMESTATS_ADD(toolong); RELEASE_LOCK(); return 0; } getrxdata(buf, len - AUX_LEN); #if CC2420_CONF_CHECKSUM getrxdata(&checksum, CHECKSUM_LEN); #endif /* CC2420_CONF_CHECKSUM */ getrxdata(footer, FOOTER_LEN); #if CC2420_CONF_CHECKSUM if(checksum != crc16_data(buf, len - AUX_LEN, 0)) { PRINTF("checksum failed 0x%04x != 0x%04x\n", checksum, crc16_data(buf, len - AUX_LEN, 0)); } if(footer[1] & FOOTER1_CRC_OK && checksum == crc16_data(buf, len - AUX_LEN, 0)) { #else if(footer[1] & FOOTER1_CRC_OK) { #endif /* CC2420_CONF_CHECKSUM */ cc2420_last_rssi = footer[0]; cc2420_last_correlation = footer[1] & FOOTER1_CORRELATION; packetbuf_set_attr(PACKETBUF_ATTR_RSSI, cc2420_last_rssi); packetbuf_set_attr(PACKETBUF_ATTR_LINK_QUALITY, cc2420_last_correlation); RIMESTATS_ADD(llrx); } else { RIMESTATS_ADD(badcrc); len = AUX_LEN; } if(CC2420_FIFOP_IS_1) { if(!CC2420_FIFO_IS_1) { /* Clean up in case of FIFO overflow! This happens for every * full length frame and is signaled by FIFOP = 1 and FIFO = * 0. */ flushrx(); } else { /* Another packet has been received and needs attention. */ process_poll(&cc2420_process); } } RELEASE_LOCK(); if(len < AUX_LEN) { return 0; } return len - AUX_LEN; } /*---------------------------------------------------------------------------*/ void cc2420_set_txpower(uint8_t power) { GET_LOCK(); set_txpower(power); RELEASE_LOCK(); }
/*---------------------------------------------------------------------------*/ int cc2420_send(const void *payload, unsigned short payload_len) { int i; uint8_t total_len; struct timestamp timestamp; uint16_t checksum; GET_LOCK(); PRINTF("cc2420: sending %d bytes\n", payload_len); RIMESTATS_ADD(lltx); /* Wait for any previous transmission to finish. */ while(status() & BV(CC2420_TX_ACTIVE)); /* Write packet to TX FIFO. */ strobe(CC2420_SFLUSHTX); checksum = crc16_data(payload, payload_len, 0); total_len = payload_len + AUX_LEN; FASTSPI_WRITE_FIFO(&total_len, 1); FASTSPI_WRITE_FIFO(payload, payload_len); FASTSPI_WRITE_FIFO(&checksum, CHECKSUM_LEN); #if CC2420_CONF_TIMESTAMPS timestamp.authority_level = timesynch_authority_level(); timestamp.time = timesynch_time(); FASTSPI_WRITE_FIFO(×tamp, TIMESTAMP_LEN); #endif /* CC2420_CONF_TIMESTAMPS */ /* The TX FIFO can only hold one packet. Make sure to not overrun * FIFO by waiting for transmission to start here and synchronizing * with the CC2420_TX_ACTIVE check in cc2420_send. * * Note that we may have to wait up to 320 us (20 symbols) before * transmission starts. */ #ifdef TMOTE_SKY #define LOOP_20_SYMBOLS 100 /* 326us (msp430 @ 2.4576MHz) */ #elif __AVR__ #define LOOP_20_SYMBOLS 500 /* XXX */ #endif #if WITH_SEND_CCA strobe(CC2420_SRXON); while(!(status() & BV(CC2420_RSSI_VALID))); strobe(CC2420_STXONCCA); #else /* WITH_SEND_CCA */ strobe(CC2420_STXON); #endif /* WITH_SEND_CCA */ for(i = LOOP_20_SYMBOLS; i > 0; i--) { if(SFD_IS_1) { #if CC2420_CONF_TIMESTAMPS rtimer_clock_t txtime = timesynch_time(); #endif /* CC2420_CONF_TIMESTAMPS */ if(receive_on) { ENERGEST_OFF(ENERGEST_TYPE_LISTEN); } ENERGEST_ON(ENERGEST_TYPE_TRANSMIT); /* We wait until transmission has ended so that we get an accurate measurement of the transmission time.*/ while(status() & BV(CC2420_TX_ACTIVE)); #if CC2420_CONF_TIMESTAMPS setup_time_for_transmission = txtime - timestamp.time; if(num_transmissions < 10000) { total_time_for_transmission += timesynch_time() - txtime; total_transmission_len += total_len; num_transmissions++; } #endif /* CC2420_CONF_TIMESTAMPS */ #ifdef ENERGEST_CONF_LEVELDEVICE_LEVELS ENERGEST_OFF_LEVEL(ENERGEST_TYPE_TRANSMIT,cc2420_get_txpower()); #endif ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT); if(receive_on) { ENERGEST_ON(ENERGEST_TYPE_LISTEN); } RELEASE_LOCK(); return 0; } } /* If we are using WITH_SEND_CCA, we get here if the packet wasn't transmitted because of other channel activity. */ RIMESTATS_ADD(contentiondrop); PRINTF("cc2420: do_send() transmission never started\n"); RELEASE_LOCK(); return -3; /* Transmission never started! */ }
/*---------------------------------------------------------------------------*/ int cc2420_read(void *buf, unsigned short bufsize) { uint8_t footer[2]; uint8_t len; uint16_t checksum; struct timestamp t; if(!FIFOP_IS_1) { /* If FIFOP is 0, there is no packet in the RXFIFO. */ return 0; } if(interrupt_time_set) { #if CC2420_CONF_TIMESTAMPS cc2420_time_of_arrival = interrupt_time; #endif /* CC2420_CONF_TIMESTAMPS */ interrupt_time_set = 0; } else { cc2420_time_of_arrival = 0; } cc2420_time_of_departure = 0; GET_LOCK(); getrxbyte(&len); if(len > CC2420_MAX_PACKET_LEN) { /* Oops, we must be out of sync. */ flushrx(); RIMESTATS_ADD(badsynch); RELEASE_LOCK(); return 0; } if(len <= AUX_LEN) { flushrx(); RIMESTATS_ADD(tooshort); RELEASE_LOCK(); return 0; } if(len - AUX_LEN > bufsize) { flushrx(); RIMESTATS_ADD(toolong); RELEASE_LOCK(); return 0; } getrxdata(buf, len - AUX_LEN); getrxdata(&checksum, CHECKSUM_LEN); getrxdata(&t, TIMESTAMP_LEN); getrxdata(footer, FOOTER_LEN); if(footer[1] & FOOTER1_CRC_OK && checksum == crc16_data(buf, len - AUX_LEN, 0)) { cc2420_last_rssi = footer[0]; cc2420_last_correlation = footer[1] & FOOTER1_CORRELATION; RIMESTATS_ADD(llrx); #if CC2420_CONF_TIMESTAMPS cc2420_time_of_departure = t.time + setup_time_for_transmission + (total_time_for_transmission * (len - 2)) / total_transmission_len; cc2420_authority_level_of_sender = t.authority_level; #endif /* CC2420_CONF_TIMESTAMPS */ } else { RIMESTATS_ADD(badcrc); len = AUX_LEN; } /* Clean up in case of FIFO overflow! This happens for every full * length frame and is signaled by FIFOP = 1 and FIFO = 0. */ if(FIFOP_IS_1 && !FIFO_IS_1) { /* printf("cc2420_read: FIFOP_IS_1 1\n");*/ flushrx(); } else if(FIFOP_IS_1) { /* Another packet has been received and needs attention. */ process_poll(&cc2420_process); } RELEASE_LOCK(); if(len < AUX_LEN) { return 0; } return len - AUX_LEN; }
/*---------------------------------------------------------------------------*/ static uint16_t packet_hash(const void *data, size_t length) { return crc16_data(data, length, 0) & 0xFFFF; }