streaming server for AM/FM radio via UDP connection.

Dependencies:   mbed EthernetNetIf

Revision:
0:bd865e5a3df3
Child:
1:3357273c97f8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RadioServer.cpp	Mon Feb 28 11:49:39 2011 +0000
@@ -0,0 +1,227 @@
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "UDPSocket.h"
+#include "TextLCD.h"
+#include "crc32.h"
+#include "ns9542.h"
+#include <vector>
+
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+TextLCD lcd(p21, p22, p23, p24, p25, p26);
+
+Ticker ticker;
+
+SPI spi(p5, p6, p7); // mosi, miso, sclk
+DigitalOut spi_cs(p8);
+
+EthernetNetIf eth(IpAddr(192,168,0,100), //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 == 7 && memcmp(buf, "request", 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", 4) == 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;
+}