2dde65d9611ef81cd2026e229a481f1787e5c27d
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

1) /* flaneth - flash and ethernet
2)    Copyright (C) 2007-2012 Stefan Schuermans <stefan@schuermans.info>
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"
13) #include "nethelp.h"
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

198) /**
199)  * @brief process next frame
200)  * @param[in,out] state internal state of application
201)  */
202) static void AppBbmProcFrame(AppBbmState *state)
203) {
204)   struct packet {
205)     struct UdpPacket udp;
206)     uint8_t mcuf[12 + state->dataSz];
207)   } pack;
208) 
209)   // read next frame from file
210)   //   - 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

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

244)     UdpSend((unsigned char *)&pack, sizeof(pack));
245)   }
246) 
Stefan Schuermans BBM play: add serial MCUF o...

Stefan Schuermans authored 12 years ago

247)   // serial output 115200 8N1
248)   if (state->ser115k2)
249)     Ser115200Send((unsigned char *)&pack.mcuf, sizeof(pack.mcuf));
250) 
Stefan Schuermans resend MCUF frame after 1s...

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

276) }
277) 
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

303)   }
304) 
Stefan Schuermans added port number to BBM->M...

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

351)   /* do not manipulate frame time - this can harm synchronous playback
352)   // 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

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

363)   // process next frame
364)   AppBbmProcFrame(state);