streaming server for AM/FM radio via UDP connection.

Dependencies:   mbed EthernetNetIf

Committer:
soramimi
Date:
Thu Aug 30 08:35:20 2012 +0000
Revision:
2:3b6816fd4ae6
Parent:
1:3357273c97f8

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
soramimi 0:bd865e5a3df3 1 #include "mbed.h"
soramimi 0:bd865e5a3df3 2 #include "EthernetNetIf.h"
soramimi 0:bd865e5a3df3 3 #include "UDPSocket.h"
soramimi 0:bd865e5a3df3 4 #include "crc32.h"
soramimi 0:bd865e5a3df3 5 #include "ns9542.h"
soramimi 0:bd865e5a3df3 6 #include <vector>
soramimi 0:bd865e5a3df3 7
soramimi 0:bd865e5a3df3 8 DigitalOut led1(LED1);
soramimi 0:bd865e5a3df3 9 DigitalOut led2(LED2);
soramimi 0:bd865e5a3df3 10
soramimi 0:bd865e5a3df3 11 Ticker ticker;
soramimi 0:bd865e5a3df3 12
soramimi 0:bd865e5a3df3 13 SPI spi(p5, p6, p7); // mosi, miso, sclk
soramimi 0:bd865e5a3df3 14 DigitalOut spi_cs(p8);
soramimi 0:bd865e5a3df3 15
soramimi 2:3b6816fd4ae6 16 EthernetNetIf eth(IpAddr(192,168,0,77), //IP Address
soramimi 0:bd865e5a3df3 17 IpAddr(255,255,255,0), //Network Mask
soramimi 0:bd865e5a3df3 18 IpAddr(192,168,0,1), //Gateway
soramimi 0:bd865e5a3df3 19 IpAddr(192,168,0,1) //DNS
soramimi 0:bd865e5a3df3 20 );
soramimi 0:bd865e5a3df3 21
soramimi 0:bd865e5a3df3 22 UDPSocket udpsocket;
soramimi 0:bd865e5a3df3 23
soramimi 0:bd865e5a3df3 24 unsigned short sample_l;
soramimi 0:bd865e5a3df3 25 unsigned short sample_r;
soramimi 0:bd865e5a3df3 26
soramimi 0:bd865e5a3df3 27 unsigned short sample_left()
soramimi 0:bd865e5a3df3 28 {
soramimi 0:bd865e5a3df3 29 spi_cs = 0;
soramimi 0:bd865e5a3df3 30 int v = spi.write(0x6800) & 0x03ff;
soramimi 0:bd865e5a3df3 31 spi_cs = 1;
soramimi 0:bd865e5a3df3 32 return (v << 6) | (v >> 4);
soramimi 0:bd865e5a3df3 33 }
soramimi 0:bd865e5a3df3 34
soramimi 0:bd865e5a3df3 35 unsigned short sample_right()
soramimi 0:bd865e5a3df3 36 {
soramimi 0:bd865e5a3df3 37 spi_cs = 0;
soramimi 0:bd865e5a3df3 38 int v = spi.write(0x7800) & 0x03ff;
soramimi 0:bd865e5a3df3 39 spi_cs = 1;
soramimi 0:bd865e5a3df3 40 return (v << 6) | (v >> 4);
soramimi 0:bd865e5a3df3 41 }
soramimi 0:bd865e5a3df3 42
soramimi 0:bd865e5a3df3 43 struct host_info_t {
soramimi 0:bd865e5a3df3 44 Host host;
soramimi 0:bd865e5a3df3 45 int timer;
soramimi 0:bd865e5a3df3 46 host_info_t()
soramimi 0:bd865e5a3df3 47 {
soramimi 0:bd865e5a3df3 48 }
soramimi 0:bd865e5a3df3 49 host_info_t(Host h)
soramimi 0:bd865e5a3df3 50 : host(h)
soramimi 0:bd865e5a3df3 51 , timer(0)
soramimi 0:bd865e5a3df3 52 {
soramimi 0:bd865e5a3df3 53 }
soramimi 0:bd865e5a3df3 54 };
soramimi 0:bd865e5a3df3 55
soramimi 0:bd865e5a3df3 56 std::vector<host_info_t> hostlist;
soramimi 0:bd865e5a3df3 57
soramimi 0:bd865e5a3df3 58 void on_udp_socket_event(UDPSocketEvent e)
soramimi 0:bd865e5a3df3 59 {
soramimi 0:bd865e5a3df3 60 if (e == UDPSOCKET_READABLE) {
soramimi 0:bd865e5a3df3 61 char buf[64] = {0};
soramimi 0:bd865e5a3df3 62 Host host;
soramimi 0:bd865e5a3df3 63 while (int len = udpsocket.recvfrom(buf, 63, &host)) {
soramimi 0:bd865e5a3df3 64 if (len <= 0) {
soramimi 0:bd865e5a3df3 65 break;
soramimi 0:bd865e5a3df3 66 }
soramimi 2:3b6816fd4ae6 67 if (len == 4 && memcmp(buf, "wave", len) == 0) {
soramimi 0:bd865e5a3df3 68 __disable_irq();
soramimi 0:bd865e5a3df3 69 size_t i, n;
soramimi 0:bd865e5a3df3 70 n = hostlist.size();
soramimi 0:bd865e5a3df3 71 for (i = 0; i < n; i++) {
soramimi 0:bd865e5a3df3 72 if (memcmp(&host, &hostlist[i].host, sizeof(Host)) == 0) {
soramimi 0:bd865e5a3df3 73 hostlist[i].timer = 0;
soramimi 0:bd865e5a3df3 74 break;
soramimi 0:bd865e5a3df3 75 }
soramimi 0:bd865e5a3df3 76 }
soramimi 0:bd865e5a3df3 77 if (i == n) {
soramimi 0:bd865e5a3df3 78 hostlist.push_back(host_info_t(host));
soramimi 0:bd865e5a3df3 79 }
soramimi 0:bd865e5a3df3 80 __enable_irq();
soramimi 0:bd865e5a3df3 81 continue;
soramimi 0:bd865e5a3df3 82 }
soramimi 0:bd865e5a3df3 83 if (len > 2 && memcmp(buf, "am", 2) == 0) {
soramimi 0:bd865e5a3df3 84 buf[len] = 0;
soramimi 0:bd865e5a3df3 85 int f = atoi(buf + 2);
soramimi 0:bd865e5a3df3 86 ns9542_tune_am9(f);
soramimi 0:bd865e5a3df3 87 continue;
soramimi 0:bd865e5a3df3 88 }
soramimi 0:bd865e5a3df3 89 if (len > 2 && memcmp(buf, "fm", 2) == 0) {
soramimi 0:bd865e5a3df3 90 buf[len] = 0;
soramimi 0:bd865e5a3df3 91 int f = atoi(buf + 2);
soramimi 0:bd865e5a3df3 92 ns9542_tune_fm(f);
soramimi 0:bd865e5a3df3 93 continue;
soramimi 0:bd865e5a3df3 94 }
soramimi 1:3357273c97f8 95 if (len == 4 && memcmp(buf, "mute", len) == 0) {
soramimi 0:bd865e5a3df3 96 ns9542_mute(true);
soramimi 0:bd865e5a3df3 97 continue;
soramimi 0:bd865e5a3df3 98 }
soramimi 0:bd865e5a3df3 99 }
soramimi 0:bd865e5a3df3 100 }
soramimi 0:bd865e5a3df3 101 }
soramimi 0:bd865e5a3df3 102
soramimi 0:bd865e5a3df3 103 static inline void store(unsigned short *p, unsigned short n)
soramimi 0:bd865e5a3df3 104 {
soramimi 0:bd865e5a3df3 105 ((unsigned char *)p)[0] = n >> 8;
soramimi 0:bd865e5a3df3 106 ((unsigned char *)p)[1] = n & 0xff;
soramimi 0:bd865e5a3df3 107 }
soramimi 0:bd865e5a3df3 108
soramimi 0:bd865e5a3df3 109 static inline void store(unsigned long *p, unsigned long n)
soramimi 0:bd865e5a3df3 110 {
soramimi 0:bd865e5a3df3 111 ((unsigned char *)p)[0] = n >> 24;
soramimi 0:bd865e5a3df3 112 ((unsigned char *)p)[1] = n >> 16;
soramimi 0:bd865e5a3df3 113 ((unsigned char *)p)[2] = n >> 8;
soramimi 0:bd865e5a3df3 114 ((unsigned char *)p)[3] = n & 0xff;
soramimi 0:bd865e5a3df3 115 }
soramimi 0:bd865e5a3df3 116
soramimi 0:bd865e5a3df3 117 class Sampler {
soramimi 0:bd865e5a3df3 118 private:
soramimi 0:bd865e5a3df3 119 unsigned long buffer_a[257];
soramimi 0:bd865e5a3df3 120 unsigned long buffer_b[257];
soramimi 0:bd865e5a3df3 121 unsigned long *in_ptr;
soramimi 0:bd865e5a3df3 122 unsigned long *out_ptr;
soramimi 0:bd865e5a3df3 123 bool output_available;
soramimi 0:bd865e5a3df3 124 unsigned long crc;
soramimi 0:bd865e5a3df3 125 int offset;
soramimi 0:bd865e5a3df3 126 public:
soramimi 0:bd865e5a3df3 127 Sampler()
soramimi 0:bd865e5a3df3 128 {
soramimi 0:bd865e5a3df3 129 in_ptr = buffer_a;
soramimi 0:bd865e5a3df3 130 out_ptr = buffer_b;
soramimi 0:bd865e5a3df3 131 output_available = false;
soramimi 0:bd865e5a3df3 132 offset = 0;
soramimi 0:bd865e5a3df3 133 crc = 0;
soramimi 0:bd865e5a3df3 134 }
soramimi 0:bd865e5a3df3 135
soramimi 0:bd865e5a3df3 136 void on_tick()
soramimi 0:bd865e5a3df3 137 {
soramimi 0:bd865e5a3df3 138 if (output_available) {
soramimi 0:bd865e5a3df3 139 return;
soramimi 0:bd865e5a3df3 140 }
soramimi 0:bd865e5a3df3 141 unsigned short *p = (unsigned short *)in_ptr;
soramimi 0:bd865e5a3df3 142 p += offset * 2;
soramimi 0:bd865e5a3df3 143 store(p + 0, sample_l);
soramimi 0:bd865e5a3df3 144 store(p + 1, sample_r);
soramimi 0:bd865e5a3df3 145 crc = crc32(crc, (unsigned char *)p, 4);
soramimi 0:bd865e5a3df3 146 offset++;
soramimi 0:bd865e5a3df3 147 if (offset >= 256) {
soramimi 0:bd865e5a3df3 148 std::swap(in_ptr, out_ptr);
soramimi 0:bd865e5a3df3 149 store(&out_ptr[256], crc);
soramimi 0:bd865e5a3df3 150 output_available = true;
soramimi 0:bd865e5a3df3 151 offset = 0;
soramimi 0:bd865e5a3df3 152 crc = 0;
soramimi 0:bd865e5a3df3 153 }
soramimi 0:bd865e5a3df3 154 }
soramimi 0:bd865e5a3df3 155
soramimi 0:bd865e5a3df3 156 char const *output_buffer()
soramimi 0:bd865e5a3df3 157 {
soramimi 0:bd865e5a3df3 158 return output_available ? (char const *)out_ptr : 0;
soramimi 0:bd865e5a3df3 159 }
soramimi 0:bd865e5a3df3 160
soramimi 0:bd865e5a3df3 161 void output_done()
soramimi 0:bd865e5a3df3 162 {
soramimi 0:bd865e5a3df3 163 output_available = false;
soramimi 0:bd865e5a3df3 164 }
soramimi 0:bd865e5a3df3 165 };
soramimi 0:bd865e5a3df3 166
soramimi 0:bd865e5a3df3 167 Sampler sampler;
soramimi 0:bd865e5a3df3 168
soramimi 0:bd865e5a3df3 169 void on_tick()
soramimi 0:bd865e5a3df3 170 {
soramimi 0:bd865e5a3df3 171 sampler.on_tick();
soramimi 0:bd865e5a3df3 172 }
soramimi 0:bd865e5a3df3 173
soramimi 0:bd865e5a3df3 174 int main()
soramimi 0:bd865e5a3df3 175 {
soramimi 0:bd865e5a3df3 176 spi_cs = 1;
soramimi 0:bd865e5a3df3 177 spi.format(16, 0);
soramimi 0:bd865e5a3df3 178 spi.frequency(3000000);
soramimi 0:bd865e5a3df3 179
soramimi 0:bd865e5a3df3 180 ns9542_init();
soramimi 0:bd865e5a3df3 181
soramimi 0:bd865e5a3df3 182 eth.setup();
soramimi 0:bd865e5a3df3 183 Host host(IpAddr(), 2000);
soramimi 0:bd865e5a3df3 184 udpsocket.bind(host);
soramimi 0:bd865e5a3df3 185 udpsocket.setOnEvent(&on_udp_socket_event);
soramimi 0:bd865e5a3df3 186
soramimi 0:bd865e5a3df3 187 led1 = 0;
soramimi 0:bd865e5a3df3 188 ticker.attach(&on_tick, 1.0 / 32000);
soramimi 0:bd865e5a3df3 189
soramimi 0:bd865e5a3df3 190 int led1_timer = 0;
soramimi 0:bd865e5a3df3 191
soramimi 0:bd865e5a3df3 192 while (1) {
soramimi 0:bd865e5a3df3 193 sample_l = sample_left();
soramimi 0:bd865e5a3df3 194 sample_r = sample_right();
soramimi 0:bd865e5a3df3 195
soramimi 0:bd865e5a3df3 196 Net::poll();
soramimi 0:bd865e5a3df3 197
soramimi 0:bd865e5a3df3 198 char const *p = sampler.output_buffer();
soramimi 0:bd865e5a3df3 199 if (p) {
soramimi 0:bd865e5a3df3 200 for (std::vector<host_info_t>::iterator it = hostlist.begin(); it != hostlist.end(); it++) {
soramimi 0:bd865e5a3df3 201 udpsocket.sendto(p, 1028, (Host *)&it->host);
soramimi 0:bd865e5a3df3 202 }
soramimi 0:bd865e5a3df3 203 sampler.output_done();
soramimi 0:bd865e5a3df3 204
soramimi 0:bd865e5a3df3 205 __disable_irq();
soramimi 0:bd865e5a3df3 206 int i = hostlist.size();
soramimi 0:bd865e5a3df3 207 while (i > 0) {
soramimi 0:bd865e5a3df3 208 i--;
soramimi 0:bd865e5a3df3 209 hostlist[i].timer++;
soramimi 0:bd865e5a3df3 210 if (hostlist[i].timer > 125) {
soramimi 0:bd865e5a3df3 211 hostlist.erase(hostlist.begin() + i);
soramimi 0:bd865e5a3df3 212 }
soramimi 0:bd865e5a3df3 213 }
soramimi 0:bd865e5a3df3 214 __enable_irq();
soramimi 0:bd865e5a3df3 215
soramimi 0:bd865e5a3df3 216 led1_timer++;
soramimi 0:bd865e5a3df3 217 if (led1_timer >= 125) {
soramimi 0:bd865e5a3df3 218 led1 = !led1;
soramimi 0:bd865e5a3df3 219 led1_timer = 0;
soramimi 0:bd865e5a3df3 220 }
soramimi 0:bd865e5a3df3 221 }
soramimi 0:bd865e5a3df3 222 }
soramimi 0:bd865e5a3df3 223
soramimi 0:bd865e5a3df3 224 return 0;
soramimi 0:bd865e5a3df3 225 }