#include #include #include #include #include #include #include #include "utils.h" #include "layer1/tx.h" #include "layer1/rx.h" #include "layer2/tundev.h" #define RESULT_CHECK(stmt) { \ result_t res = stmt; \ if(res != OK) { \ fprintf(stderr, "Error %d in %s:%d!", res, __FILE__, __LINE__); \ exit(1); \ } \ } static int m_tunfd = -1; static bool m_running = true; 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 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"); //fprintf(stderr, "%s\n", packet_data); //fprintf(stderr, "=======================\n"); break; case RX_EVT_PACKET_RECEIVED: fprintf(stderr, "=== DECODED PAYLOAD (%4zu bytes) ===\n", packet_len); fprintf(stderr, "%s\n", packet_data); fprintf(stderr, "====================================\n"); ret = write(m_tunfd, packet_data, packet_len); if(ret < 0) { perror("write"); } break; case RX_EVT_PREAMBLE_FOUND: fprintf(stderr, "Found preamble!\n"); break; } } int main(void) { layer1_tx_t tx; layer1_rx_t rx; // ** Initialize ** char devname[IFNAMSIZ] = "hamnet70"; m_tunfd = tundev_open(devname); if(m_tunfd < 0) { return 1; } RESULT_CHECK(layer1_tx_init(&tx)); RESULT_CHECK(layer1_rx_init(&rx, cb_rx)); // channel emulation channel_cccf channel = channel_cccf_create(); float snr = 15.0f; channel_cccf_add_awgn(channel, -snr, snr); channel_cccf_add_carrier_offset(channel, 0.20f, 1.00f); //channel_cccf_add_shadowing(channel, 1.00f, 0.1f); // ** Process packets ** uint8_t packetbuf[2048]; while(m_running) { int 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"); // ** Apply channel distortions ** float complex msg_received[burst_len]; channel_cccf_execute_block(channel, whole_burst, burst_len, msg_received); // scale the entire signal to give the AGC something to do for(size_t i = 0; i < burst_len; i++) { msg_received[i] *= 0.02f; } dump_array_cf(msg_received, burst_len, 1.0f, "/tmp/rx.cpx"); // ** Receive signal ** RESULT_CHECK(layer1_rx_process(&rx, msg_received, burst_len)); } // ** Cleanup ** channel_cccf_destroy(channel); layer1_tx_shutdown(&tx); layer1_rx_shutdown(&rx); fprintf(stderr, "Done.\n"); }