streaming server for AM/FM radio via UDP connection.

Dependencies:   mbed EthernetNetIf

RadioServer.cpp

Committer:
soramimi
Date:
2012-08-30
Revision:
2:3b6816fd4ae6
Parent:
1:3357273c97f8

File content as of revision 2:3b6816fd4ae6:

#include "mbed.h"
#include "EthernetNetIf.h"
#include "UDPSocket.h"
#include "crc32.h"
#include "ns9542.h"
#include <vector>

DigitalOut led1(LED1);
DigitalOut led2(LED2);

Ticker ticker;

SPI spi(p5, p6, p7); // mosi, miso, sclk
DigitalOut spi_cs(p8);

EthernetNetIf eth(IpAddr(192,168,0,77), //IP Address
                  IpAddr(255,255,255,0), //Network Mask
                  IpAddr(192,168,0,1), //Gateway
                  IpAddr(192,168,0,1)  //DNS
                 );

UDPSocket udpsocket;

unsigned short sample_l;
unsigned short sample_r;

unsigned short sample_left()
{
    spi_cs = 0;
    int v = spi.write(0x6800) & 0x03ff;
    spi_cs = 1;
    return (v << 6) | (v >> 4);
}

unsigned short sample_right()
{
    spi_cs = 0;
    int v = spi.write(0x7800) & 0x03ff;
    spi_cs = 1;
    return (v << 6) | (v >> 4);
}

struct host_info_t {
    Host host;
    int timer;
    host_info_t()
    {
    }
    host_info_t(Host h)
        : host(h)
        , timer(0)
    {
    }
};

std::vector<host_info_t> hostlist;

void on_udp_socket_event(UDPSocketEvent e)
{
    if (e == UDPSOCKET_READABLE) {
        char buf[64] = {0};
        Host host;
        while (int len = udpsocket.recvfrom(buf, 63, &host)) {
            if (len <= 0) {
                break;
            }
            if (len == 4 && memcmp(buf, "wave", len) == 0) {
                __disable_irq();
                size_t i, n;
                n = hostlist.size();
                for (i = 0; i < n; i++) {
                    if (memcmp(&host, &hostlist[i].host, sizeof(Host)) == 0) {
                        hostlist[i].timer = 0;
                        break;
                    }
                }
                if (i == n) {
                    hostlist.push_back(host_info_t(host));
                }
                __enable_irq();
                continue;
            }
            if (len > 2 && memcmp(buf, "am", 2) == 0) {
                buf[len] = 0;
                int f = atoi(buf + 2);
                ns9542_tune_am9(f);
                continue;
            }
            if (len > 2 && memcmp(buf, "fm", 2) == 0) {
                buf[len] = 0;
                int f = atoi(buf + 2);
                ns9542_tune_fm(f);
                continue;
            }
            if (len == 4 && memcmp(buf, "mute", len) == 0) {
                ns9542_mute(true);
                continue;
            }
        }
    }
}

static inline void store(unsigned short *p, unsigned short n)
{
    ((unsigned char *)p)[0] = n >> 8;
    ((unsigned char *)p)[1] = n & 0xff;
}

static inline void store(unsigned long *p, unsigned long n)
{
    ((unsigned char *)p)[0] = n >> 24;
    ((unsigned char *)p)[1] = n >> 16;
    ((unsigned char *)p)[2] = n >> 8;
    ((unsigned char *)p)[3] = n & 0xff;
}

class Sampler {
private:
    unsigned long buffer_a[257];
    unsigned long buffer_b[257];
    unsigned long *in_ptr;
    unsigned long *out_ptr;
    bool output_available;
    unsigned long crc;
    int offset;
public:
    Sampler()
    {
        in_ptr = buffer_a;
        out_ptr = buffer_b;
        output_available = false;
        offset = 0;
        crc = 0;
    }

    void on_tick()
    {
        if (output_available) {
            return;
        }
        unsigned short *p = (unsigned short *)in_ptr;
        p += offset * 2;
        store(p + 0, sample_l);
        store(p + 1, sample_r);
        crc = crc32(crc, (unsigned char *)p, 4);
        offset++;
        if (offset >= 256) {
            std::swap(in_ptr, out_ptr);
            store(&out_ptr[256], crc);
            output_available = true;
            offset = 0;
            crc = 0;
        }
    }
    
    char const *output_buffer()
    {
        return output_available ? (char const *)out_ptr : 0;
    }

    void output_done()
    {
        output_available = false;
    }
};

Sampler sampler;

void on_tick()
{
    sampler.on_tick();
}

int main()
{
    spi_cs = 1;
    spi.format(16, 0);
    spi.frequency(3000000);

    ns9542_init();

    eth.setup();
    Host host(IpAddr(), 2000);
    udpsocket.bind(host);
    udpsocket.setOnEvent(&on_udp_socket_event);

    led1 = 0;
    ticker.attach(&on_tick, 1.0 / 32000);

    int led1_timer = 0;

    while (1) {
        sample_l = sample_left();
        sample_r = sample_right();

        Net::poll();

        char const *p = sampler.output_buffer();
        if (p) {
            for (std::vector<host_info_t>::iterator it = hostlist.begin(); it != hostlist.end(); it++) {
                udpsocket.sendto(p, 1028, (Host *)&it->host);
            }
            sampler.output_done();

            __disable_irq();
            int i = hostlist.size();
            while (i > 0) {
                i--;
                hostlist[i].timer++;
                if (hostlist[i].timer > 125) {
                    hostlist.erase(hostlist.begin() + i);
                }
            }
            __enable_irq();

            led1_timer++;
            if (led1_timer >= 125) {
                led1 = !led1;
                led1_timer = 0;
            }
        }
    }

    return 0;
}