diff --git a/stack/apps/AT_modem/CMakeLists.txt b/stack/apps/AT_modem/CMakeLists.txt index 0c4cf16d4..f569021db 100644 --- a/stack/apps/AT_modem/CMakeLists.txt +++ b/stack/apps/AT_modem/CMakeLists.txt @@ -30,7 +30,8 @@ # #Add App specific linker flags -#Add newlib for this app -INSERT_LINKER_FLAGS(AFTER LINK_LIBRARIES INSERT "-fuse-clib=newlib") +IF(${PLATFORM} STREQUAL "cortus_fpga") + INSERT_LINKER_FLAGS(AFTER LINK_LIBRARIES INSERT "-fuse-clib=newlib") +ENDIF() APP_BUILD(NAME ${APP_NAME} SOURCES at_modem.c at_parser.c LIBS d7ap framework) diff --git a/stack/apps/AT_modem/at_modem.c b/stack/apps/AT_modem/at_modem.c index 8ac8ac0f7..156e180a5 100644 --- a/stack/apps/AT_modem/at_modem.c +++ b/stack/apps/AT_modem/at_modem.c @@ -52,7 +52,8 @@ #include "fec.h" -#if (!defined PLATFORM_EFM32GG_STK3700 && !defined PLATFORM_EZR32LG_WSTK6200A && !defined PLATFORM_CORTUS_FPGA) +#if (!defined PLATFORM_EFM32GG_STK3700 && !defined PLATFORM_EZR32LG_WSTK6200A && \ + !defined PLATFORM_CORTUS_FPGA && !defined PLATFORM_B_L072Z_LRWAN1) #error Mismatch between the configured platform and the actual platform. #endif @@ -78,7 +79,7 @@ // Carson's rule: 2 x fm + 2 x fd = 9.600 + 2 x 4.800 = 19.2 kHz // assuming 10 ppm crystals gives max error of: 2 * 10 ppm * 868 = 17.36 kHz // => BW > 19.2 + 17.36 kHz => > 36.5 kHZ. -#define RXBW_L 36500 //Hz +#define RXBW_L 10468 //Hz // normal rate #define BITRATE_N 55555 // bps @@ -86,7 +87,7 @@ // Carson's rule: 2 x fm + 2 x fd = 55.555 + 2 x 50 = 155.555 kHz // assuming 10 ppm crystals gives max error of: 2 * 10 ppm * 868 = 17.36 kHz // => BW > 155.555 + 17.36 => 172.91 KHz -#define RXBW_N 172910 //Hz +#define RXBW_N 78646 //Hz // high rate #define BITRATE_H 166667 // bps @@ -94,7 +95,7 @@ // Carson's rule: 2 x fm + 2 x fd = 166.667 + 2 x 41.667 = 250 kHz // assuming 10 ppm crystals gives max error of: 2 * 10 ppm * 868 = 17.36 kHz // => BW > 250 + 17.36 kHz => > 267.36 kHZ. -#define RXBW_H 267360 //Hz +#define RXBW_H 125868 //Hz typedef struct { @@ -102,6 +103,9 @@ typedef struct uint8_t __data[255]; } frame_t; +static uint8_t raw_tx_frame[255]; +static uint8_t raw_tx_frame_length; + static netdev_t *netdev; static uint8_t uart_rx_buffer[MAX_AT_COMMAND_SIZE] = { 0 }; @@ -134,8 +138,18 @@ static hwradio_init_args_t init_args; static state_t state = STATE_IDLE; +typedef enum +{ + CODING_RFU = 0x00, + CODING_PN9 = 0x01, + CODING_FEC = 0x02, + CODING_FEC_PN9 = 0x04 +} coding_t; + +static uint8_t current_encoding = 0; + static channel_id_t default_channel_id = { - .channel_header.ch_coding = PHY_CODING_PN9, + .channel_header.ch_coding = PHY_CODING_RFU, .channel_header.ch_class = PHY_CLASS_NORMAL_RATE, .channel_header.ch_freq_band = PHY_BAND_868, .center_freq_index = 0 @@ -155,8 +169,10 @@ static uint16_t missed_packets_counter = 0; static uint16_t received_packets_counter = 0; static uint64_t id; +static uint32_t time = 0; -bool refill_flag = 0; +bool refill_flag = false; +bool infinite_rx = false; static char cmd_tx_continuously(char *value); static char cmd_tx(char *value); @@ -179,7 +195,7 @@ static void channel_id_to_string(channel_id_t* channel, char* str, size_t len) { case PHY_BAND_915: strncpy(band, "915", sizeof(band)); break; } - snprintf(str, len, "%.3s%c%i", band, rate, channel->center_freq_index); + snprintf(str, len, "%.3s-%c-%i", band, rate, channel->center_freq_index); } static uint16_t encode_packet(uint8_t *data, uint16_t nbytes) @@ -187,12 +203,14 @@ static uint16_t encode_packet(uint8_t *data, uint16_t nbytes) uint16_t encoded_len = nbytes; #ifndef HAL_RADIO_USE_HW_FEC - if (current_channel_id.channel_header.ch_coding == PHY_CODING_FEC_PN9) + if (current_encoding == CODING_FEC) encoded_len = fec_encode(data, nbytes); #endif #ifndef HAL_RADIO_USE_HW_DC_FREE - pn9_encode(data, encoded_len); + if ((current_encoding == CODING_PN9) || + (current_encoding == CODING_FEC_PN9)) + pn9_encode(data, encoded_len); #endif return encoded_len; @@ -212,16 +230,21 @@ static void packet_received(hw_radio_packet_t* hw_radio_packet) DPRINT("packet received @ %i , RSSI = %i", hw_radio_packet->rx_meta.timestamp, hw_radio_packet->rx_meta.rssi); #ifndef HAL_RADIO_USE_HW_DC_FREE - pn9_encode(hw_radio_packet->data, hw_radio_packet->length); + if ((current_encoding == CODING_PN9) || + (current_encoding == CODING_FEC_PN9)) + pn9_encode(hw_radio_packet->data, hw_radio_packet->length); #endif #ifndef HAL_RADIO_USE_HW_FEC - if (current_channel_id.channel_header.ch_coding == PHY_CODING_FEC_PN9) + if (current_encoding == CODING_FEC) fec_decode_packet(hw_radio_packet->data, hw_radio_packet->length, hw_radio_packet->length); #endif - hw_radio_packet->length = hw_radio_packet->data[0] + 1; + DPRINT("len %i", hw_radio_packet->length); DPRINT_DATA(hw_radio_packet->data, hw_radio_packet->length); + if (infinite_rx) + return; + if (hw_radio_packet->rx_meta.crc_status == HW_CRC_UNAVAILABLE) { uint16_t crc; @@ -230,33 +253,46 @@ static void packet_received(hw_radio_packet_t* hw_radio_packet) if(memcmp(&crc, hw_radio_packet->data + hw_radio_packet->length - 2, 2) != 0) { DPRINT("CRC invalid"); + //DPRINT_DATA(hw_radio_packet->data, hw_radio_packet->length); missed_packets_counter++; return; } } else if (hw_radio_packet->rx_meta.crc_status == HW_CRC_INVALID) { - DPRINT("CRC invalid"); + DPRINT("CRC invalid %i", hw_radio_packet->length); +// DPRINT_DATA(hw_radio_packet->data, hw_radio_packet->length); missed_packets_counter++; return; } + if (hw_radio_packet->length < (1 + sizeof(uint64_t) + sizeof(uint16_t) + 2)) + return; + #if PLATFORM_NUM_LEDS > 0 led_toggle(0); #endif + + // if frame not formatted according the convention, return + if (hw_radio_packet->length < (1 + sizeof(uint64_t) + sizeof(uint16_t) + 2)) + return; + uint16_t msg_counter = 0; uint64_t msg_id; - uint16_t data_len = hw_radio_packet->length - sizeof(msg_id) - sizeof(msg_counter) - 2; + uint16_t data_len = hw_radio_packet->length - 1 - sizeof(msg_id) - sizeof(msg_counter) - 2; - char rx_data[PACKET_MAX_SIZE + 1]; + char rx_data[data_len + 1]; memcpy(&msg_id, hw_radio_packet->data + 1, sizeof(msg_id)); memcpy(&msg_counter, hw_radio_packet->data + 1 + sizeof(msg_id), sizeof(msg_counter)); memcpy(rx_data, hw_radio_packet->data + 1 + sizeof(msg_id) + sizeof(msg_counter), data_len); rx_data[data_len] = '\0'; - char chan[8]; + char chan[32]; channel_id_to_string(&default_channel_id, chan, sizeof(chan)); DPRINT("DATA received: %s", rx_data); - DPRINT("%7s, counter <%i>, rssi <%idBm>, msgId <%lu>, Id <%lu>, timestamp <%lu>", chan, msg_counter, hw_radio_packet->rx_meta.rssi, (unsigned long)msg_id, (unsigned long)id, hw_radio_packet->rx_meta.timestamp); + DPRINT("%s, counter <%i>, rssi <%idBm>, timestamp <%lu>", chan, msg_counter, hw_radio_packet->rx_meta.rssi, hw_radio_packet->rx_meta.timestamp); + + DPRINT("Packet emitted by node ID:"); + DPRINT_DATA(&msg_id, sizeof(msg_id)); if(counter == 0) { @@ -270,11 +306,13 @@ static void packet_received(hw_radio_packet_t* hw_radio_packet) { received_packets_counter++; counter++; + DPRINT("received_packets_counter: %d counter %d", received_packets_counter, counter); } else if(msg_counter > expected_counter) { missed_packets_counter += msg_counter - expected_counter; counter = msg_counter; + DPRINT("missed_packets_counter: %d counter %d", missed_packets_counter, counter); } double per = 0; @@ -286,17 +324,25 @@ static void packet_received(hw_radio_packet_t* hw_radio_packet) static void packet_header_received(uint8_t *data, uint8_t len) { - uint8_t packet_len; + uint16_t packet_len; DPRINT("Packet Header received %i\n", len); DPRINT_DATA(data, len); + if (infinite_rx) + { + hw_radio_set_payload_length(0xFF); + return; + } + assert(len == 4); #ifndef HAL_RADIO_USE_HW_DC_FREE - pn9_encode(data, len); + if ((current_encoding == CODING_PN9) || + (current_encoding == CODING_FEC_PN9)) + pn9_encode(data, len); #endif - if (current_channel_id.channel_header.ch_coding == PHY_CODING_FEC_PN9) + if (current_encoding == CODING_FEC) { #ifndef HAL_RADIO_USE_HW_FEC fec_decode_packet(data, len, len); @@ -307,21 +353,60 @@ static void packet_header_received(uint8_t *data, uint8_t len) packet_len = data[0] + 1 ; DPRINT("RX Packet Length: %i ", packet_len); + + if (packet_len <= 4) + { + DPRINT("No more data expected"); + + // restart RX + hw_radio_stop(); + hw_radio_set_opmode(HW_STATE_RX); + return; + } + // set PayloadLength to the length of the expected foreground frame hw_radio_set_payload_length(packet_len); } +static void cmd_tx_repeat() +{ + state = STATE_TX; + + counter++; + memcpy(tx_frame.hw_radio_packet.data, raw_tx_frame, raw_tx_frame_length); + tx_frame.hw_radio_packet.length = raw_tx_frame_length; + + // update only the counter and the resulting CRC + memcpy(tx_frame.hw_radio_packet.data + 1 + sizeof(id), &counter, sizeof(counter)); + +#ifndef HAL_RADIO_USE_HW_CRC + /* the CRC calculation shall include all the bytes of the frame including the byte for the length*/ + uint16_t crc = __builtin_bswap16(crc_calculate(tx_frame.hw_radio_packet.data, tx_frame.hw_radio_packet.length - 2)); + memcpy(tx_frame.hw_radio_packet.data + tx_frame.hw_radio_packet.length - 2, &crc, 2); +#endif + + DPRINT("Frame <%i>", counter); + DPRINT_DATA(tx_frame.hw_radio_packet.data, tx_frame.hw_radio_packet.length); + + // Encode the packet if not supported by xcvr + tx_frame.hw_radio_packet.length = encode_packet(tx_frame.hw_radio_packet.data, + tx_frame.hw_radio_packet.length); + + hw_radio_send_payload(tx_frame.hw_radio_packet.data, tx_frame.hw_radio_packet.length); +} + static void stop() { netopt_state_t opmode = NETOPT_STATE_STANDBY; netdev->driver->set(netdev, NETOPT_STATE, &opmode, sizeof(netopt_state_t)); // make sure to cancel tasks which might me pending already - /*if(state == STATE_TX) + if(state == STATE_TX) { timer_cancel_task(&cmd_tx_repeat); sched_cancel_task(&cmd_tx_repeat); - }*/ + time = 0; + } } static void packet_transmitted(timer_tick_t timestamp) @@ -329,22 +414,29 @@ static void packet_transmitted(timer_tick_t timestamp) assert(state == STATE_TX); DPRINT("Transmitted packet @ %i with length = %i", timestamp, tx_frame.hw_radio_packet.length); - state = STATE_IDLE; - - /* TODO Repeat ? - timer_tick_t delay; - if(tx_packet_delay_s == 0) - delay = TIMER_TICKS_PER_SEC * 5; - else - delay = TIMER_TICKS_PER_SEC * tx_packet_delay_s; - - timer_post_task_delay(&cmd_tx_repeat, delay); - */ + //state = STATE_IDLE; + if(time != 0) + { + DPRINT("Next TX in %u ms", time); + timer_post_task_delay(&cmd_tx_repeat, /*TIMER_TICKS_PER_SEC **/ time); + } + else { + stop(); + // Setting refill_flag to false + refill_flag = false; + // Unlimited Length packet format to set the Receive packet of arbitrary length + hw_radio_set_payload_length(0x00); // unlimited length mode + DPRINT("START FG scan @ %i", timer_get_counter_value()); + state = STATE_RX; + hw_radio_set_opmode(HW_STATE_RX); + DPRINT("Listen mode set\n"); + } } static void fill_in_fifo(uint8_t remaining_bytes_len) { //Refill the fifo with the same packet + //DPRINT("TX"); hw_radio_send_payload(tx_frame.hw_radio_packet.data, tx_frame.hw_radio_packet.length); } @@ -502,16 +594,16 @@ static char cmd_set_preamble_size(char *value) ret = at_parse_extract_number(value, &size); if (ret == AT_OK) - netdev->driver->set(netdev, NETOPT_PREAMBLE_LENGTH, &size, sizeof(uint16_t)); + netdev->driver->set(netdev, NETOPT_PREAMBLE_LENGTH, &size, sizeof(uint8_t)); return ret; } static char cmd_get_preamble_size(char *value) { - uint16_t size; + uint8_t size; - netdev->driver->get(netdev, NETOPT_PREAMBLE_LENGTH, &size, sizeof(uint16_t)); + netdev->driver->get(netdev, NETOPT_PREAMBLE_LENGTH, &size, sizeof(uint8_t)); snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+PRES: %d\r\n", size); return AT_OK; } @@ -532,7 +624,7 @@ static char cmd_get_preamble_polarity(char *value) { uint32_t polarity; - netdev->driver->set(netdev, NETOPT_PREAMBLE_POLARITY, &polarity, sizeof(uint8_t)); + netdev->driver->get(netdev, NETOPT_PREAMBLE_POLARITY, &polarity, sizeof(uint8_t)); snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+PREP: %d\r\n", (uint8_t)polarity); return AT_OK; } @@ -636,6 +728,34 @@ static char cmd_get_bandwidth(char *value) return AT_OK; } +static char cmd_set_eirp(char *value) +{ + char ret; + int32_t eirp; + + ret = at_parse_extract_signed_number(value, &eirp); + if (ret == AT_OK) + { + if (eirp < -128 || eirp > 127) + return AT_ERROR; + + netdev->driver->set(netdev, NETOPT_TX_POWER, &eirp, sizeof(int8_t)); + netdev->driver->get(netdev, NETOPT_TX_POWER, &eirp, sizeof(int8_t)); + snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+EIRP: %d\r\n", (int8_t)eirp); + } + + return ret; +} + +static char cmd_get_eirp(char *value) +{ + int8_t eirp; + + netdev->driver->get(netdev, NETOPT_TX_POWER, &eirp, sizeof(int8_t)); + snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+EIRP: %d\r\n", eirp); + return AT_OK; +} + static char cmd_set_rssi_threshold(char *value) { char ret; @@ -772,7 +892,7 @@ static char cmd_get_mod_shaping(char *value) uint8_t BT; netdev->driver->get(netdev, NETOPT_MOD_SHAPING, &BT, sizeof(uint8_t)); - snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+MODS: %d\r\n", BT); + snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+BT: %d\r\n", BT); return AT_OK; } @@ -824,18 +944,36 @@ static char cmd_set_fec_on(char *value) uint32_t enable; ret = at_parse_extract_number(value, &enable); - if (ret == AT_OK) - netdev->driver->set(netdev, NETOPT_FEC_ON, &enable, sizeof(uint8_t)); + if(ret == AT_ERROR) + return AT_ERROR; + snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+FEC: %d\r\n", (uint8_t)enable); + +#ifdef HAL_RADIO_USE_HW_FEC + netdev->driver->set(netdev, NETOPT_FEC_ON, &enable, sizeof(uint8_t)); +#else + if(enable == 0) + current_encoding &= ~CODING_FEC; + else + current_encoding |= CODING_FEC; +#endif return AT_OK; } static char cmd_get_fec_on(char *value) { +#ifdef HAL_RADIO_USE_HW_FEC uint8_t enable; netdev->driver->get(netdev, NETOPT_FEC_ON, &enable, sizeof(uint8_t)); - snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+FEC: %d\r\n", enable); + snprintf(value, MAX_AT_RESPONSE_SIZE, "+FEC: %d\r\n", enable); +#else + if((current_encoding & CODING_FEC) == CODING_FEC) + snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+FEC: 1\r\n"); + else + snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+FEC: 0\r\n"); +#endif + return AT_OK; } @@ -898,18 +1036,37 @@ static char cmd_set_dc_free_scheme(char *value) uint32_t scheme; ret = at_parse_extract_number(value, &scheme); - if (ret == AT_OK) - netdev->driver->set(netdev, NETOPT_DC_FREE_SCHEME, &scheme, sizeof(uint8_t)); + if(ret == AT_ERROR) + return AT_ERROR; + + snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+DCFREE: %d\r\n", (uint8_t)scheme); + +#ifdef HAL_RADIO_USE_HW_FEC + netdev->driver->set(netdev, NETOPT_DC_FREE_SCHEME, &scheme, sizeof(uint8_t)); +#else + if(scheme == 0) + current_encoding &= ~CODING_PN9; + else + current_encoding |= CODING_PN9; +#endif return AT_OK; } static char cmd_get_dc_free_scheme(char *value) { +#ifdef HAL_RADIO_USE_HW_FEC uint8_t scheme; netdev->driver->get(netdev, NETOPT_DC_FREE_SCHEME, &scheme, sizeof(uint8_t)); - snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+DCFREE: %d\r\n", scheme); + snprintf(value, MAX_AT_RESPONSE_SIZE, "+DCFREE: %d\r\n", scheme); +#else + if((current_encoding&CODING_PN9) == CODING_PN9) + snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+DCFREE: 1\r\n"); + else + snprintf(value, MAX_AT_RESPONSE_SIZE, "\r\n+DCFREE: 0\r\n"); +#endif + return AT_OK; } @@ -921,6 +1078,12 @@ static char cmd_start_rx(char *value) // Setting refill_flag to false refill_flag = false; + if (infinite_rx == false) + { + netopt_enable_t netopt_enable = NETOPT_ENABLE; + netdev->driver->set(netdev, NETOPT_RX_END_IRQ, &netopt_enable, sizeof(netopt_enable_t)); + } + // Unlimited Length packet format to set the Receive packet of arbitrary length hw_radio_set_payload_length(0x00); // unlimited length mode @@ -934,39 +1097,128 @@ static char cmd_start_rx(char *value) return AT_OK; } + +void atoh(char *ascii_ptr, char *hex_ptr, int len) +{ + int i; + + for(i = 0; i < (len / 2); i++) + { + + *(hex_ptr+i) = (*(ascii_ptr+(2*i)) <= '9') ? ((*(ascii_ptr+(2*i)) - '0') * 16 ) : (((*(ascii_ptr+(2*i)) - 'A') + 10) << 4); + *(hex_ptr+i) |= (*(ascii_ptr+(2*i)+1) <= '9') ? (*(ascii_ptr+(2*i)+1) - '0') : (*(ascii_ptr+(2*i)+1) - 'A' + 10); + } +} + + static char cmd_tx(char *value) { - DPRINT("Sending \"%s\" payload (%d bytes)\n", value, strlen(value)); + char data[strlen(value) + 1]; + uint8_t len = strlen(value); + + if(extract_field_number(value) > 2) + return AT_ERROR; + + if(at_parse_extract_string(value, data, &len) == AT_ERROR) + return AT_ERROR; + + // Check if a time interval is given. + // Otherwise cmd_tx was called from cmd_tx_continuously() + if(extract_field_number(value) == 2) + { + char *time_field = value + skip_to_next_field(value, strlen(value)); + if (at_parse_extract_number(time_field, &time) == AT_ERROR) + return AT_ERROR; + } + else { + time = 0; + } + + DPRINT("Sending \"%s\" payload (%d bytes)\n", data, len); state = STATE_TX; - tx_frame.hw_radio_packet.length = sizeof(id) + sizeof(counter) + strlen(value); - memcpy(tx_frame.hw_radio_packet.data + 1, &id, sizeof(id)); - memcpy(tx_frame.hw_radio_packet.data + 1 + sizeof(id), &counter, sizeof(counter)); - memcpy(tx_frame.hw_radio_packet.data + 1 + sizeof(id) + sizeof(counter), value, strlen(value)); + // ensure state is standby before switching to TX mode + hw_radio_set_opmode(HW_STATE_STANDBY); + infinite_rx = false; + + if(refill_flag) + { + if (len > 235) // 256 bytes -16 bytes preamble + 2 bytes sync + 1 bytes length + 2 bytes CRC + return AT_ERROR; + + hw_radio_enable_refill(true); + + uint8_t i = 0; + + if (len == 2) //fill the byte stream with this character + { + uint8_t hex_byte; + atoh(data, &hex_byte, 2); + for (i = 0; i < 32; i++) + tx_frame.hw_radio_packet.data[i] = hex_byte; + + tx_frame.hw_radio_packet.length = 32; + } + else + { + //fill the byte stream with the preamble + for (i = 0; i < 16; i++) + tx_frame.hw_radio_packet.data[i] = 0xAA; + + // insert the sync word (sync word = 0x192F + // Since all data in D7A is send MSB first, this means, the 0x19 is sent first, + tx_frame.hw_radio_packet.data[i++] = 0x19; + tx_frame.hw_radio_packet.data[i++] = 0x2F; + + // insert the byte length + tx_frame.hw_radio_packet.data[i++] = len + 2; + + memcpy(tx_frame.hw_radio_packet.data + i, data, len); + + uint16_t crc = __builtin_bswap16(crc_calculate(tx_frame.hw_radio_packet.data + 18, len + 1)); + memcpy(tx_frame.hw_radio_packet.data + i + len, &crc, 2); + + tx_frame.hw_radio_packet.length = 16 + 2 + 1 + len + 2; + } + + DPRINT("Frame <%d>", tx_frame.hw_radio_packet.length); + DPRINT_DATA(tx_frame.hw_radio_packet.data, tx_frame.hw_radio_packet.length); + + hw_radio_set_payload_length(tx_frame.hw_radio_packet.length); + } + else + { + hw_radio_enable_refill(false); + counter++; + tx_frame.hw_radio_packet.length = 1 + sizeof(id) + sizeof(counter) + len; + memcpy(tx_frame.hw_radio_packet.data + 1, &id, sizeof(id)); + memcpy(tx_frame.hw_radio_packet.data + 1 + sizeof(id), &counter, sizeof(counter)); + memcpy(tx_frame.hw_radio_packet.data + 1 + sizeof(id) + sizeof(counter), data, len); + tx_frame.hw_radio_packet.data[0] = tx_frame.hw_radio_packet.length -1 + sizeof(uint16_t); /* CRC is an uint16_t */; #ifndef HAL_RADIO_USE_HW_CRC - /* the CRC calculation shall include all the bytes of the frame including the byte for the length*/ - uint16_t crc = __builtin_bswap16(crc_calculate(tx_frame.hw_radio_packet.data, tx_frame.hw_radio_packet.length + 1 - 2)); - memcpy(tx_frame.hw_radio_packet.data + 1 + sizeof(id) + sizeof(counter) + strlen(value), &crc, 2); - tx_frame.hw_radio_packet.length += sizeof(uint16_t); /* CRC is an uint16_t */ + /* the CRC calculation shall include all the bytes of the frame including the byte for the length*/ + uint16_t crc = __builtin_bswap16(crc_calculate(tx_frame.hw_radio_packet.data, tx_frame.hw_radio_packet.length)); + memcpy(tx_frame.hw_radio_packet.data + tx_frame.hw_radio_packet.length, &crc, 2); + tx_frame.hw_radio_packet.length += sizeof(uint16_t); /* CRC is an uint16_t */ #endif - tx_frame.hw_radio_packet.data[0] = tx_frame.hw_radio_packet.length; - tx_frame.hw_radio_packet.length +=1; - - DPRINT("Frame <%i>", counter); - DPRINT_DATA(tx_frame.hw_radio_packet.data, tx_frame.hw_radio_packet.length); + DPRINT("Frame <%i>", counter); + DPRINT_DATA(tx_frame.hw_radio_packet.data, tx_frame.hw_radio_packet.length); - // Encode the packet if not supported by xcvr - tx_frame.hw_radio_packet.length = encode_packet(tx_frame.hw_radio_packet.data, - tx_frame.hw_radio_packet.length); + //backup the initial frame + memcpy(raw_tx_frame, tx_frame.hw_radio_packet.data, tx_frame.hw_radio_packet.length); + raw_tx_frame_length = tx_frame.hw_radio_packet.length; - DPRINT("Encoded frame len<%i>", tx_frame.hw_radio_packet.length); - DPRINT_DATA(tx_frame.hw_radio_packet.data, tx_frame.hw_radio_packet.length); + // Encode the packet if not supported by xcvr + tx_frame.hw_radio_packet.length = encode_packet(tx_frame.hw_radio_packet.data, + tx_frame.hw_radio_packet.length); + // DPRINT("Encoded frame len<%i>", tx_frame.hw_radio_packet.length); + // DPRINT_DATA(tx_frame.hw_radio_packet.data, tx_frame.hw_radio_packet.length); - if(refill_flag) - hw_radio_enable_refill(true); + hw_radio_set_payload_length(tx_frame.hw_radio_packet.length + sizeof(uint16_t)); + } if (hw_radio_send_payload(tx_frame.hw_radio_packet.data, tx_frame.hw_radio_packet.length) == -ENOTSUP) { DPRINT("Cannot send: radio is still transmitting"); @@ -983,6 +1235,16 @@ static char cmd_tx_continuously(char *value) return (cmd_tx(value)); } +static char cmd_start_rx_continuously(char *value) +{ + // If you need traces, increase the baudrate to 576000 + infinite_rx = true; + netopt_enable_t netopt_enable = NETOPT_DISABLE; + netdev->driver->set(netdev, NETOPT_RX_END_IRQ, &netopt_enable, sizeof(netopt_enable_t)); + return (cmd_start_rx(value)); +} + + static uint32_t get_parameter(netopt_t opt, size_t maxlen) { uint32_t value = 0x00000000; @@ -1118,20 +1380,22 @@ static char cmd_print_help(char *value); { "+SYNCW", cmd_set_syncword, cmd_get_sync_word, "", "get/set syncword"}, { "+SYNC", cmd_set_sync_on, cmd_get_sync_on, "", "toggle SyncOn"}, - { "+CHANNEL", cmd_set_center_freq, cmd_get_center_freq, "","get/set RF center frequency"}, + { "+CFREQ", cmd_set_center_freq, cmd_get_center_freq, "","get/set RF center frequency"}, { "+RXBW", cmd_set_bandwidth, cmd_get_bandwidth, "","get/set bandwith"}, { "+FDEV", cmd_set_fdev, cmd_get_fdev, "","get/set fdev"}, { "+BR", cmd_set_bitrate, cmd_get_bitrate, "","get/set bitrate"}, { "+BT", cmd_set_mod_shaping, cmd_get_mod_shaping, "", "get/set modulation shaping"}, - { "+DCFREE", cmd_set_dc_free_scheme, cmd_get_dc_free_scheme, "%d", "get/set the DC free coding scheme"}, - { "+FEC", cmd_set_fec_on, cmd_get_fec_on, "%d", "get/set the FEC encoder"}, + { "+DCFREE", cmd_set_dc_free_scheme, cmd_get_dc_free_scheme, "<%d>", "get/set the DC free coding scheme"}, + { "+FEC", cmd_set_fec_on, cmd_get_fec_on, "<%d>", "get/set the FEC encoder"}, { "+MODE", cmd_set_opmode, cmd_get_opmode, "<%d>", "get/set operation mode"}, { "+PAYLEN", cmd_set_payload_length, NULL, "<%d>", "set payload length"}, - { "+TX", cmd_tx, NULL, "<%d or string>","transmit packet over phy"}, + { "+TX", cmd_tx, NULL, "<%d or string>,[time (ms)]","transmit packet over phy [every X msec]"}, { "+TXC", cmd_tx_continuously, NULL, "<%d or string>", "transmit continuously same packet over phy"}, { "+RX", cmd_start_rx, NULL, "","start RX"}, + { "+RXC", cmd_start_rx_continuously, NULL, "","start RX in continuous mode"}, + { "+EIRP", cmd_set_eirp, cmd_get_eirp, "%d", "get/set the TX power"}, { "+STATUS", cmd_print_status, cmd_print_status, "","print status"}, { "+HELP", cmd_print_help, cmd_print_help, "","this list of commands"}, @@ -1143,12 +1407,12 @@ static char cmd_print_help(char *value) int i; char help_item[MAX_AT_RESPONSE_SIZE]; - snprintf(help_item, MAX_AT_RESPONSE_SIZE, "%-10s %-14s %s\r\n", "Command", "Arg", "Description"); + snprintf(help_item, MAX_AT_RESPONSE_SIZE, "%-10s %-25s %s\r\n", "Command", "Arg", "Description"); console_print(help_item); console_print("------------------------------------------------------\r\n"); for (i = 0; cmd_items[i].cmd != NULL ; i++) { - snprintf(help_item, MAX_AT_RESPONSE_SIZE, "%-10s %-14s %s\r\n", + snprintf(help_item, MAX_AT_RESPONSE_SIZE, "%-10s %-25s %s\r\n", cmd_items[i].cmd, cmd_items[i].arg_descr, cmd_items[i].description); console_print(help_item); } @@ -1226,7 +1490,10 @@ void bootstrap() { #endif #ifdef HAL_RADIO_USE_HW_DC_FREE - hw_radio_set_dc_free(HW_DC_FREE_WHITENING); + if (default_channel_id.channel_header.ch_coding == PHY_CODING_RFU) + hw_radio_set_dc_free(HW_DC_FREE_NONE); + else + hw_radio_set_dc_free(HW_DC_FREE_WHITENING); #else hw_radio_set_dc_free(HW_DC_FREE_NONE); #endif @@ -1244,6 +1511,7 @@ void bootstrap() { console_set_rx_interrupt_callback(&uart_rx_cb); sched_register_task(&process_uart_rx_fifo); + sched_register_task(&cmd_tx_repeat); // put in RX mode by default cmd_start_rx(NULL); diff --git a/stack/apps/AT_modem/at_parser.c b/stack/apps/AT_modem/at_parser.c index 095e2bb70..7c2973bbe 100644 --- a/stack/apps/AT_modem/at_parser.c +++ b/stack/apps/AT_modem/at_parser.c @@ -188,12 +188,12 @@ char at_parse_line(string_t line, char *ret) { ms_array_slice_to_string(line, index_write_start, line_len - 1, ret); result = at_execute_command(temp, ret, state); - ret[0] = 0; + //ret[0] = 0; } else { result = at_execute_command(temp, ret, state); - ret[0] = 0; + //ret[0] = 0; } break; @@ -204,7 +204,6 @@ char at_parse_line(string_t line, char *ret) return result; } - char at_parse_extract_number(string_t parameter, uint32_t *number) { int pos = 0; @@ -224,6 +223,56 @@ char at_parse_extract_number(string_t parameter, uint32_t *number) return AT_OK; } +char at_parse_extract_signed_number(string_t parameter, int32_t *number) +{ + int pos = 0; + int32_t value = 0; + int sign = 1; + + if ((uint8_t)parameter[pos]=='-') + { + sign = -1; + pos += 1; + } + + while (parameter[pos] >= '0' && parameter[pos] <= '9') { + value = value * 10 + (int32_t)(parameter[pos] - '0'); + pos += 1; + } + + if (pos == 0) + return AT_ERROR; + + if (number) + *number = (value * sign); + + return AT_OK; +} + +char at_parse_extract_string(string_t parameter, char *string, uint8_t *string_len) +{ + int pos = 0; + int len = strlen((const char *)parameter); + + // check if the size of the string is compatible with the size of the expected number + if (*string_len < len) + return AT_ERROR; + + while ((pos < len) && (parameter[pos] != ',')) + { + pos += 1; + } + + if (pos == 0) + return AT_ERROR; + + strncpy(string, parameter, pos); + string[pos] = '\0'; + *string_len = pos; + + return AT_OK; +} + char at_parse_extract_hexstring(string_t parameter, uint8_t *bytes, uint8_t *bytes_len) { int pos = 0; @@ -251,15 +300,42 @@ char at_parse_extract_hexstring(string_t parameter, uint8_t *bytes, uint8_t *byt unsigned byte ; sscanf( ¶meter[i * 2], "%02X", &byte ) ; - DPRINT("byte <%x>", byte); + //DPRINT("byte <%x>", byte); //DPRINT("parameter + pos %s ", ¶meter[pos]); //sscanf(¶meter[pos], "%02hhx", buf); bytes[i] = byte; - DPRINT("byte[%d]=0x%X", i, bytes[i]); + //DPRINT("byte[%d]=0x%X", i, bytes[i]); } return AT_OK; } + +int skip_to_next_field(char *line, int len) +{ + int pos = 0; + + while (pos < len && line[pos] != ',') + pos += 1; + + if (pos < len && line[pos] == ',') + pos += 1; + + line += pos; + return pos; +} + +int extract_field_number(char *line) +{ + int ret = 1; + + for(int i=0; i < strlen(line); i++) + { + if(line[i] == ',') + ret++; + } + + return ret; +} diff --git a/stack/apps/AT_modem/at_parser.h b/stack/apps/AT_modem/at_parser.h index 79412d821..40c13748d 100644 --- a/stack/apps/AT_modem/at_parser.h +++ b/stack/apps/AT_modem/at_parser.h @@ -57,6 +57,10 @@ typedef struct _at_command void at_register_command(string_t command, at_callback getter, at_callback setter/*, at_callback test, at_callback execute*/); char at_parse_line(string_t line, char *ret); char at_parse_extract_number(string_t parameter, uint32_t *number); +char at_parse_extract_signed_number(string_t parameter, int32_t *number); char at_parse_extract_hexstring(string_t parameter, uint8_t *bytes, uint8_t *bytes_len); +char at_parse_extract_string(string_t parameter, char *string, uint8_t *string_len); +int skip_to_next_field(char *line, int len); +int extract_field_number(char *line); #endif //__AT_PARSER_H diff --git a/stack/framework/hal/chips/cortus/Bsp/machine/spi.h b/stack/framework/hal/chips/cortus/Bsp/machine/spi.h index cfab82193..f51e7db31 100644 --- a/stack/framework/hal/chips/cortus/Bsp/machine/spi.h +++ b/stack/framework/hal/chips/cortus/Bsp/machine/spi.h @@ -71,7 +71,7 @@ typedef struct SPI } SPI; -/*************** Bit definition for SPI_TX_STATUS register ******************/ +/*************** Bit definition ******************/ #define SPI_TX_SR_FIFO_NOT_FULL 0x01 /*!< space in the fifo - bit 0 of spi.tx_status*/ #define SPI_RX_SR_DATA_AVAILABLE 0x01 /*!< data available in fifo - bit 0 of spi.rx_status*/ #define SPI_BUS_ACTIVE 0x01 /*!< activity on spi bus - bit 0 of spi.bus_active*/ diff --git a/stack/framework/hal/chips/cortus/cortus_system.c b/stack/framework/hal/chips/cortus/cortus_system.c index 7650e45f4..dce240b0b 100644 --- a/stack/framework/hal/chips/cortus/cortus_system.c +++ b/stack/framework/hal/chips/cortus/cortus_system.c @@ -69,5 +69,6 @@ uint32_t hw_get_battery(void) system_reboot_reason_t hw_system_reboot_reason() { - return REBOOT_REASON_NOT_IMPLEMENTED; + //TODO + return REBOOT_REASON_NOT_IMPLEMENTED; } diff --git a/stack/framework/hal/chips/cortus/cortus_timer.c b/stack/framework/hal/chips/cortus/cortus_timer.c index 769c359f9..08df8764d 100644 --- a/stack/framework/hal/chips/cortus/cortus_timer.c +++ b/stack/framework/hal/chips/cortus/cortus_timer.c @@ -169,6 +169,8 @@ error_t hw_timer_schedule(hwtimer_id_t timer_id, hwtimer_tick_t tick ) timer1_cmpb->enable = 1; timer1_cmpb->mask = 1; end_atomic(); + + return SUCCESS; } @@ -184,6 +186,8 @@ error_t hw_timer_cancel(hwtimer_id_t timer_id) timer1_cmpb->status = 0; timer1_cmpb->enable = 0; end_atomic(); + + return SUCCESS; } @@ -206,6 +210,8 @@ error_t hw_timer_counter_reset(hwtimer_id_t timer_id) timer1_cmpa->enable = 1; timer1_cmpa->mask = 1; end_atomic(); + + return SUCCESS; } diff --git a/stack/framework/hal/chips/cortus/cortus_uart.c b/stack/framework/hal/chips/cortus/cortus_uart.c index 710a4036d..945a5632d 100644 --- a/stack/framework/hal/chips/cortus/cortus_uart.c +++ b/stack/framework/hal/chips/cortus/cortus_uart.c @@ -57,7 +57,8 @@ bool uart_enable(uart_handle_t* uart_handle) { while(uart1->rx_status) dump = uart1->rx_data; - uart1->rx_mask = 1; /* start Rx interrupt */ + /* starting Rx interrupt should be done with uart_rx_interrupt_enable */ + uart1->rx_mask = 0; return true; } diff --git a/stack/framework/hal/chips/netdev_driver/inc/sx127x.h b/stack/framework/hal/chips/netdev_driver/inc/sx127x.h index b64028410..feaecc2eb 100644 --- a/stack/framework/hal/chips/netdev_driver/inc/sx127x.h +++ b/stack/framework/hal/chips/netdev_driver/inc/sx127x.h @@ -209,7 +209,7 @@ typedef struct { typedef struct { uint16_t preamble_len; /**< Length of preamble header */ uint8_t sync_len; /**< Length of sync word */ - uint8_t power; /**< Signal power */ + int8_t power; /**< Signal power */ uint8_t bandwidth; /**< Signal bandwidth */ uint8_t datarate; /**< bitrate in bps */ @@ -662,7 +662,7 @@ void sx127x_set_payload_length(sx127x_t *dev, uint16_t len); * * @return the radio power */ -uint8_t sx127x_get_tx_power(const sx127x_t *dev); +int8_t sx127x_get_tx_power(const sx127x_t *dev); /** * @brief Sets the SX127X transmission power diff --git a/stack/framework/hal/chips/netdev_driver/netdev.c b/stack/framework/hal/chips/netdev_driver/netdev.c index 50fac1065..caf588f4f 100644 --- a/stack/framework/hal/chips/netdev_driver/netdev.c +++ b/stack/framework/hal/chips/netdev_driver/netdev.c @@ -63,7 +63,7 @@ static tx_refill_callback_t tx_refill_callback; static netdev_t *netdev; static void isr_handler(void *arg) { - DPRINT("Netdev ISR handler outside the IRQ context"); + //DPRINT("Netdev ISR handler outside the IRQ context"); netdev->driver->isr(netdev); } @@ -284,7 +284,7 @@ static void _event_cb(netdev_t *dev, netdev_event_t event) } break; case NETDEV_EVENT_TX_REFILL_NEEDED: - DPRINT("New data needed to transmit without discontinuity"); + //DPRINT("New data needed to transmit without discontinuity"); if (tx_refill_callback) { uint8_t thr; diff --git a/stack/framework/hal/chips/netdev_driver/sx127x.c b/stack/framework/hal/chips/netdev_driver/sx127x.c index 601e75300..f4489f8a9 100644 --- a/stack/framework/hal/chips/netdev_driver/sx127x.c +++ b/stack/framework/hal/chips/netdev_driver/sx127x.c @@ -198,6 +198,7 @@ void sx127x_init_radio_settings(sx127x_t *dev) sx127x_set_symbol_timeout(dev, LORA_SYMBOL_TIMEOUT_DEFAULT); sx127x_set_rx_single(dev, SX127X_RX_SINGLE); sx127x_set_tx_timeout(dev, SX127X_TX_TIMEOUT_DEFAULT); + break; default: assert(false);//not implemented break; @@ -325,10 +326,12 @@ static void _init_timers(sx127x_t *dev) { dev->_internal.tx_timeout_timer.f = _on_tx_timeout; dev->_internal.tx_timeout_timer.priority = MAX_PRIORITY; + dev->_internal.tx_timeout_timer.arg = dev; timer_init_event(&dev->_internal.tx_timeout_timer, &_on_tx_timeout); dev->_internal.rx_timeout_timer.f = _on_rx_timeout; dev->_internal.rx_timeout_timer.priority = MAX_PRIORITY; + dev->_internal.rx_timeout_timer.arg = dev; timer_init_event(&dev->_internal.rx_timeout_timer, &_on_rx_timeout); } diff --git a/stack/framework/hal/chips/netdev_driver/sx127x_getset.c b/stack/framework/hal/chips/netdev_driver/sx127x_getset.c index 824ab086f..78cea453a 100644 --- a/stack/framework/hal/chips/netdev_driver/sx127x_getset.c +++ b/stack/framework/hal/chips/netdev_driver/sx127x_getset.c @@ -58,7 +58,6 @@ uint8_t sx127x_get_state(const sx127x_t *dev) void sx127x_set_state(sx127x_t *dev, uint8_t state) { -#if ENABLE_DEBUG switch (state) { case SX127X_RF_IDLE: DEBUG("[sx127x] Change state: IDLE\n"); @@ -73,7 +72,6 @@ void sx127x_set_state(sx127x_t *dev, uint8_t state) DEBUG("[sx127x] Change state: UNKNOWN\n"); break; } -#endif dev->settings.state = state; } @@ -321,7 +319,7 @@ void sx127x_set_standby(sx127x_t *dev) timer_cancel_event(&dev->_internal.tx_timeout_timer); timer_cancel_event(&dev->_internal.rx_timeout_timer); - dev->options = 0; // clear the options + //Do not clear the options here /* Disable the interrupts */ hw_gpio_disable_interrupt(dev->params.dio0_pin); hw_gpio_disable_interrupt(dev->params.dio1_pin); @@ -629,7 +627,6 @@ uint8_t sx127x_get_op_mode(const sx127x_t *dev) void sx127x_set_op_mode(const sx127x_t *dev, uint8_t op_mode) { -#if ENABLE_DEBUG switch(op_mode) { case SX127X_RF_OPMODE_SLEEP: DEBUG("[sx127x] Set op mode: SLEEP\n"); @@ -650,16 +647,13 @@ void sx127x_set_op_mode(const sx127x_t *dev, uint8_t op_mode) DEBUG("[sx127x] Set op mode: UNKNOWN (%d)\n", op_mode); break; } -#endif #if defined(PLATFORM_SX127X_USE_MANUAL_RXTXSW_PIN) || defined(PLATFORM_USE_ABZ) set_antenna_switch(dev, op_mode); #endif /* Replace previous mode value and setup new mode value */ - sx127x_reg_write(dev, SX127X_REG_OPMODE, - (sx127x_reg_read(dev, SX127X_REG_OPMODE) & - SX127X_RF_OPMODE_MASK) | op_mode); + sx127x_reg_write(dev, SX127X_REG_OPMODE, op_mode); } uint32_t computeRxBw( uint8_t mantisse, uint8_t exponent ) @@ -1051,7 +1045,7 @@ static inline uint8_t sx127x_get_pa_select(const sx127x_t *dev) return SX127X_RF_PACONFIG_PASELECT_RFO; } -uint8_t sx127x_get_tx_power(const sx127x_t *dev) +int8_t sx127x_get_tx_power(const sx127x_t *dev) { switch (dev->settings.modem) { case SX127X_MODEM_FSK: diff --git a/stack/framework/hal/chips/netdev_driver/sx127x_netdev.c b/stack/framework/hal/chips/netdev_driver/sx127x_netdev.c index 00f6ee6d0..91b5a4b37 100644 --- a/stack/framework/hal/chips/netdev_driver/sx127x_netdev.c +++ b/stack/framework/hal/chips/netdev_driver/sx127x_netdev.c @@ -36,14 +36,14 @@ #include "hwsystem.h" #include "debug.h" -#if defined(FRAMEWORK_LOG_ENABLED) && defined(HAL_RADIO_LOG_ENABLED) +//#if defined(FRAMEWORK_LOG_ENABLED) && defined(HAL_RADIO_LOG_ENABLED) #include "log.h" #define DEBUG(...) log_print_string(__VA_ARGS__) #define DEBUG_DATA(...) log_print_data(__VA_ARGS__) -#else +/*#else #define DEBUG(...) #define DEBUG_DATA(...) -#endif +#endif*/ /* Internal helper functions */ static int _set_state(sx127x_t *dev, netopt_state_t state); @@ -119,6 +119,7 @@ static int _send(netdev_t *netdev, const iolist_t *iolist) } } + /* FIFO operations can not take place in Sleep mode * So wake up the chip */ if (sx127x_get_op_mode(dev) == SX127X_RF_OPMODE_SLEEP) { @@ -153,8 +154,18 @@ static int _send(netdev_t *netdev, const iolist_t *iolist) dev->packet.pos = size; if (dev->options & SX127X_OPT_TELL_TX_REFILL) // we expect to refill the FIFO with subsequent data { - sx127x_reg_write(dev, SX127X_REG_FIFOTHRESH, 0x81); // FIFO level interrupt if under 2 bytes - dev->packet.fifothresh = 2; + // Setting the fifo threshold to half the packet length + if ((dev->packet.length % 2) == 1) + { + dev->packet.fifothresh = ((dev->packet.length+1)/2); + sx127x_reg_write(dev, SX127X_REG_FIFOTHRESH, (0x80 | (dev->packet.fifothresh-1))); + } + else + { + dev->packet.fifothresh = ((dev->packet.length/2)+1); + sx127x_reg_write(dev, SX127X_REG_FIFOTHRESH, (0x80 | (dev->packet.fifothresh-1))); + } + sx127x_write_fifo(dev, iolist->iol_base, size); hw_gpio_set_edge_interrupt(dev->params.dio1_pin, GPIO_FALLING_EDGE); hw_gpio_enable_interrupt(dev->params.dio1_pin); @@ -220,9 +231,16 @@ static int _send(netdev_t *netdev, const iolist_t *iolist) timer_add_event(&dev->_internal.tx_timeout_timer); } - /* Put chip into transfer mode */ - sx127x_set_state(dev, SX127X_RF_TX_RUNNING); - sx127x_set_op_mode(dev, SX127X_RF_OPMODE_TRANSMITTER); + if (sx127x_get_state(dev) & SX127X_RF_TX_RUNNING) {} + else { + /* Put chip into Standby mode */ + sx127x_set_state(dev, SX127X_RF_IDLE); + sx127x_set_op_mode(dev, SX127X_RF_OPMODE_STANDBY); + + /* Put chip into transfer mode */ + sx127x_set_state(dev, SX127X_RF_TX_RUNNING); + sx127x_set_op_mode(dev, SX127X_RF_OPMODE_TRANSMITTER); + } } return 0; @@ -352,6 +370,7 @@ static int _init(netdev_t *netdev) sx127x->irq = 0; sx127x_radio_settings_t settings; + memset((uint8_t*)&settings, 0, sizeof(sx127x_radio_settings_t)); settings.channel = SX127X_CHANNEL_DEFAULT; settings.modem = SX127X_MODEM_DEFAULT; settings.state = SX127X_RF_IDLE; @@ -370,6 +389,9 @@ static int _init(netdev_t *netdev) /* Put chip into sleep */ sx127x_set_sleep(sx127x); + /* Put chip into standby mode*/ + sx127x_set_standby(sx127x); + DEBUG("[sx127x] init_radio: sx127x initialization done\n"); init_done = true; @@ -474,8 +496,8 @@ static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len) return sizeof(netopt_enable_t); case NETOPT_TX_POWER: - assert(max_len >= sizeof(int16_t)); - *((int16_t*) val) = (int16_t)sx127x_get_tx_power(dev); + assert(max_len >= sizeof(int8_t)); + *((int8_t*) val) = sx127x_get_tx_power(dev); return sizeof(int16_t); case NETOPT_IQ_INVERT: @@ -670,8 +692,8 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len) res = -EINVAL; break; } - sx127x_set_tx_power(dev, (int8_t)power); - return sizeof(int16_t); + sx127x_set_tx_power(dev, power); + return sizeof(int8_t); case NETOPT_FIXED_HEADER: assert(len <= sizeof(netopt_enable_t)); @@ -956,6 +978,27 @@ void _on_dio1_irq(void *arg) hw_gpio_disable_interrupt(dev->params.dio1_pin); timer_cancel_event(&dev->_internal.rx_timeout_timer); + uint8_t byte = 0; +/* if (!(dev->options & SX127X_OPT_TELL_RX_END)) + { + while(!sx127x_is_fifo_empty(dev)) + { + byte = sx127x_reg_read(dev, SX127X_REG_FIFO); + //log_print_data(&byte, 1); + //DEBUG("%02X", byte); + printf("%02X\r\n", byte); + } + + //sx127x_read_fifo(dev, &dev->packet.buf[dev->packet.pos], dev->packet.fifothresh); + //DEBUG_DATA(dev->packet.buf, dev->packet.fifothresh); + + sx127x_reg_write(dev, SX127X_REG_FIFOTHRESH, 0x80 | (60 - 1)); + dev->packet.fifothresh = 60; + hw_gpio_set_edge_interrupt(dev->params.dio1_pin, GPIO_RISING_EDGE); + hw_gpio_enable_interrupt(dev->params.dio1_pin); + return; + }*/ + if (dev->packet.length == 0 && dev->packet.pos == 0) { // For RX, the threshold is set to 4, so if the DIO1 interrupt occurs, it means that can read at least 4 bytes diff --git a/stack/framework/hal/platforms/cortus_fpga/CMakeLists.txt b/stack/framework/hal/platforms/cortus_fpga/CMakeLists.txt index 6f2b1b2c8..ee7332feb 100644 --- a/stack/framework/hal/platforms/cortus_fpga/CMakeLists.txt +++ b/stack/framework/hal/platforms/cortus_fpga/CMakeLists.txt @@ -57,12 +57,13 @@ EXPORT_GLOBAL_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) #Set platform specific compile options #INSERT_C_FLAGS(AFTER "-c -Os -Wall -Wcast-align -g3 -MMD -MP -fmessage-length=0") -INSERT_C_FLAGS(AFTER "-Os -Wall -Wcast-align -g3 -MMD -MP -fmessage-length=0") +INSERT_C_FLAGS(AFTER "-v -Os -Wall -Wcast-align -g3 -MMD -MP -fmessage-length=0") #Add platform specific linker flags INSERT_LINKER_FLAGS(BEFORE OBJECTS INSERT "") -#INSERT_LINKER_FLAGS(BEFORE LINK_LIBRARIES INSERT "-nostartfiles") -INSERT_LINKER_FLAGS(AFTER LINK_LIBRARIES INSERT "-fno-lto -Os -g3 -Wl,-q -Wl,--noinhibit-exec -Wl,-Map,cortus.map -fno-exceptions") +INSERT_LINKER_FLAGS(BEFORE LINK_LIBRARIES INSERT "-nostartfiles") +#INSERT_LINKER_FLAGS(AFTER LINK_LIBRARIES INSERT "-fuse-clib=newlib") +INSERT_LINKER_FLAGS(AFTER LINK_LIBRARIES INSERT "-fno-lto -Os -g3 -Wl,-q -Wl,--noinhibit-exec -Wl,-Map,cortus.map -nostartfiles -fno-exceptions") #INSERT_LINKER_FLAGS(AFTER LINK_LIBRARIES INSERT "-lc -L. -fno-lto -Os -g3 -Wl,-q -Wl,--noinhibit-exec -Wl,-Map,cortus.map -fno-exceptions") #MESSAGE(STATUS "CMAKE_C_COMPILER ${CMAKE_C_COMPILER}") @@ -74,6 +75,7 @@ ADD_LIBRARY(PLATFORM OBJECT cortus_leds.c cortus_userbutton.c libc_overrides.c + crt0.c inc/button.h ) diff --git a/stack/framework/hal/platforms/cortus_fpga/crt0.c b/stack/framework/hal/platforms/cortus_fpga/crt0.c new file mode 100644 index 000000000..51b2b4e49 --- /dev/null +++ b/stack/framework/hal/platforms/cortus_fpga/crt0.c @@ -0,0 +1,1085 @@ +/********************************************************************************* + * This confidential and proprietary software may be used only as authorized + * by a licensing agreement from + * Cortus S.A.S + * + * (C) Copyright 2006-2017 Cortus S.A.S + * ALL RIGHTS RESERVED + * + * The entire notice above must be reproduced on all authorized copies + * and any such reproduction must be pursuant to a licensing agreement + * from Cortus S.A.S (http://www.cortus.com) + * + * $CortusRelease$ + * $FileName$ + * + * + *********************************************************************************/ +#pragma GCC optimize ("Os") + +#include +#include +#include +#ifdef __APS__ +#include +#else +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#ifdef __riscv +#define CSR_MTVEC 0x305 +#define CSR_MSCRATCH 0x340 +#define CSR_MEPC 0x341 +#define CSR_MCAUSE 0x342 +#define CSR_DCSR 0x7b0 +#endif + +/* Debugger printf buffer size. + Define this to be bigger than 3 in order to enable it in place of uart output + for stdio - should not be bigger than 255 */ +#define DBG_PRINTF_BUF_SIZE 0 + +/* Clock frequency in KHZ + Nominal clock frequency for a 90nm implementation is 400,000 KHZ - i.e. 400 MHZ. + This is global so that it can be set/read by user code. Note that for + profiling, it has to be set before profiling is started. */ +unsigned _cpu_clock_frequency_khz __attribute__((weak)) = 400000; + +/* This is used by at_exit */ +void* __dso_handle __attribute__((weak)); + +/******************************************************************************** + * Trap vector table + ********************************************************************************/ + +/* Prototypes for trap handlers. + * By defining these as weak, we allow the user to override these in his code */ +#ifdef __riscv +void start(void) __attribute__((section (".init"), used)); +void interrupt0_handler (void) __attribute__((weak)); +void interrupt1_handler (void) __attribute__((weak)); +void interrupt2_handler (void) __attribute__((weak)); +void interrupt3_handler (void) __attribute__((weak)); +void interrupt4_handler (void) __attribute__((weak)); +#else +void start(void) __attribute__((section (".init"), used, noreturn, naked)); +void critical_error_handler (void) __attribute__((weak)); +void illegal_instruction_handler (void) __attribute__((weak)); +void debugger_breakpoint_handler (void); +#endif +void debugger_stop_handler (void); +#ifdef PROFILING +void profile_handler (void); +#endif +void interrupt5_handler (void) __attribute__((weak)); +void interrupt6_handler (void) __attribute__((weak)); +void interrupt7_handler (void) __attribute__((weak)); +void interrupt8_handler (void) __attribute__((weak)); +void interrupt9_handler (void) __attribute__((weak)); +void interrupt10_handler (void) __attribute__((weak)); +void interrupt11_handler (void) __attribute__((weak)); +void interrupt12_handler (void) __attribute__((weak)); +void interrupt13_handler (void) __attribute__((weak)); +void interrupt14_handler (void) __attribute__((weak)); +void interrupt15_handler (void) __attribute__((weak)); +void interrupt16_handler (void) __attribute__((weak)); +void interrupt17_handler (void) __attribute__((weak)); +void interrupt18_handler (void) __attribute__((weak)); +void interrupt19_handler (void) __attribute__((weak)); +void interrupt20_handler (void) __attribute__((weak)); +void interrupt21_handler (void) __attribute__((weak)); +void interrupt22_handler (void) __attribute__((weak)); +void interrupt23_handler (void) __attribute__((weak)); +void interrupt24_handler (void) __attribute__((weak)); +void interrupt25_handler (void) __attribute__((weak)); +void interrupt26_handler (void) __attribute__((weak)); +void interrupt27_handler (void) __attribute__((weak)); +void interrupt28_handler (void) __attribute__((weak)); +void interrupt29_handler (void) __attribute__((weak)); +void interrupt30_handler (void) __attribute__((weak)); +void interrupt31_handler (void) __attribute__((weak)); +void interrupt32_handler (void) __attribute__((weak)); +void interrupt33_handler (void) __attribute__((weak)); +void interrupt34_handler (void) __attribute__((weak)); +void interrupt35_handler (void) __attribute__((weak)); +void interrupt36_handler (void) __attribute__((weak)); +void interrupt37_handler (void) __attribute__((weak)); +void interrupt38_handler (void) __attribute__((weak)); +void interrupt39_handler (void) __attribute__((weak)); +void interrupt40_handler (void) __attribute__((weak)); +void interrupt41_handler (void) __attribute__((weak)); +void interrupt42_handler (void) __attribute__((weak)); +void interrupt43_handler (void) __attribute__((weak)); +void interrupt44_handler (void) __attribute__((weak)); +void interrupt45_handler (void) __attribute__((weak)); +void interrupt46_handler (void) __attribute__((weak)); +void interrupt47_handler (void) __attribute__((weak)); +void interrupt48_handler (void) __attribute__((weak)); +void interrupt49_handler (void) __attribute__((weak)); +void interrupt50_handler (void) __attribute__((weak)); +void interrupt51_handler (void) __attribute__((weak)); +void interrupt52_handler (void) __attribute__((weak)); +void interrupt53_handler (void) __attribute__((weak)); +void interrupt54_handler (void) __attribute__((weak)); +void interrupt55_handler (void) __attribute__((weak)); +void interrupt56_handler (void) __attribute__((weak)); +void interrupt57_handler (void) __attribute__((weak)); +void interrupt58_handler (void) __attribute__((weak)); +void interrupt59_handler (void) __attribute__((weak)); +void interrupt60_handler (void) __attribute__((weak)); +void interrupt61_handler (void) __attribute__((weak)); +void interrupt62_handler (void) __attribute__((weak)); +void interrupt63_handler (void) __attribute__((weak)); + +#ifdef __riscv +void timer_interrupt_handler (void) __attribute__((weak)); +void software_interrupt_handler (void) __attribute__((weak)); +void ecall_handler (void) __attribute__((weak)); +#endif + +#ifdef __riscv +volatile trap_handler_fp trap_vectors[32] + __attribute__((used)) = +#else +volatile trap_handler_fp trap_vectors[64] + __attribute ((section (".vectors"), used)) = +#endif +{ +#ifdef __riscv + [0] = interrupt0_handler, + [1] = interrupt1_handler, + [2] = interrupt2_handler, + [3] = interrupt3_handler, +#else + [0] = start, + [1] = critical_error_handler, + [2] = illegal_instruction_handler, + [3] = debugger_breakpoint_handler, +#endif + [4] = debugger_stop_handler, + [5] = interrupt5_handler, + [6] = interrupt6_handler, +#ifdef PROFILING + [7] = profile_handler, +#else + [7] = interrupt7_handler, +#endif + [8] = interrupt8_handler, + [9] = interrupt9_handler, + [10] = interrupt10_handler, + [11] = interrupt11_handler, + [12] = interrupt12_handler, + [13] = interrupt13_handler, + [14] = interrupt14_handler, + [15] = interrupt15_handler, + [16] = interrupt16_handler, + [17] = interrupt17_handler, + [18] = interrupt18_handler, + [19] = interrupt19_handler, + [20] = interrupt20_handler, + [21] = interrupt21_handler, + [22] = interrupt22_handler, + [23] = interrupt23_handler, + [24] = interrupt24_handler, + [25] = interrupt25_handler, + [26] = interrupt26_handler, + [27] = interrupt27_handler, + [28] = interrupt28_handler, + [29] = interrupt29_handler, + [30] = interrupt30_handler, + [31] = interrupt31_handler, + [32] = interrupt32_handler, + [33] = interrupt33_handler, + [34] = interrupt34_handler, + [35] = interrupt35_handler, + [36] = interrupt36_handler, + [37] = interrupt37_handler, + [38] = interrupt38_handler, + [39] = interrupt39_handler, + [40] = interrupt40_handler, + [41] = interrupt41_handler, + [42] = interrupt42_handler, + [43] = interrupt43_handler, + [44] = interrupt44_handler, + [45] = interrupt45_handler, + [46] = interrupt46_handler, + [47] = interrupt47_handler, + [48] = interrupt48_handler, + [49] = interrupt49_handler, + [50] = interrupt50_handler, + [51] = interrupt51_handler, + [52] = interrupt52_handler, + [53] = interrupt53_handler, + [54] = interrupt54_handler, + [55] = interrupt55_handler, + [56] = interrupt56_handler, + [57] = interrupt57_handler, + [58] = interrupt58_handler, + [59] = interrupt59_handler, + [60] = interrupt60_handler, + [61] = interrupt61_handler, + [62] = interrupt62_handler, + [63] = interrupt63_handler, +}; + +/******************************************************************************** + * stdio + * + * This is where all the libgloss IO functions end up. + * These can be overriden in user supplied code to do something more interesting + * and maybe even look at the FILE* parameter. + * + ********************************************************************************/ + +/* For debugger stub, restore previous cache status */ +int p_cache_en = 0; +int pending = 0; + +/* Register save area and status info for debugger */ +typedef struct dbg_info_t { + unsigned char status0, status1, status2, status3; +#ifdef __riscv + + unsigned regs[31]; + unsigned mepc, mstatus; +#else + unsigned r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11; + unsigned r12, r13, r14, r15, rtt, psr; +#ifdef __HAVE_MAC__ + unsigned accl, acch; +#endif +#endif +#if DBG_PRINTF_BUF_SIZE > 1 + unsigned char size; + unsigned char wrp; + volatile unsigned char rdp; + unsigned char buf[DBG_PRINTF_BUF_SIZE]; +#endif +} dbg_info_t; +dbg_info_t _dbg_info __attribute__((section(".sbss.debugger_register_save_area"))); + +void uart1_outch_raw (int c) __attribute__((weak)); + +#if DBG_PRINTF_BUF_SIZE > 1 +/* Output via debugger instead of uart */ +void uart1_outch_raw (int c) +{ + /* Flush, wait for pending done, disable cache */ + p_cache_en = *(unsigned*)(0x4000a024); + + *(unsigned*)(0x4000a000) = 0x1; + do { + pending = *(unsigned*)(0x4000a028); + } while (pending); + + *(unsigned*)(0x4000a024) = 0; + + /* Next location to write to */ + unsigned nwrp = _dbg_info.wrp + 1; + + /* Wrap around */ + if (nwrp == DBG_PRINTF_BUF_SIZE) nwrp = 0; + + /* Wait if buffer is full (always one slot empty to detect difference + between full and empty) */ + while (nwrp == _dbg_info.rdp - 1 || nwrp == _dbg_info.rdp + DBG_PRINTF_BUF_SIZE - 1); + + /* Put data in buffer */ + _dbg_info.buf[_dbg_info.wrp] = c; + + /* Update write pointer */ + _dbg_info.wrp = nwrp; + + /* Provide buffer size */ + _dbg_info.size = DBG_PRINTF_BUF_SIZE; + + /* Tell debugger to take a look */ + _dbg_info.status1 = 1; + *(unsigned*)(0x50000000) = 0x10000; + + /* Enable cache if previously enabled */ + *(unsigned*)(0x4000a024) = p_cache_en; + +} +#else +void uart1_outch_raw (int c) +{ + while (! (uart1->tx_status & 1)) ; + uart1->tx_data = c; +} +#endif + +void uart1_outch (void* f, int c) __attribute__((weak)); +void uart1_outch (void* f, int c) +{ + if (c == '\n') + uart1_outch_raw ('\r'); + uart1_outch_raw (c); +} + +int uart1_inch (void* f) __attribute__((weak)); +int uart1_inch (void* f) +{ + int c; + while (! (uart1->rx_status & 1)) ; + c = uart1->rx_data; + return c; +} + +/******************************************************************************** + * Stack and Heap are defined by the default linker script in .bss and will be + * initialized by the startup code below. + * + * The sizes can be overriden by defining the symbols _STACK_SIZE and _HEAP_SIZE. + * This can be done by using the macros in sys/memsize.h or by defining them + * on the linker command line with --defsym. + * + * Also the maximum size of memory can be defined. + * + * e.g. + * HEAP_SIZE (16*1024); + * STACK_SIZE (4*1024); + * DATA_MEMORY_SIZE (64*1024); + * PROGRAM_MEMORY_SIZE (128*1024); +*/ + +/* + * If stack overflow checking is enabled, set a break point on __stack_overflowed + * in the debugger. At this stage a stack trace can be done. After that the + * stack is reset, and the function __stack_overflow is called. The default version + * of this functions just does exit(3). + */ + +/******************************************************************************** + * HW Initialization + * e.g. set up uart baud rate + ********************************************************************************/ + +/* All the peripherals etc should be fully initialised here in order to ensure a + successful reboot in the event of an abort () call or watch dog timeout. */ +void initialise_hw (void) __attribute__((weak)); +void initialise_hw (void) +{ +#if DBG_PRINTF_BUF_SIZE > 1 + /* Intialise pointers */ + _dbg_info.wrp = 0; + _dbg_info.rdp = 0; + _dbg_info.size = DBG_PRINTF_BUF_SIZE; +#endif + /* Enable the data cache (if present) */ +#if DATA_CACHE_PRESENT + dcache->enable = 1; +#endif + + // Initialize the UART to reasonable values + uart1->config = 0; + uart1->selclk = 0; + // Uart speed is 115200 bauds + uart1->divider = 8*(32000000/115200); /* CPU frequency is 32MHz */ + uart1->enable = 1; +} + +/******************************************************************************** + * Execution starts here (linker entry point) + ********************************************************************************/ + +/* Type definition for a C++ static constructor function */ +typedef void (*constructor_t)(void); + +/* Static constructor array */ +extern const constructor_t __CTOR_LIST__[], __CTOR_END__[]; + +/* Location of data for initialization of .sdata and .data sections */ +extern const unsigned _data_image[]; + +/* Start of ram, Start/end of .sbss, .sdata/.data, .bss */ +extern unsigned _sram[], _sbss[], _esbss[], _sdata[], _edata[], _bss[], _ebss[]; + +int main (void); +void init_profile (void); +void start_profile (void); +void stop_profile (void); + +/* This function must be compiled with optimization enabled so that is does not + place anything on the stack. The initialization of the .bss section will + clear the stack resetting the variables used! */ +void start(void) +{ +#ifdef __riscv + /* Intialize stack pointer and exception register */ + extern void exception_handler(void); + asm volatile ("la sp, __stack_top"); + asm volatile ("csrw %0,%1": : "i"(CSR_MTVEC), "r"(exception_handler)); + /* Enable ebreak machine mode to enter debug mode */ + asm volatile ("li t6, 0x8000"); + asm volatile ("csrw %0,t6": : "i"(CSR_DCSR)); +#else + /* Initialize stack pointer */ + asm (" movhi r1, #high(__stack_top)\n" + " add r1, #low(__stack_top)\n"); + + /* Initialize pointer to rodata */ + asm (" movhi r8, #high(_rodata)\n" + " add r8, #low(_rodata)\n"); +#endif + + /* Initialize HW and memory etc and call main */ + while (1) { + + const constructor_t* ctor; + const unsigned *src; + unsigned *dst; + int status; + + icache_flush (); + initialise_hw (); + +#ifdef __riscv + /* Enable jtag interrupt from debugger. + This is what happens when you hit the stop button in the + debugger GUI */ + irq[IRQ_DEBUGGER_STOP].ipl = 0; + + /* Enable interrupts */ + plic->ien[0] = 1 << IRQ_DEBUGGER_STOP; +#else + /* Enable jtag interrupt from debugger. + This is what happens when you hit the stop button in the + debugger GUI */ + irq[IRQ_DEBUGGER_STOP].ien = 1; + + /* Enable all interrupts */ + ic->ien = 1; +#endif + cpu_int_enable(); + + /* Initialize the area at address 0 up to the register save area to + something recognisable in the debugger to help track down NULL + pointer deferencing. Depending on the linker script, this is usually + 32 bytes of memory */ + for (dst = _sram; dst < (unsigned*) &_dbg_info; dst++) + *dst = 0xa5a5a5a5; + + /* Initialize .sbss section */ + for (dst = _sbss; dst < _esbss; dst++) + *dst = 0; + + /* Initialize .sdata and .data sections */ + for (src = _data_image, dst = _sdata; dst < _edata;) + *dst++ = *src++; + + /* Initialize .bss section (including stack - make sure that + 'dst' is not on the stack! */ + for (dst = _bss; dst < _ebss; dst++) + *dst = 0; + /* Call static constructors */ + for (ctor = __CTOR_LIST__; ctor < __CTOR_END__; ctor++) + (**ctor)(); + + /* Start profiling */ +#ifdef PROFILING + init_profile(); + + /* The start can be anywhere convenient */ + start_profile(); +#endif + /* Call main */ + status = main (); + + /* Exit should call destructors if desired */ + exit (status); + } +} + +#ifdef __APS__ +/******************************************************************************** + * Monitor stub for debugger + ********************************************************************************/ +asm (".section .text\n" + "illegal_instruction_handler:\n" + " st r2, [r0]+short(_dbg_info+2*4)\n" + " mov r2, #2\n" + " bra monitor\n" + "debugger_breakpoint_handler:\n" + " st r2, [r0]+short(_dbg_info+2*4)\n" + " mov r2, #3\n" + " bra monitor\n" + "debugger_stop_handler:\n" + " st r2, [r0]+short(_dbg_info+2*4)\n" + " mov r2, #4\n" + " bra monitor\n" + "critical_error_handler:\n" + "interrupt5_handler:\n" + "interrupt6_handler:\n" + "interrupt7_handler:\n" + "interrupt8_handler:\n" + "interrupt9_handler:\n" + "interrupt10_handler:\n" + "interrupt11_handler:\n" + "interrupt12_handler:\n" + "interrupt13_handler:\n" + "interrupt14_handler:\n" + "interrupt15_handler:\n" + "uninitialized_trap_handler:\n" + " st r2, [r0]+short(_dbg_info+2*4)\n" + " mov r2, #1\n" + " bra monitor\n" + "\n" + "; Monitor entry and exit - save and restore registers around call to monitor proper\n" + "; save all registers\n" + ".section .text\n" + "monitor:\n" + " st r1, [r0]+short(_dbg_info+1*4)\n" + " st r3, [r0]+short(_dbg_info+3*4)\n" + " movhi r3, #high(0x50000000)\n" + "; stop trace\n" + " st r0, [r3]+0x1000\n" + " stq r4, [r0]+short(_dbg_info+4*4)\n" + " stq r8, [r0]+short(_dbg_info+8*4)\n" + " stq r12,[r0]+short(_dbg_info+12*4)\n" + " mov r4, rtt\n" + " mov r5, psr\n" +#ifdef __HAVE_MAC__ + " mov r6, accl\n" + " mov r7, acch\n" + " stq r4, [r0]+short(_dbg_info+16*4)\n" +#else + " std r4, [r0]+short(_dbg_info+16*4)\n" +#endif + "\n" + "; Save interrupt source information\n" + " stb r2, [r0]+short(_dbg_info+0*4)\n" + "; Flush and disable data cache so debugger can see/manipulate data memory\n" + " movhi r6, #high(0x4000a000)\n" + " add r6, #low(0x4000a000)\n" + "; Read cache en bit\n" + " ld r5, [r6]+0x24\n" + "; Store to p_cache_en\n" + " movhi r7, #high(p_cache_en)\n" + " add r7, #low(p_cache_en)\n" + " st r5, [r7]\n" + "; Flush the cache\n" + " mov r5, #0x1\n" + " st r5, [r6]\n" + "; Check pending status\n" + "wait_pend: \n" + " ld.cc r5, [r6]+0x28\n" + " bne wait_pend\n" + "; Disable the cache\n" + " st r0, [r6]+0x24\n" + "; Tell debugger to look at us\n" + " movhi r2, #0x1\n" + " st r2, [r3]\n" + "; Wait for debugger to tell us to go\n" + "wait: \n" + " ldub.cc r4, [r0]+short(_dbg_info)\n" + " bne wait\n" + "; Lets go!\n" + "\n" + "; Reload all registers and return\n" + "go:\n" + "; Renable data cache if previously enabled\n" + " ld r5, [r7]\n" + " st r5, [r6]+0x24\n" + " icache_flush\n" + "; renable trace - this could come later but it is useful to\n" + "; see all the values of all the registers getting reloaded\n" + " mov r2, #3\n" + " st r2, [r3]+0x1000\n" + " bra go1 ; so trace buffer decode resyncs\n" + "go1:\n" +#ifdef __HAVE_MAC__ + " ldq r4, [r0]+short(_dbg_info+16*4)\n" + " mov acch, r7\n" + " mov accl, r6\n" +#else + " ldd r4, [r0]+short(_dbg_info+16*4)\n" +#endif + " mov psr, r5\n" + " mov rtt, r4\n" + " ldq r12,[r0]+short(_dbg_info+12*4)\n" + " ldq r8, [r0]+short(_dbg_info+8*4)\n" + " ldq r4, [r0]+short(_dbg_info+4*4)\n" + " ldd r2, [r0]+short(_dbg_info+2*4)\n" + " ld r1, [r0]+short(_dbg_info+1*4)\n" + " rti\n"); +#endif + +void __attribute__((noinline)) exit (int status) +{ + while (1) { + /* Reboot */ +#ifdef __riscv + asm ("j start"); +#else + asm ("trap #0"); +#endif + } +} + +/* _exit and _Exit have exactly the same function as exit */ +asm (".global _exit\n" + ".global _Exit\n" + ".equiv _exit, exit\n" + ".equiv _Exit, exit"); + +/* Ensure that a reference to the function __errno is generated here so that + the symbol gets picked up from libc. Otherwise if the first reference + to __errno could come from libgloss - in which case end up with link errors */ +asm (".equiv xerrno, __errno"); + +#ifdef __riscv +/******************************************************************************** + * Exception Handler + ********************************************************************************/ +asm (".section .text\n" + ".option nopic\n" + ".equ plic, 0x40000000\n" + ".equ ocds, 0x50000000\n" + ".equ tracebuf, 0x50001000\n" + ".balign 4\n" + ".globl exception_handler\n" + ".type exception_handler, @function\n" + "exception_handler:\n" + "# Store non caller save registers to stack\n" + " addi sp, sp, -(16*4)\n" + " sw ra, (0*4)(sp)\n" + " sw t0, (1*4)(sp)\n" + " sw t1, (2*4)(sp)\n" + " sw t2, (3*4)(sp)\n" + " sw a0, (4*4)(sp)\n" + " sw a1, (5*4)(sp)\n" + " sw a2, (6*4)(sp)\n" + " sw a3, (7*4)(sp)\n" + " sw a4, (8*4)(sp)\n" + " sw a5, (9*4)(sp)\n" + " sw a6, (10*4)(sp)\n" + " sw a7, (11*4)(sp)\n" + " sw t3, (12*4)(sp)\n" + " sw t4, (13*4)(sp)\n" + " sw t5, (14*4)(sp)\n" + " sw t6, (15*4)(sp)\n" + " csrr t0, mcause\n" + " li t1, 0x8000000b\n" + " sub t2, t0, t1\n" + " bnez t2, not_external_interrupt\n" + + "# Get address of interrupt handler into t2\n" + " li t2, plic\n" + " lw t2, 4(t2) # t2 <- plic->claim\n" + " addi t1, t2, -4\n" + " beqz t1, debugger_stop_handler\n" + " slli t1, t2, 2\n" + " la t6, trap_vectors\n" + " add t1, t1, t6\n" + " lw t1, 0(t1) # t1 <- trap_vectors[plic->claim]\n" + " jalr t1\n" + + "# Restore caller save registers\n" + ".globl interrupt_return\n" + ".type interrupt_return, @function\n" + "interrupt_return:\n" + " lw ra, (0*4)(sp)\n" + " lw t0, (1*4)(sp)\n" + " lw t1, (2*4)(sp)\n" + " lw t2, (3*4)(sp)\n" + " lw a0, (4*4)(sp)\n" + " lw a1, (5*4)(sp)\n" + " lw a2, (6*4)(sp)\n" + " lw a3, (7*4)(sp)\n" + " lw a4, (8*4)(sp)\n" + " lw a5, (9*4)(sp)\n" + " lw a6, (10*4)(sp)\n" + " lw a7, (11*4)(sp)\n" + " lw t3, (12*4)(sp)\n" + " lw t4, (13*4)(sp)\n" + " lw t5, (14*4)(sp)\n" + " lw t6, (15*4)(sp)\n" + " addi sp, sp, (16*4)\n" + " mret\n" + "\n" + + "# Handle internal interrupts\n" + "not_external_interrupt:\n" + " la ra, interrupt_return\n" + " addi t2, t2, 4\n" + " bnez t2, not_timer_interrupt_handler\n" + " j timer_interrupt_handler\n" + "not_timer_interrupt_handler:\n" + " addi t2, t2, 4\n" + " bnez t2, not_software_interrupt_handler\n" + " j software_interrupt_handler\n" + "not_software_interrupt_handler:\n" + " addi t2, t0, -3\n" + " beqz t2, enter_debugger\n" + " addi t2, t0, -11\n" + " bnez t2, not_ecall_handler\n" + " j ecall_handler\n" + "# An exception of some kind which is not breakpoint or ecall\n" + "not_ecall_handler:\n" + " beqz zero, enter_debugger\n" + + "enter_debugger:\n" + "# Stop trace\n" + " li t0, tracebuf\n" + " sw zero, 0(t0)\n" + "# Debugger is responsible for adjusting mepc if necessary\n" + "# Save all registers for debugger a few choice CSRs\n" + " la t0, _dbg_info\n" + " lw t1, (0*4)(sp)# ra/x1\n" + " sw t1, (1*4)(t0)\n" + " addi sp, sp, (16*4)\n" + " sw sp, (2*4)(t0)\n" + " addi sp, sp, -(16*4)\n" + " sw gp, (3*4)(t0)\n" + " sw tp, (4*4)(t0)\n" + " lw t1, (1*4)(sp) # t0/x5\n" + " sw t1, (5*4)(t0)\n" + " lw t1, (2*4)(sp) # t1/x6\n" + " sw t1, (6*4)(t0)\n" + " lw t1, (3*4)(sp) # t2/x7\n" + " sw t1, (7*4)(t0)\n" + " sw s0, (8*4)(t0)\n" + " sw s1, (9*4)(t0)\n" + " sw a0, (10*4)(t0)\n" + " sw a1, (11*4)(t0)\n" + " sw a2, (12*4)(t0)\n" + " sw a3, (13*4)(t0)\n" + " sw a4, (14*4)(t0)\n" + " sw a5, (15*4)(t0)\n" + " sw a6, (16*4)(t0)\n" + " sw a7, (17*4)(t0)\n" + " sw s2, (18*4)(t0)\n" + " sw s3, (19*4)(t0)\n" + " sw s4, (20*4)(t0)\n" + " sw s5, (21*4)(t0)\n" + " sw s6, (22*4)(t0)\n" + " sw s7, (23*4)(t0)\n" + " sw s8, (24*4)(t0)\n" + " sw s9, (25*4)(t0)\n" + " sw s10, (26*4)(t0)\n" + " sw s11, (27*4)(t0)\n" + " sw t3, (28*4)(t0)\n" + " sw t4, (29*4)(t0)\n" + " sw t5, (30*4)(t0)\n" + " lw t1, (15*4)(sp) # t6/x31\n" + " sw t1, (31*4)(t0)\n" + "# Save CSRs\n" + " csrr t1, mepc\n" + " sw t1, (32*4)(t0)\n" + " csrr t1, mstatus\n" + " sw t1, (33*4)(t0)\n" + "# Reason for monitor entry\n" + " csrr t1, mcause\n" + " bgez t1, store_cause\n" + " add t1, t1, 0x14 # stop_cause_value\n" + "store_cause:\n" + " sb t1, (0)(t0) # status 0\n" + "# Tell the debugger to look at us\n" + "wake_debugger:\n" + " li t1, 1\n" + " li t2, ocds # address of ocds register\n" + " sb t1, (2)(t2)\n" + "# Wait for the debugger to tell us to go\n" + "wait:\n" + " lb t1, (0)(t0)\n" + " bnez t1, wait\n" + "# Lets go\n" + "# Restore CSRs which may have been modified by debugger\n" + "go:\n" + " lw t1, (32*4)(t0)\n" + " csrw mepc, t1\n" + " lw t1, (33*4)(t0)\n" + " csrw mstatus, t1\n" + "# Renable trace - this could come later but it is useful to\n" + "# see all the values of all the registers getting reloaded\n" + " li t1, tracebuf\n" + " li t2, 3\n" + " sw t2, 0(t1)\n" + "# Restore all registers\n" + "# place (potentially updated) t0/x5 value into mscratch\n" + " lw ra, (1*4)(t0)\n" + " lw sp, (2*4)(t0)\n" + " lw gp, (3*4)(t0)\n" + " lw tp, (4*4)(t0)\n" + " lw t1, (6*4)(t0)\n" + " lw t2, (7*4)(t0)\n" + " lw s0, (8*4)(t0)\n" + " lw s1, (9*4)(t0)\n" + " lw a0, (10*4)(t0)\n" + " lw a1, (11*4)(t0)\n" + " lw a2, (12*4)(t0)\n" + " lw a3, (13*4)(t0)\n" + " lw a4, (14*4)(t0)\n" + " lw a5, (15*4)(t0)\n" + " lw a6, (16*4)(t0)\n" + " lw a7, (17*4)(t0)\n" + " lw s2, (18*4)(t0)\n" + " lw s3, (19*4)(t0)\n" + " lw s4, (20*4)(t0)\n" + " lw s5, (21*4)(t0)\n" + " lw s6, (22*4)(t0)\n" + " lw s7, (23*4)(t0)\n" + " lw s8, (24*4)(t0)\n" + " lw s9, (25*4)(t0)\n" + " lw s10, (26*4)(t0)\n" + " lw s11, (27*4)(t0)\n" + " lw t3, (28*4)(t0)\n" + " lw t4, (29*4)(t0)\n" + " lw t5, (30*4)(t0)\n" + " lw t6, (31*4)(t0)\n" + " lw t0, (5*4)(t0) # t0/x5\n" + " mret\n" + ); + +asm (".section .text\n" + ".equ plic, 0x40000000\n" + ".equ ocds, 0x50000000\n" + ".globl debugger_stop_handler\n" + ".type debugger_stop_handler, @function\n" + "debugger_stop_handler:\n" + "# Write mcause for debugger\n" + " li t1, 0x14\n" + " csrw mcause, t1\n" + "# Clear stop request in brkpts module\n" + " li t1, ocds # address of ocds register\n" + " sb zero, (1)(t1)\n" + "# Clear pending request in plic\n" + " li t1, plic\n" + " sw t2, 4(t1) #t2 contains claimed vector\n" + "# Go to monitor\n" + " j enter_debugger\n" + + ); + +void timer_interrupt_handler (void) +{ + /* Clear interrupt */ + rvtimer->compare_h = 0xffffffff; + rvtimer->compare_l = 0xffffffff; +} + +void software_interrupt_handler (void) +{ + +} + +void ecall_handler (void) +{ + +} +#endif + +/******************************************************************************** + * Profiling support + ********************************************************************************/ + +#ifdef PROFILING + +/* This is the main structure which will be dumped at the end of execution. + It should be in bss and cleared on startup. + The arrays are allocated dynmically from the heap via sbrk. + It is assumed that the heap is initially reset to 0 via the startup code + above (i.e. it is in .bss) */ +struct gmonparam gmonparam; + +/* Keep one counter for every 4 bytes of code + (power of 2 to avoid divide routine in interupt handler) */ +static const unsigned scale = 4; + +/* Allow for one arc every 32 bytes of code size + (power of 2 to avoid divide routine) */ +static const unsigned arc_density = 32; + +/* We have cpu frequency available in KHZ. We divide it by this number to give + the number of samples per second */ +#define CLOCK_DIVISOR 4 +#define SAMPLES_PER_SECOND (1000/(CLOCK_DIVISOR)) + +void init_profile (void) +{ + extern char _text[], _etext[]; + struct rawarc* arcs; + unsigned short* counts; + unsigned lowpc, highpc, ncounts, maxarcs; + + /* Calculate parameters for data structure */ + lowpc = (unsigned)_text; + highpc = (unsigned)_etext; + ncounts = (highpc - lowpc + scale - 1)/scale; + highpc = lowpc + ncounts * scale; + maxarcs = (highpc - lowpc)/arc_density; + + /* Allocate arrays */ + counts = (unsigned short *) sbrk (ncounts * sizeof(unsigned short)); + arcs = (struct rawarc *) sbrk (maxarcs * sizeof(struct rawarc)); + + if (counts == (void*)-1 || arcs == (void*)-1) + exit(2); + + /* Initialize gmonparam data structure */ + gmonparam = (struct gmonparam) { + .lowpc = lowpc, + .highpc = highpc, + .ncounts = ncounts, + .maxarcs = maxarcs, + .narcs = 0, + .rate = SAMPLES_PER_SECOND, + .counts = counts, + .arcs = arcs, + }; +} + +void start_profile (void) +{ + /* Set up counter to run profile_handler at the rate SAMPLES_PER_SECOND */ + unsigned reload = _cpu_clock_frequency_khz/CLOCK_DIVISOR; + counter1->reload = reload; + counter1->value = reload; +#ifdef __riscv + irq[IRQ_COUNTER1].ipl = 0; + + plic->ien[0] = plic->ien[0] | (1 << IRQ_COUNTER1); +#else + irq[IRQ_COUNTER1].ien = 1; +#endif + counter1->mask = 1; +} + +void stop_profile (void) +{ + counter1->mask = 0; +} + +/* Update the profile counters for the location we are at when the interrupt + occurs */ +#ifdef __APS__ +void profile_handler (void) __attribute__((interrupt)); +#endif +void profile_handler (void) +{ + unsigned pc; +#ifdef __riscv + asm ("csrr %0, mepc" : "=r"(pc) : /*no inputs*/); +#else + asm ("mov %0, rtt" : "=r"(pc) : /*no inputs*/); +#endif + + counter1->expired = 0; + + if (pc < gmonparam.lowpc) return; + unsigned i = (pc - gmonparam.lowpc)/scale; + if (i < gmonparam.ncounts) + gmonparam.counts[i]++; + +#ifdef __riscv + /* Completion message */ + plic->claim = IRQ_COUNTER1; +#endif + +} + +/* Arc counting routine. + The compiler inserts calls to mcount. The assembler mcount routine + saves the r2-r7 before calling this routine */ +void _mcount (unsigned frompc, unsigned selfpc) +{ + struct rawarc *arc = gmonparam.arcs; + unsigned i; + + /* If arc already exists, increment count */ + for (i = 0; i < gmonparam.narcs; i++) { + if (arc[i].frompc == frompc && arc[i].selfpc == selfpc) { + arc[i].count++; + return; + } + } + + /* space for another arc? */ + if (gmonparam.narcs + 1 <= gmonparam.maxarcs) + arc[gmonparam.narcs++] = (struct rawarc) { + .frompc = frompc, + .selfpc = selfpc, + .count = 1 + }; +} + +#ifdef __riscv +/* The compiler inserts calls to this routine when we compile with -pg. + */ +asm(".section .text\n" + ".balign 4\n" + ".global mcount\n" + ".type mcount, @function\n" + "mcount:\n" + " addi sp, sp, -16*4\n" + " sw ra, (0*4)(sp)\n" + " sw t0, (1*4)(sp)\n" + " sw t1, (2*4)(sp)\n" + " sw t2, (3*4)(sp)\n" + " sw a0, (4*4)(sp)\n" + " sw a1, (5*4)(sp)\n" + " sw a2, (6*4)(sp)\n" + " sw a3, (7*4)(sp)\n" + " sw a4, (8*4)(sp)\n" + " sw a5, (9*4)(sp)\n" + " sw a6, (10*4)(sp)\n" + " sw a7, (11*4)(sp)\n" + " sw t3, (12*4)(sp)\n" + " sw t4, (13*4)(sp)\n" + " sw t5, (14*4)(sp)\n" + " sw t6, (15*4)(sp)\n" + " mv a1, ra\n" + " call _mcount\n" + " lw ra, (0*4)(sp)\n" + " lw t0, (1*4)(sp)\n" + " lw t1, (2*4)(sp)\n" + " lw t2, (3*4)(sp)\n" + " lw a0, (4*4)(sp)\n" + " lw a1, (5*4)(sp)\n" + " lw a2, (6*4)(sp)\n" + " lw a3, (7*4)(sp)\n" + " lw a4, (8*4)(sp)\n" + " lw a5, (9*4)(sp)\n" + " lw a6, (10*4)(sp)\n" + " lw a7, (11*4)(sp)\n" + " lw t3, (12*4)(sp)\n" + " lw t4, (13*4)(sp)\n" + " lw t5, (14*4)(sp)\n" + " lw t6, (15*4)(sp)\n" + "addi sp, sp, 16*4\n" + "ret\n" + ".size mcount, .-mcount\n"); +#else +/* The compiler inserts calls to this routine when we compile with -pg. + The compiler assumes that only r7 and r15 are clobbered so we have to + save r2-r6. The prologue code in _mcount will save what it clobbers in + r8-r14 */ +asm(".section .text\n" + ".balign 4\n" + ".global mcount\n" + ".type mcount, @function\n" + "mcount:\n" + " sub r1, #7*4\n" + " std r2, [r1]\n" + " stq r4, [r1]+2*4\n" + " st r15,[r1]+6*4\n" + " mov r2, r7\n" + " mov r3, r15\n" + " call _mcount\n" + " ld r15,[r1]+6*4\n" + " ldq r4, [r1]+2*4\n" + " ldd r2, [r1]\n" + " add r1, #7*4\n" + " jmp [r15]\n" + ".size mcount, .-mcount\n"); +#endif +#endif