28c2376fddc17e40fb44b548b9baedd325f23c40
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

1) /* flaneth - flash and ethernet
Stefan Schuermans change email address in hea...

Stefan Schuermans authored 12 years ago

2)    Copyright (C) 2007-2012 Stefan Schuermans <stefan@blinkenarea.org>
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

3)    Copyleft: GNU public license V2 - http://www.gnu.org/copyleft/gpl.html
4)    a BlinkenArea project - http://www.blinkenarea.org/ */
5) 
6) #include <stdio.h>
7) #include <string.h>
8) 
9) #include "apps_tools.h"
10) #include "app_bbm.h"
11) #include "debug.h"
12) #include "dosfs.h"
Stefan Schuermans implement MCUF input via Et...

Stefan Schuermans authored 5 years ago

13) #include "mcuf_in.h"
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

14) #include "nethelp.h"
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

15) #include "udp.h"
Stefan Schuermans BBM play: add serial MCUF o...

Stefan Schuermans authored 12 years ago

16) #include "ser115200.h"
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

17) #include "timing.h"
18) 
19) ///< BBM file header
20) typedef struct app_bbm_header {
21)   uint32_t magic;
22)   uint16_t height;
23)   uint16_t width;
24)   uint16_t channels;
25)   uint16_t maxval;
26)   uint32_t framecnt;
27)   uint32_t duration;
28)   uint32_t frameptr;
29) } AppBbmHeader;
30) 
31) /**
32)  * @brief get name of next file from playlist directory
33)  * @param[in,out] state internal state of application
34)  * @param[out] filename name of file
35)  * @param[in] filename_sz length of filename buffer
36)  * @return 0 if success ful, -1 if not
37)  */
38) static char AppBbmNextName(AppBbmState *state, char *filename,
39)                            unsigned char filename_sz)
40) {
41)   // assemble filename of playlist directory
42)   char dirname[10];
43)   sprintf(dirname, "bbm%hhu/pl", state->no);
44) 
45)   // open playlist directory
46)   DIRINFO di;
47)   di.scratch = *state->sectorBuf;
48)   if (DFS_OpenDir(state->vi, (uint8_t *)dirname, &di) != DFS_OK) {
49)     // no playlist dir -> deactivate application
50)     state->isInit = 0;
51)     debug_app_bbm_printf("%hhu: cannot open directory %s",
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

52)                          state->no, dirname);
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

53)     return -1;
54)   }
55) 
56)   // get file with index idxFile
57)   DIRENT de;
58)   unsigned short idx;
59)   char firstName[11], haveFirst;
60)   haveFirst = 0;
61)   for (idx = 0; idx <= /* file 0 -> loop once */ state->idxFile; ++idx) {
62) 
63)     // get next file
64)     do {
65)       if (DFS_GetNext(state->vi, &di, &de) != 0) {
66)         // no files at all -> deactivate application
67)         if (!haveFirst) {
68)           state->isInit = 0;
69)           debug_app_bbm_printf("%hhu: no files in playlist directory",
70)                                state->no);
71)           return -1;
72)         }
73)         // end of (non-empty) playlist reached -> restart playlist
74)         // -> return first file name, next file index 1
75)         snprintf(filename, filename_sz,
76)                  "bbm%hhu/pl/%-11.11s", state->no, firstName);
77)         filename[filename_sz - 1] = 0;
78)         state->idxFile = 1;
79)         return 0;
80)       }
81)     } while (de.name[0] == 0 ||                            // ignore deleted
82)              de.attr & (ATTR_VOLUME_ID | ATTR_DIRECTORY)); // ignore volumeIDs,
83)                                                            // dirs, long names
84) 
85)     // first file found -> save name (for restarting playlist when end reached)
86)     if (!haveFirst) {
87)       memcpy(firstName, de.name, sizeof(firstName));
88)       haveFirst = 1;
89)     }
90) 
91)   } // for idx
92) 
93)   // found name of file with index idxFile
94)   // -> return file name, increment file index for next file
95)   snprintf(filename, filename_sz,
96)            "bbm%hhu/pl/%-11.11s", state->no, de.name);
97)   filename[filename_sz - 1] = 0;
98)   state->idxFile++;
99)   return 0;
100) }
101) 
102) /**
103)  * @brief parse header of BBM file
104)  * @param[in,out] state internal state of application
105)  */
106) static void AppBbmParseHeader(AppBbmState *state)
107) {
108)   // read BBM header
109)   AppBbmHeader hdr;
110)   uint32_t len;
111)   if (DFS_ReadFile(&state->fi, *state->sectorBuf,
112)                    (uint8_t *)&hdr, &len, sizeof(hdr)) != DFS_OK)
113)     len = 0;
114)   if (len < sizeof(hdr)) {
115)     debug_app_bbm_printf("%hhu: truncated BBM file", state->no);
116)     return; // retry with next file in next iteration
117)   }
118) 
119)   // check header
120)   if (ntohl(hdr.magic) != 0x23542666) {
121)     debug_app_bbm_printf("%hhu: invalid magic %lX in BBM file",
122)                          state->no, hdr.magic);
123)     return; // retry with next file in next iteration
124)   }
125)   state->height   = ntohs(hdr.height);
126)   state->width    = ntohs(hdr.width);
127)   state->channels = ntohs(hdr.channels);
128)   state->maxval   = ntohs(hdr.maxval);
Stefan Schuermans be more conservative on fra...

