ed647c2e0811e113ee32af099b8f930acfa367ba
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 iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

197) /**
198)  * @brief process next frame
199)  * @param[in,out] state internal state of application
200)  */
201) static void AppBbmProcFrame(AppBbmState *state)
202) {
203)   struct packet {
204)     struct UdpPacket udp;
205)     uint8_t mcuf[12 + state->dataSz];
206)   } pack;
207) 
208)   // read next frame from file
209)   //   - read to mcuf pos 10, so data is placed at pos 12 for MCUF frame
210)   uint32_t len;
211)   if (DFS_ReadFile(&state->fi, *state->sectorBuf,
212)                    pack.mcuf + 10, &len, state->dataSz + 2) != DFS_OK)
213)     len = 0;
214)   if (len < state->dataSz + 2) {
215)     // end of file reached -> use next file in next iteration
216)     state->haveFile = 0;
217)     debug_app_bbm_printf("%hhu: end of file", state->no);
218)     return;
219)   }
220) 
221)   // get frame duration
222)   uint16_t duration = ntohs(*(uint16_t *)(pack.mcuf + 10));
223)   debug_app_bbm_printf("%hhu: frame duration %u", state->no, duration);
224) 
225)   // fill in MCUF header
226)   *(uint32_t *)(pack.mcuf +  0) = htonl(0x23542666);
227)   *(uint16_t *)(pack.mcuf +  4) = htons(state->height);
228)   *(uint16_t *)(pack.mcuf +  6) = htons(state->width);
229)   *(uint16_t *)(pack.mcuf +  8) = htons(state->channels);
230)   *(uint16_t *)(pack.mcuf + 10) = htons(state->maxval);
231) 
232)   // send MCUF frame
233)   if (state->haveAddr) {
234)     memcpy(pack.udp.IpHdr.Dest, state->addr, sizeof(pack.udp.IpHdr.Dest));
235)     pack.udp.UdpHdr.SrcPort = htons(2323);
236)     pack.udp.UdpHdr.DestPort = htons(2323);
237)     UdpSend((unsigned char *)&pack, sizeof(pack));
238)   }
239) 
240)   // wait for frame duration
241)   state->nextActMs += duration;
242) }
243) 
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

244) /**
245)  * @brief initialize BBM play application
246)  * @param[in,out] state internal state of application
247)  *
248)  * state.sectorBuf, state.vi, state.no have to be initialized before calling
249)  */
250) void AppBbmInit(AppBbmState *state) // (extern)
251) {
252)   // default: not initialized
253)   state->isInit = 0;
254) 
255)   // get destination address for MCUF frames
256)   char filename[12];
257)   sprintf(filename, "bbm%hhu/addr", state->no);
258)   if (AppsToolsReadIp(*state->sectorBuf, state->vi,
259)                       filename, state->addr) == 0) {
260)     state->haveAddr = 1;
261)     debug_app_bbm_printf("%hhu: address %hhu.%hhu.%hhu.%hhu", state->no,
262)                          state->addr[0], state->addr[1],
263)                          state->addr[2], state->addr[3]);
264)   } else {
265)     state->haveAddr = 0;
266)     debug_app_bbm_printf("%hhu: no address", state->no);
267)   }
268) 
269)   // initialize internal state
270)   state->idxFile = 0;
271)   state->haveFile = 0;
272) 
273)   // initialized, start with first action now
274)   state->isInit = 1;
275)   TimingGetMs(&state->nextActMs);
276) }
277) 
278) /**
279)  * @brief run BBM play application
280)  * @param[in,out] state internal state of application
281)  */
282) void AppBbmRun(AppBbmState *state) // (extern)
283) {
284)   // not initialized -> leave
285)   if (!state->isInit)
286)     return;
287) 
288)   // time for next action not yet reached -> leave
289)   unsigned long ms;
290)   TimingGetMs(&ms);
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

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

Stefan Schuermans authored 12 years ago

293)     return;
Stefan Schuermans be more conservative on fra...

Stefan Schuermans authored 12 years ago

294)   // if lagging behind more than 100ms, do not try to catch up -> advance time
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

295)   if (delta < -100)
296)     state->nextActMs = ms;
Stefan Schuermans iplemented 1st part of BBM...

Stefan Schuermans authored 12 years ago

297) 
298)   // no file -> open next one
299)   if (!state->haveFile) {
300)     AppBbmNextFile(state);
301)     return; // do not work too much in one step / app might be deactivated now
302)   }
303) 
Stefan Schuermans sending MCUF frames via UDP...

Stefan Schuermans authored 12 years ago

304)   // process next frame
305)   AppBbmProcFrame(state);