| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lwip_fs.c
Go to the documentation of this file.
1 /*
2 * @brief lwIP Filesystem implementation module
3 *
4 * @note
5 * Copyright(C) NXP Semiconductors, 2012
6 * All rights reserved.
7 *
8 * @par
9 * Software that is described herein is for illustrative purposes only
10 * which provides customers with programming information regarding the
11 * LPC products. This software is supplied "AS IS" without any warranties of
12 * any kind, and NXP Semiconductors and its licensor disclaim any and
13 * all warranties, express or implied, including all implied warranties of
14 * merchantability, fitness for a particular purpose and non-infringement of
15 * intellectual property rights. NXP Semiconductors assumes no responsibility
16 * or liability for the use of the software, conveys no license or rights under any
17 * patent, copyright, mask work right, or any other intellectual property rights in
18 * or to any products. NXP Semiconductors reserves the right to make changes
19 * in the software without notification. NXP Semiconductors also makes no
20 * representation or warranty that such application will be suitable for the
21 * specified use without further testing or modification.
22 *
23 * @par
24 * Permission to use, copy, modify, and distribute this software and its
25 * documentation is hereby granted, under NXP Semiconductors' and its
26 * licensor's relevant copyrights in the software, without fee, provided that it
27 * is used in conjunction with NXP Semiconductors microcontrollers. This
28 * copyright, permission, and disclaimer notice must appear in all copies of
29 * this code.
30 */
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35
36 #include "lwip/mem.h"
37 #include "lwip/memp.h"
38 #include "board.h"
39 #include "ff.h"
40 #include "fs_mem.h"
41 #include "lwip_fs.h"
42 #include "httpd_structs.h"
43
49 /*****************************************************************************
50 * Private types/enumerations/variables
51 ****************************************************************************/
52
53 /* Default html file */
54 const static char http_index_html[] =
55 "<html><head><title>Congrats!</title></head>"
56 "<body><h1>Welcome to our lwIP HTTP server!</h1>"
57 "<p>This is a small test page, served by httpd of "
58 "lwip.</p></body></html>";
59
60 static FATFS Fatfs; /* File system object */
61
62 /* Internal File descriptor structure */
63 struct file_ds {
64 uint8_t scratch[SECTOR_SZ];
65 FIL fi;
66 struct fs_file fs;
67 int fi_valid;
68 };
69 static volatile int32_t sdio_wait_exit = 0;
70
71 /*****************************************************************************
72 * Public types/enumerations/variables
73 ****************************************************************************/
74 /* SDMMC card info structure */
75 mci_card_struct sdcardinfo;
76
77 /*****************************************************************************
78 * Private functions
79 ****************************************************************************/
80
81 #ifdef OS_FREE_RTOS
82 #include "FreeRTOS.h"
83 #include "semphr.h"
84 static xSemaphoreHandle open_lock;
85 /* FreeRTOS mutex lock */
86 static int mutex_lock(xSemaphoreHandle *mx)
87 {
88 if (xSemaphoreTake(*mx, 500) != pdTRUE) {
89 return 1;
90 }
91 return 0;
92 }
93
94 /* FreeRTOS mutex unlock */
95 static void mutex_unlock(xSemaphoreHandle *mx)
96 {
97 xSemaphoreGive(*mx);
98 }
99
100 /* FreeRTOS mutex init */
101 static int mutex_init(void)
102 {
103 open_lock = xSemaphoreCreateMutex();
104 return open_lock == NULL;
105 }
106
107 #elif defined(OS_UCOS_III)
108
109 #include "os.h"
110 #include "cpu.h"
111 #include "os_cfg_app.h"
112
113 static OS_MUTEX *open_lock;
114
115 /* mutex lock function for ucos-iii */
116 static int mutex_lock(OS_MUTEX **mx)
117 {
118 CPU_TS ts;
119 OS_ERR os_err;
120 OSMutexPend(*mx, 500, OS_OPT_PEND_BLOCKING, &ts, &os_err);
121 if (os_err != OS_ERR_NONE) {
122 return 1;
123 }
124
125 return 0;
126 }
127
128 /* Mutex unlock function for ucos-iii */
129 static void mutex_unlock(OS_MUTEX **mx)
130 {
131 OS_ERR os_err;
132 OSMutexPost(*mx, OS_OPT_POST_NONE, &os_err);
133 }
134
135 /* Mutex init function for ucos-iii */
136 static int mutex_init(void)
137 {
138 static OS_MUTEX fsmutex;
139 OS_ERR os_err;
140 OSMutexCreate(&fsmutex, "DOS_FS_Mutex", &os_err);
141 if (os_err == OS_ERR_NONE) {
142 open_lock = &fsmutex;
143 return 0;
144 }
145 else {
146 return 1;
147 }
148 }
149
150 #else
151 static int open_lock;
152 /* Mutex lock function for standalone */
153 static int mutex_lock(int *mx)
154 {
155 return 0;
156 }
157
158 /* Mutex init for standalone */
159 static int mutex_init(void)
160 {
161 open_lock = 1;
162 return 0;
163 }
164
165 /* Mutex lock for standalone */
166 static void mutex_unlock(int *mx)
167 {}
168
169 #endif
170
175 static int
176 get_http_headers(const char *fName, char *buff)
177 {
178 unsigned int iLoop;
179 const char *pszExt = NULL;
180 const char *hdrs[4];
181
182 /* Ensure that we initialize the loop counter. */
183 iLoop = 0;
184
185 /* In all cases, the second header we send is the server identification
186 so set it here. */
187 hdrs[1] = g_psHTTPHeaderStrings[HTTP_HDR_SERVER];
188
189 /* Is this a normal file or the special case we use to send back the
190 default "404: Page not found" response? */
191 if (( fName == NULL) || ( *fName == 0) ) {
192 hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND];
193 hdrs[2] = g_psHTTPHeaderStrings[DEFAULT_404_HTML];
194 goto end_fn;
195 }
196 /* We are dealing with a particular filename. Look for one other
197 special case. We assume that any filename with "404" in it must be
198 indicative of a 404 server error whereas all other files require
199 the 200 OK header. */
200 if (strstr(fName, "404")) {
201 iLoop = HTTP_HDR_NOT_FOUND;
202 }
203 else if (strstr(fName, "400")) {
204 iLoop = HTTP_HDR_BAD_REQUEST;
205 }
206 else if (strstr(fName, "501")) {
207 iLoop = HTTP_HDR_NOT_IMPL;
208 }
209 else {
210 iLoop = HTTP_HDR_OK;
211 }
212 hdrs[0] = g_psHTTPHeaderStrings[iLoop];
213
214 /* Get a pointer to the file extension. We find this by looking for the
215 last occurrence of "." in the filename passed. */
216 pszExt = strrchr(fName, '.');
217
218 /* Does the FileName passed have any file extension? If not, we assume it
219 is a special-case URL used for control state notification and we do
220 not send any HTTP headers with the response. */
221 if (pszExt == NULL) {
222 return 0;
223 }
224
225 pszExt++;
226 /* Now determine the content type and add the relevant header for that. */
227 for (iLoop = 0; (iLoop < NUM_HTTP_HEADERS); iLoop++)
228 /* Have we found a matching extension? */
229 if (!strcmp(g_psHTTPHeaders[iLoop].extension, pszExt)) {
230 hdrs[2] =
231 g_psHTTPHeaderStrings[g_psHTTPHeaders[iLoop].headerIndex];
232 break;
233 }
234
235 /* Did we find a matching extension? */
236 if (iLoop == NUM_HTTP_HEADERS) {
237 /* No - use the default, plain text file type. */
238 hdrs[2] = g_psHTTPHeaderStrings[HTTP_HDR_DEFAULT_TYPE];
239 }
240
241 end_fn:
242 iLoop = strlen(hdrs[0]);
243 strcpy(buff, hdrs[0]);
244 strcat(buff, hdrs[1]);
245 strcat(buff, hdrs[2]);
246 return strlen(buff);
247 }
248 /* Delay callback for timed SDIF/SDMMC functions */
249 static void sdmmc_waitms(uint32_t time)
250 {
251 /* In an RTOS, the thread would sleep allowing other threads to run.
252 For standalone operation, we just spin on RI timer */
253 int32_t curr = (int32_t) Chip_RIT_GetCounter(LPC_RITIMER);
254 int32_t final = curr + ((SystemCoreClock / 1000) * time);
255
256 if (final == curr) return;
257
258 if ((final < 0) && (curr > 0)) {
259 while (Chip_RIT_GetCounter(LPC_RITIMER) < (uint32_t) final) {}
260 }
261 else {
262 while ((int32_t) Chip_RIT_GetCounter(LPC_RITIMER) < final) {}
263 }
264
265 return;
266 }
267
273 static void sdmmc_setup_wakeup(void *bits)
274 {
275 uint32_t bit_mask = *((uint32_t *)bits);
276 /* Wait for IRQ - for an RTOS, you would pend on an event here with a IRQ based wakeup. */
277 NVIC_ClearPendingIRQ(SDIO_IRQn);
278 sdio_wait_exit = 0;
279 Chip_SDIF_SetIntMask(LPC_SDMMC, bit_mask);
280 NVIC_EnableIRQ(SDIO_IRQn);
281 }
282
287 static uint32_t sdmmc_irq_driven_wait(void)
288 {
289 uint32_t status;
290
291 /* Wait for event, would be nice to have a timeout, but keep it simple */
292 while (sdio_wait_exit == 0) {}
293
294 /* Get status and clear interrupts */
295 status = Chip_SDIF_GetIntStatus(LPC_SDMMC);
296
297 return status;
298 }
299
300 /* Initialize SD/MMC */
301 static void App_SDMMC_Init()
302 {
303 memset(&sdcardinfo, 0, sizeof(sdcardinfo));
304 sdcardinfo.card_info.evsetup_cb = sdmmc_setup_wakeup;
305 sdcardinfo.card_info.waitfunc_cb = sdmmc_irq_driven_wait;
306 sdcardinfo.card_info.msdelay_func = sdmmc_waitms;
307
308 /* SD/MMC initialization */
309 Board_SDMMC_Init();
310
311 /* The SDIO driver needs to know the SDIO clock rate */
312 Chip_SDIF_Init(LPC_SDMMC);
313 }
314
315 /*****************************************************************************
316 * Public functions
317 ****************************************************************************/
318
319 /* Read http header information into a string */
320 int GetHTTP_Header(const char *fName, char *buff)
321 {
322 return get_http_headers(fName, buff);
323 }
324
325 /* Initialize the file system */
326 int fs_init(void)
327 {
328 void rtc_initialize(void);
329 App_SDMMC_Init();
330 rtc_initialize();
331
332 NVIC_DisableIRQ(SDIO_IRQn);
333 /* Enable SD/MMC Interrupt */
334 NVIC_EnableIRQ(SDIO_IRQn);
335
336 f_mount(0, &Fatfs); /* Register volume work area (never fails) */
337
338 /* Initialize the mutex if not done already */
339 if (mutex_init()) {
340 LWIP_DEBUGF(HTTPD_DEBUG, ("DFS: ERROR: Mutex Init!\r\n"));
341 return 1;
342 }
343 return 0;
344 }
345
346 /* Opens the default index html file */
347 struct fs_file *fs_open_default(void) {
348 int hlen;
349
350 struct file_ds *fds;
351
352 struct fs_file *fs;
353
354 fds = (struct file_ds *)mem_malloc(sizeof(*fds));
355 if (fds == NULL) {
356 DEBUGSTR("Malloc Failure, Out of Memory!\r\n");
357 return NULL;
358 }
359 memset(fds, 0, sizeof(*fds));
360 fs = &fds->fs;
361 fs->pextension = (void *) fds; /* Store this for later use */
362 hlen = get_http_headers("default.htm", (char *) fds->scratch);
363 fs->data = (const char *) fds->scratch;
364 memcpy((void *) &fs->data[hlen], (void *) http_index_html, sizeof(http_index_html) - 1);
365 fs->len = hlen + sizeof(http_index_html) - 1;
366 fs->index = fs->len;
367 fs->http_header_included = 1;
368 return fs;
369 }
370
371 /* File open function */
372 struct fs_file *fs_open(const char *name) {
373 FRESULT res;
374 int hlen;
375 struct file_ds *fds;
376 struct fs_file *fs;
377
378 /* Too huge to keep in stack, must be protected with mutex */
379 static struct file_ds tmpds;
380
381 if (mutex_lock(&open_lock)) {
382 LWIP_DEBUGF(HTTPD_DEBUG, ("DFS: ERROR: Mutex Timeout!\r\n"));
383 return NULL;
384 }
385 memset(&tmpds, 0, sizeof(tmpds));
386 fds = &tmpds;
387
388 res = f_open(&fds->fi, name, FA_READ);
389 if (res) {
390 LWIP_DEBUGF(HTTPD_DEBUG, ("DFS: OPEN: File %s does not exist\r\n", name));
391 mutex_unlock(&open_lock);
392 return NULL;
393 }
394
395 fds = (struct file_ds *)mem_malloc(sizeof(*fds));
396 if (fds == NULL) {
397 DEBUGSTR("Malloc Failure, Out of Memory!\r\n");
398 mutex_unlock(&open_lock);
399 return NULL;
400 }
401 memcpy(fds, &tmpds, sizeof(*fds));
402 mutex_unlock(&open_lock);
403
404 fs = &fds->fs;
405 fds->fi_valid = 1;
406 fs->pextension = (void *) fds; /* Store this for later use */
407 hlen = get_http_headers(name, (char *) fds->scratch);
408 fs->data = (const char *) fds->scratch;
409 fs->index = hlen;
410 fs->len = f_size(&fds->fi) + hlen;
411 fs->http_header_included = 1;
412
413 return fs;
414 }
415
416 /* File close function */
417 void fs_close(struct fs_file *file)
418 {
419 struct file_ds *fds;
420
421 if(file == NULL)
422 return;
423
424 fds = (struct file_ds *) file->pextension;
425
426 #ifndef BOARD_HITEX_EVA_18504350
427 if (fds->fi_valid)
428 f_close(&fds->fi);
429 #endif
430
431 mem_free(fds);
432 }
433
434 /* File read function */
435 int fs_read(struct fs_file *file, char *buffer, int count)
436 {
437 uint32_t i = 0;
438 struct file_ds *fds = (struct file_ds *) file->pextension;
439 if (f_read(&fds->fi, (uint8_t *) buffer, count, &i))
440 return 0; /* Error in reading file */
441 file->index += i;
442 return i;
443 }
444
445 /* Number of bytes left in the file */
446 int fs_bytes_left(struct fs_file *file)
447 {
448 return file->len - file->index;
449 }
450
455 void SDIO_IRQHandler(void)
456 {
457 /* All SD based register handling is done in the callback
458 function. The SDIO interrupt is not enabled as part of this
459 driver and needs to be enabled/disabled in the callbacks or
460 application as needed. This is to allow flexibility with IRQ
461 handling for applicaitons and RTOSes. */
462 /* Set wait exit flag to tell wait function we are ready. In an RTOS,
463 this would trigger wakeup of a thread waiting for the IRQ. */
464 NVIC_DisableIRQ(SDIO_IRQn);
465 sdio_wait_exit = 1;
466 }
467
468
469 #ifdef LWIP_DEBUG
470 #if 0
471 /* Assert print function */
472 void assert_printf(char *msg, int line, char *file)
473 {
474 DEBUGOUT("ASSERT: %s at %s:%d\r\n", msg, file, line);
475 }
476 #endif
477
478 /* LWIP str err function */
479 const char *lwip_strerr(err_t eno)
480 {
481 return "";
482 }
483
484 #endif
485