Stefan Schuermans authored 12 years ago

129)   if (state->height < 1 || state->height > 256 ||
130)       state->width < 1 || state->width > 256 ||
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

131)       state->channels < 1 || state->channels > 3 ||
132)       state->maxval < 1 || state->maxval > 255) {
133)     debug_app_bbm_printf("%hhu: invalid dimensions in BBM file", state->no);
134)     return; // retry with next file in next iteration
135)   }
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

136)   state->dataSz = state->height * state->width * state->channels;
Stefan Schuermans save memory, to avoid stack...

Stefan Schuermans authored 12 years ago

137)   if (state->dataSz > 768) {
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

138)     debug_app_bbm_printf("%hhu: BBM frame size too large", state->no);
139)     return; // retry with next file in next iteration
140)   }
141)   uint32_t frameptr = ntohl(hdr.frameptr);
142)   if (frameptr < sizeof(hdr)) {
143)     debug_app_bbm_printf("%hhu: invalid framepointer in BBM", state->no);
144)     return; // retry with next file in next iteration
145)   }
146) 
147)   // seek to start of first frame
148)   DFS_Seek(&state->fi, frameptr, *state->sectorBuf);
149)   if (state->fi.pointer != frameptr) {
150)     debug_app_bbm_printf("%hhu: seek to first frame failed", state->no);
151)     return; // retry with next file in next iteration
152)   }
153) 
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

154)   // read frame start mrker
155)   uint8_t framestart[4];
156)   if (DFS_ReadFile(&state->fi, *state->sectorBuf,
157)                    framestart, &len, sizeof(framestart)) != DFS_OK)
158)     len = 0;
159)   if (len < sizeof(framestart)) {
160)     debug_app_bbm_printf("%hhu: truncated BBM file", state->no);
161)     return; // retry with next file in next iteration
162)   }
163)   if (memcmp(framestart, "frms", 4) != 0) {
164)     debug_app_bbm_printf("%hhu: invalid frame start marker in BBM file",
165)                          state->no);
166)     return; // retry with next file in next iteration
167)   }
168) 
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

169)   // a file has been found and opened, header is parsed
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

170)   state->haveFile = 1;
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

171)   debug_app_bbm_printf("%hhu: header parsed: %hux%hu-%hu/%hu", state->no,
172)                        state->width, state->height, state->channels,
173)                        state->maxval + 1);
174) }
175) 
176) /**
177)  * @brief open next file from playlist directory
178)  * @param[in,out] state internal state of application
179)  */
180) static void AppBbmNextFile(AppBbmState *state)
181) {
182)   // get name of next file to open
183)   char filename[22];
184)   if (AppBbmNextName(state, filename, sizeof(filename)) != 0)
185)     return;
186) 
187)   // open file
188)   if (DFS_OpenFile(state->vi, (uint8_t *)filename, DFS_READ,
189)                    *state->sectorBuf, &state->fi) != 0) {
190)     debug_app_bbm_printf("%hhu: cannot open file %s", state->no, filename);
191)     return; // retry with next file in next iteration
192)   }
193)   debug_app_bbm_printf("%hhu: file %s", state->no, filename);
194) 
195)   // parse header
196)   AppBbmParseHeader(state);
197) }
198) 
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

