This week was mostly spent trying to make sense of dl-fldigi’s source code. After my experiments last semester trying to extract the raw bytes decoded from the incoming RTTY signal, I have finally built what seems like a robust system – or as robust as it can be given dl-fldigi’s “original” codebase.

I’ve settled for using sockets to transmit the byte stream from fldigi to the future packet decoder: they’re fairly simple to use, and they’re cross-platform, provided I use an AF_INET socket connected to localhost instead of a UNIX domain socket.

In src/cw_rtty/rtty.cxx, I’ve replaced the temporary printf() with a call to bin_exporter::log(uint8_t). The exporter class is fairly simple: it opens the socket connection in the constructor, and every time a byte is logged, opens any pending client connection before sending the received byte to each of them.

::cpp
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <unistd.h>
#include "bin_export.h"

bin_exporter::bin_exporter() : socket_(0), is_open_(false) {
    struct sockaddr_in server;

    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    server.sin_port = htons(BINEX_SOCKET_PORT);

    if((socket_ = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("error requesting socket from system\n");
        return;
    }
    fcntl(socket_, F_SETFL, O_NONBLOCK);

    if(bind(socket_, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
        perror("bind");
        close(socket_);
        return;
    }

    if(listen(socket_, 5) < 0) {
        perror("listen");
        close(socket_);
        return;
    }

    is_open_ = true;
}

bin_exporter::~bin_exporter() {
    close(socket_);
}

void bin_exporter::log(uint8_t data) {
    if(!is_open_) { return; }

    int client;
    socklen_t socksize = sizeof(struct sockaddr_in);
    struct sockaddr_in dest;
    
    if((client = accept(socket_, (struct sockaddr *)&dest, &socksize)) > 0) {
        clients_.insert(client);
    }

    for(auto fd : clients_) {
        if(write(fd, &data, 1) != 1) {
            // Remove the client so we don't keep sending them data
            clients_.erase(fd);
        }
    }
}