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"
|
sending MCUF frames via UDP...
Stefan Schuermans authored 12 years ago
|
14) #include "udp.h"
|
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",
|
sending MCUF frames via UDP...
Stefan Schuermans authored 12 years ago
|
50) state->no, dirname);
|
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);
|
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 ||
|
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) }
|
sending MCUF frames via UDP...
Stefan Schuermans authored 12 years ago
|
134) state->dataSz = state->height * state->width * state->channels;
|
save memory, to avoid stack...
Stefan Schuermans authored 12 years ago
|
135) if (state->dataSz > 768) {
|
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)
|
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)
|
iplemented 1st part of BBM...
Stefan Schuermans authored 12 years ago
|
167) // a file has been found and opened, header is parsed
|
sending MCUF frames via UDP...
Stefan Schuermans authored 12 years ago
|
168) state->haveFile = 1;
|
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)
|
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)
|
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);
|
sending MCUF frames via UDP...
Stefan Schuermans authored 12 years ago
|
291) long delta = state->nextActMs - ms;
292) if (delta > 0)
|
iplemented 1st part of BBM...
Stefan Schuermans authored 12 years ago
|
293) return;
|
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
|
sending MCUF frames via UDP...
Stefan Schuermans authored 12 years ago
|
295) if (delta < -100)
296) state->nextActMs = ms;
|
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)
|
sending MCUF frames via UDP...
Stefan Schuermans authored 12 years ago
|
304) // process next frame
305) AppBbmProcFrame(state);
|