199) /**
200)  * @brief process next frame
201)  * @param[in,out] state internal state of application
202)  */
203) static void AppBbmProcFrame(AppBbmState *state)
204) {
205)   struct packet {
206)     struct UdpPacket udp;
207)     uint8_t mcuf[12 + state->dataSz];
208)   } pack;
209) 
210)   // read next frame from file
211)   //   - read to mcuf pos 10, so data is placed at pos 12 for MCUF frame
Stefan Schuermans resend MCUF frame after 1s...

Stefan Schuermans authored 12 years ago

212)   uint32_t pos_before_frame = state->fi.pointer;
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

213)   uint32_t len;
214)   if (DFS_ReadFile(&state->fi, *state->sectorBuf,
215)                    pack.mcuf + 10, &len, state->dataSz + 2) != DFS_OK)
216)     len = 0;
217)   if (len < state->dataSz + 2) {
218)     // end of file reached -> use next file in next iteration
219)     state->haveFile = 0;
220)     debug_app_bbm_printf("%hhu: end of file", state->no);
221)     return;
222)   }
223) 
224)   // get frame duration
225)   uint16_t duration = ntohs(*(uint16_t *)(pack.mcuf + 10));
226)   debug_app_bbm_printf("%hhu: frame duration %u", state->no, duration);
Stefan Schuermans resend MCUF frame after 1s...

Stefan Schuermans authored 12 years ago

227)   // subtract time this frame has already been shown
228)   if (state->thisFrameMs < duration)
229)     duration -= state->thisFrameMs;
230)   else
231)     duration = 0;
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

232) 
233)   // fill in MCUF header
234)   *(uint32_t *)(pack.mcuf +  0) = htonl(0x23542666);
235)   *(uint16_t *)(pack.mcuf +  4) = htons(state->height);
236)   *(uint16_t *)(pack.mcuf +  6) = htons(state->width);
237)   *(uint16_t *)(pack.mcuf +  8) = htons(state->channels);
238)   *(uint16_t *)(pack.mcuf + 10) = htons(state->maxval);
239) 
240)   // send MCUF frame
241)   if (state->haveAddr) {
242)     memcpy(pack.udp.IpHdr.Dest, state->addr, sizeof(pack.udp.IpHdr.Dest));
243)     pack.udp.UdpHdr.SrcPort = htons(2323);
Stefan Schuermans added port number to BBM->M...

Stefan Schuermans authored 12 years ago

244)     pack.udp.UdpHdr.DestPort = htons(state->port);
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

245)     UdpSend((unsigned char *)&pack, sizeof(pack));
246)   }
247) 
Stefan Schuermans implement MCUF input via Et...

Stefan Schuermans authored 5 years ago

248)   // serial output 115200 8N1 (if MCUF input is not active)
249)   if (state->ser115k2 && ! McufInIsActive()) {
Stefan Schuermans BBM play: add serial MCUF o...

Stefan Schuermans authored 12 years ago

250)     Ser115200Send((unsigned char *)&pack.mcuf, sizeof(pack.mcuf));
Stefan Schuermans implement MCUF input via Et...

Stefan Schuermans authored 5 years ago

251)   }
Stefan Schuermans BBM play: add serial MCUF o...

Stefan Schuermans authored 12 years ago

252) 
Stefan Schuermans resend MCUF frame after 1s...

Stefan Schuermans authored 12 years ago

253)   // frame duration not more than one second
254)   if (duration <= 1000) {
255)     // wait for frame duration
256)     state->nextActMs += duration;
257)     // next time, a new frame will be read
258)     state->thisFrameMs = 0;
259)     // done
260)     return;
261)   }
262) 
263)   // show same frame again in 1 second
264) 
265)   // jump back to position before this frame
266)   DFS_Seek(&state->fi, pos_before_frame, *state->sectorBuf);
267)   if (state->fi.pointer != pos_before_frame) {
268)     // broken file -> use next file in next iteration
269)     state->haveFile = 0;
270)     debug_app_bbm_printf("%hhu: seek failed", state->no);
271)     return;
272)   }
273) 
274)   // next action in 1 second
275)   state->nextActMs += 1000;
276)   // next time, the frame has been shown 1 second longer
277)   state->thisFrameMs += 1000;
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

