#include #include #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" #include "layer1/tx.h" #include "layer1/rx.h" #include "layer2/tundev.h" #include "sdr/sdr.h" #include "config.h" #define RESULT_CHECK(stmt) { \ result_t res = stmt; \ if(res != OK) { \ fprintf(stderr, "Error %d in %s:%d!\n", res, __FILE__, __LINE__); \ exit(1); \ } \ } static int m_tunfd = -1; static bool m_running = true; static double next_tx_switch_time = 0.0; static void block_tx_for(unsigned offset_ms) { next_tx_switch_time = get_hires_time() + (double)offset_ms * 0.001; } void print_complex_array(const char *varname, float complex const *array, size_t len) { fprintf(stderr, "%s=np.array([%f%+fj", varname, crealf(array[0]), cimagf(array[0])); for(size_t k = 1; k < len; k++) { fprintf(stderr, ", %f%+fj", crealf(array[k]), cimagf(array[k])); } fprintf(stderr, "])\n"); } void hexdump(const uint8_t *data, size_t len) { static const char lut[16] = "0123456789ABCDEF"; static const size_t BYTES_PER_LINE = 16; size_t pos = 0; while(pos < len) { size_t bytes_in_line = len - pos; if(bytes_in_line > BYTES_PER_LINE) { bytes_in_line = BYTES_PER_LINE; } for(size_t i = 0; i < BYTES_PER_LINE; i++) { if(i >= bytes_in_line) { fputs(" ", stderr); } else { uint8_t byte = data[pos+i]; fprintf(stderr, "%c%c ", lut[byte >> 4], lut[byte & 0x0F]); } } fputs(" ", stderr); for(size_t i = 0; i < bytes_in_line; i++) { uint8_t byte = data[pos+i]; if(isprint(byte)) { putc(byte, stderr); } else { putc('.', stderr); } } putc('\n', stderr); pos += bytes_in_line; } } void cb_rx(rx_evt_t evt, uint8_t *packet_data, size_t packet_len) { int ret; switch(evt) { case RX_EVT_CHECKSUM_ERROR: fprintf(stderr, "Received a message of %zu bytes, but decoding failed.\n", packet_len); //fprintf(stderr, "=== FAILED PAYLOAD ===\n"); //hexdump(packet_data, packet_len); //fprintf(stderr, "=======================\n"); break; case RX_EVT_PACKET_RECEIVED: fprintf(stderr, "A message of %zu bytes was decoded successfully.\n", packet_len); //fprintf(stderr, "=== DECODED PAYLOAD (%4zu bytes) ===\n", packet_len); //hexdump(packet_data, packet_len < 64 ? packet_len : 64); //fprintf(stderr, "====================================\n"); block_tx_for(TX_SWITCH_BACKOFF_END_OF_PACKET_MS); ret = write(m_tunfd, packet_data, packet_len); if(ret < 0) { perror("write"); } break; case RX_EVT_PREAMBLE_FOUND: fprintf(stderr, "Found preamble!\n"); block_tx_for(TX_SWITCH_BACKOFF_PREAMBLE_MS); break; } } static int debug_fd; #define CHUNKSIZE_BB 16384 #define CHUNKSIZE_RF (CHUNKSIZE_BB * SDR_OVERSAMPLING) static result_t transmit_in_chunks(sdr_ctx_t *sdr, const float complex *samples, size_t len) { size_t transmitted = 0; unsigned retry_counter = 0; float complex rf_samples[CHUNKSIZE_RF]; while(transmitted < len) { size_t to_transmit_bb = len - transmitted; if(to_transmit_bb > CHUNKSIZE_BB) { to_transmit_bb = CHUNKSIZE_BB; } RESULT_CHECK(sdr_baseband_to_rf(sdr, samples + transmitted, to_transmit_bb, rf_samples, CHUNKSIZE_RF)); size_t to_transmit_rf = to_transmit_bb * SDR_OVERSAMPLING; result_t result = sdr_transmit(sdr, rf_samples, to_transmit_rf, 100000); if(result != OK) { retry_counter++; fprintf(stderr, "sdr_transmit failed %d times\n", retry_counter); if(retry_counter > 3) { return result; } else { continue; } } write(debug_fd, rf_samples, to_transmit_rf*sizeof(rf_samples[0])); fprintf(stderr, "t"); transmitted += to_transmit_bb; retry_counter = 0; } return OK; } int main(void) { layer1_tx_t tx; layer1_rx_t rx; sdr_ctx_t sdr; SoapySDR_setLogLevel(SOAPY_SDR_DEBUG); bool on_air = true; debug_fd = open("/tmp/dump.cf32", O_CREAT | O_WRONLY | O_TRUNC); // ** Initialize ** char devname[IFNAMSIZ] = "hamnet70"; m_tunfd = tundev_open(devname); if(m_tunfd < 0) { return 1; } RESULT_CHECK(sdr_init(&sdr)); RESULT_CHECK(layer1_tx_init(&tx)); RESULT_CHECK(layer1_rx_init(&rx, cb_rx)); // ** Process packets ** struct pollfd pfd; memset(&pfd, 0, sizeof(pfd)); pfd.fd = m_tunfd; pfd.events = POLLIN; // start in TX mode to work around SoapyHackRF not setting the correct frequency. RESULT_CHECK(sdr_start_tx(&sdr, 1)); unsigned rx_retries = 0; while(m_running) { double now = get_hires_time(); if((now > next_tx_switch_time) && (on_air || !layer1_rx_is_busy(&rx))) { int ret = poll(&pfd, 1, 0); if(ret < 0) { perror("poll"); break; } else if(ret > 0) { // there is a packet to be read. uint8_t packetbuf[2048]; ret = read(m_tunfd, packetbuf, sizeof(packetbuf)); if(ret < 0) { perror("read"); break; } else if(ret == 0) { // no more data break; } fprintf(stderr, "Transmitting packet with %d bytes.\n", ret); RESULT_CHECK(layer1_tx_reset(&tx)); // ** Modulate packet ** RESULT_CHECK(layer1_tx_add_packet_to_burst(&tx, packetbuf, ret)); RESULT_CHECK(layer1_tx_finalize_burst(&tx)); size_t burst_len = layer1_tx_get_sample_count(&tx); const float complex *whole_burst = layer1_tx_get_sample_data(&tx); dump_array_cf(whole_burst, burst_len, 1.0f, "/tmp/tx.cpx"); if(!on_air) { RESULT_CHECK(sdr_start_tx(&sdr, burst_len * SDR_OVERSAMPLING)); RESULT_CHECK(sdr_flush_tx_buffer(&sdr)); } RESULT_CHECK(transmit_in_chunks(&sdr, whole_burst, burst_len)); on_air = true; } else if(on_air) { // ret == 0 RESULT_CHECK(sdr_flush_tx_buffer(&sdr)); RESULT_CHECK(sdr_start_rx(&sdr)); on_air = false; block_tx_for(TX_SWITCH_BACKOFF_AFTER_RX_ON); } } if(!on_air) { // ** Receive signal ** float complex rf_samples[CHUNKSIZE_RF]; float complex bb_samples[CHUNKSIZE_BB]; size_t n_rf_samples = CHUNKSIZE_RF; size_t n_bb_samples; if(sdr_receive(&sdr, rf_samples, &n_rf_samples, 100000) != OK) { rx_retries++; fprintf(stderr, "sdr_receive() failed %d times.\n", rx_retries); if(rx_retries >= 3) { break; } else { continue; } } rx_retries = 0; fprintf(stderr, "r"); RESULT_CHECK(sdr_rf_to_baseband(&sdr, rf_samples, n_rf_samples, bb_samples, CHUNKSIZE_BB)); n_bb_samples = n_rf_samples / SDR_OVERSAMPLING; RESULT_CHECK(layer1_rx_process(&rx, bb_samples, n_bb_samples)); } else { rx_retries = 0; } } close(debug_fd); // ** Cleanup ** layer1_tx_shutdown(&tx); layer1_rx_shutdown(&rx); sdr_destroy(&sdr); fprintf(stderr, "Done.\n"); }