1

This is the second project I'm working on which will use a design that I'm not 100% confident about. I'd like some feedback, maybe recommendations for a better design, or verification that this would be acceptable by more proficient programmers:

I have a device that I need to interface with. Be it via TCP, UART, UDP, or whatever. I need to send this device data/control, and receive data/control information from this device, but it's not exactly a request/response sort of situation. The device can send data at random times without user stimulus. For instance, the newest device is a full-duplex radio. When the radio correctly demodulates and decodes digital packets, he will send the voice data via UDP to my library. It doesn't wait for a user for input. When you want to send stuff out over the air, I send control information, and then data for the radio to modulate and push over the air.

Packets that go between my library and the device are framed: ie, each packet is prepended a header (and other metadata to identify the type of packet) and appended a CRC and footer so I know a) the start of a packet in case garbage is somehow introduced over the stream, and b) the data is correct (by verifying the footer, and the correct CRC).

Okay, so I'm designing a library that will need to be handed to a different developer for application development. So all the internals are abstracted away from him. For ease in this example, I want this library to have 4 calls: send_data, receive_data, send_voice, receive_voice. The different packet types (voice and data) are sent over one port. The library can frame and parse the appropriate packets (for sending and receiving, respectively), and so can the device.

For sending data to the device:
This is easy.
The application developer calls either send_data or send_voice. I take relevant voice or data, frame it accordingly, and send it to the device. The device parses the data, and sends it on its way. The calls are thread safe, so the developer can't call a UDP send asynchronously.

For receiving data from the device:
This is where I'm not 100% confident in the design.
I start a receive (RX) thread in my library. When I get a packet (either voice or data), I de-frame the packet, and put either the voice or data on a respective queue (a voice queue and a data queue).
When the application developer wants voice, he calls receive_voice and it will return a pop from the voice queue. When the application developer wants data, he calls receive_data and it will return a pop from the data queue. Obviously I'm careful the queues can't grow to infinity, and when a queue is MAX_QUEUE_LEN, I pop a voice/data packet off the queue and discard it before putting a new one on, and set a 'overrun' flag. This flag can be set/read with set_X_overrun, or get_X_overrun, where X is voice or data depending on the queue.

I actually like the design. However, what do other people think? I'm not sure what people think about putting a running thread inside of a library? I guess the other option is just to have read_data and read_voice calls that will block until a packet is found that matches what they want (voice or data). This eliminates the need for a running thread, but then the opposite packet is essentially disregarded while we wait for the one of choice. Or is there another design I'm not even thinking about?

Sorry about the long-winded and probably unclear design question. Now that I feel like more of a confident programmer using the semantics/syntax of languages themselves, I've been getting much more interested in the design of programs rather than the nitty-gritty of the lower level calls. I'm striving for the best/coolest design possible rather than something that 'just works.'

Bonus points if there's some sort of open source software out there that I can look into and improve my design.

Image of design:

http://imgur.com/VoEveCn]

Pseudo code:

public void send_data(buf) {
    frame_data_packet(buf);
    udp_send(buf);
}

public void send_voice(buf) {
    frame_voice_packet(buf);
    udp_send_(buf);
}

public void receive_data(buf) {
    buf = data_queue.pop();
}

public void receive_voice(buf) {
    buf = voice_queue.pop();
}

/* RX Thread */
public void run_rx()
{
    while (run_rx_f) {
        type = deframe_data(data);
        switch (type) {
            case VOICE:
                voice_queue.add(data);
                break;
            case DATA:
                data_queue.add(data);
                break;
        }
    }
}

1 Answer 1

1

Addressing a possible improvement: Could improve your design by having a generic send() and receive() accepting an Abstract buffer class and two classes of Voice and Data buffers that extend it.

This makes your internal code easier to handle and can enhance modularity and extensibility. ie) allows ease for you to possibly improve support different types of send and receive methods without a method explosion from your library. Say you want to add capability to specially handle images.

The VoiceBuffer and DataBuffer classes could even be abstract, forcing whoever is going to implement your library to address how the buffer of data is constructed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.