278) }
279) 
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

280) /**
281)  * @brief initialize BBM play application
282)  * @param[in,out] state internal state of application
283)  *
284)  * state.sectorBuf, state.vi, state.no have to be initialized before calling
285)  */
286) void AppBbmInit(AppBbmState *state) // (extern)
287) {
288)   // default: not initialized
289)   state->isInit = 0;
290) 
291)   // get destination address for MCUF frames
Stefan Schuermans BBM play: add serial MCUF o...

Stefan Schuermans authored 12 years ago

292)   {
293)     char filename[12];
294)     sprintf(filename, "bbm%hhu/addr", state->no);
295)     if (AppsToolsReadIp(*state->sectorBuf, state->vi,
296)                         filename, state->addr) == 0) {
297)       state->haveAddr = 1;
298)       debug_app_bbm_printf("%hhu: address %hhu.%hhu.%hhu.%hhu", state->no,
299)                            state->addr[0], state->addr[1],
300)                            state->addr[2], state->addr[3]);
301)     } else {
302)       state->haveAddr = 0;
303)       debug_app_bbm_printf("%hhu: no address", state->no);
304)     }
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

305)   }
306) 
Stefan Schuermans added port number to BBM->M...

Stefan Schuermans authored 12 years ago

307)   // get destination port for MCUF frames
308)   if (state->haveAddr) {
309)     char filename[12];
310)     sprintf(filename, "bbm%hhu/port", state->no);
311)     if (AppsToolsReadPort(*state->sectorBuf, state->vi,
312)                           filename, &state->port) != 0)
313)       state->port = 2323; // default MCUF destination port
314)     debug_app_bbm_printf("%hhu: port %hu", state->no, state->port);
315)   }
316) 
Stefan Schuermans BBM play: add serial MCUF o...

Stefan Schuermans authored 12 years ago

317)   // check if serial output 115200 8N1 is requested
318)   {
319)     char filename[13], serDummy[3];
320)     sprintf(filename, "bbm%hhu/115k2", state->no);
321)     state->ser115k2 = AppsToolsReadStr(*state->sectorBuf, state->vi, filename,
322)                                        serDummy, sizeof(serDummy)) == 0;
323)     debug_app_bbm_printf("%hhu: serial output 115200 8N1: %c",
324)                          state->no, state->ser115k2 ? 'Y' : 'n');
325)   }
326) 
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

327)   // initialize internal state
328)   state->idxFile = 0;
329)   state->haveFile = 0;
Stefan Schuermans resend MCUF frame after 1s...

Stefan Schuermans authored 12 years ago

330)   state->thisFrameMs = 0;
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

331) 
332)   // initialized, start with first action now
333)   state->isInit = 1;
334)   TimingGetMs(&state->nextActMs);
335) }
336) 
337) /**
338)  * @brief run BBM play application
339)  * @param[in,out] state internal state of application
340)  */
341) void AppBbmRun(AppBbmState *state) // (extern)
342) {
343)   // not initialized -> leave
344)   if (!state->isInit)
345)     return;
346) 
347)   // time for next action not yet reached -> leave
348)   unsigned long ms;
349)   TimingGetMs(&ms);
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

350)   long delta = state->nextActMs - ms;
351)   if (delta > 0)
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

352)     return;
Stefan Schuermans resend MCUF frame after 1s...

Stefan Schuermans authored 12 years ago

353)   /* do not manipulate frame time - this can harm synchronous playback
354)   // if lagging behind more than 100ms, do not try to catch up
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

355)   if (delta < -100)
356)     state->nextActMs = ms;
Stefan Schuermans do not try to catch up with...

Stefan Schuermans authored 12 years ago

357)   */
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

358) 
359)   // no file -> open next one
360)   if (!state->haveFile) {
361)     AppBbmNextFile(state);
362)     return; // do not work too much in one step / app might be deactivated now
363)   }
364) 
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

365)   // process next frame
366)   AppBbmProcFrame(state);