mirror of
https://github.com/oliverschmidt/contiki.git
synced 2024-12-22 10:30:13 +00:00
360 lines
7.3 KiB
C
360 lines
7.3 KiB
C
#include <stm32f10x_map.h>
|
|
#include <sdcard.h>
|
|
#include <sys/process.h>
|
|
#include <sys/etimer.h>
|
|
#include <cfs/cfs.h>
|
|
#include <efs.h>
|
|
#include <ls.h>
|
|
#include <interfaces/sd.h>
|
|
#include <gpio.h>
|
|
#include <stdio.h>
|
|
|
|
process_event_t sdcard_inserted_event;
|
|
|
|
process_event_t sdcard_removed_event;
|
|
|
|
static struct process *event_process = NULL;
|
|
|
|
#if 0
|
|
#undef TXT
|
|
#define TXT(x) x
|
|
#undef DBG
|
|
#define DBG(x) printf x
|
|
#endif
|
|
|
|
static void
|
|
init_spi()
|
|
{
|
|
SPI1->CR1 &= ~SPI_CR1_SPE;
|
|
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
|
|
GPIO_CONF_INPUT_PORT(A,0,FLOATING);
|
|
GPIO_CONF_INPUT_PORT(A,1,FLOATING);
|
|
GPIO_CONF_OUTPUT_PORT(A,4,PUSH_PULL,50);
|
|
GPIOA->BSRR = GPIO_BSRR_BS4;
|
|
GPIO_CONF_OUTPUT_PORT(A,5,ALT_PUSH_PULL,50);
|
|
GPIO_CONF_INPUT_PORT(A,6,FLOATING);
|
|
GPIO_CONF_OUTPUT_PORT(A,7,ALT_PUSH_PULL,50);
|
|
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
|
|
SPI1->CR2 = SPI_CR2_SSOE;
|
|
SPI1->CR1 = (SPI_CR1_SPE
|
|
| (SPI_CR1_BR_2) /* fPCLK / 32 */
|
|
| SPI_CR1_MSTR
|
|
| SPI_CR1_CPOL | SPI_CR1_CPHA
|
|
| SPI_CR1_SSM | SPI_CR1_SSI);
|
|
|
|
}
|
|
|
|
void
|
|
if_spiInit(hwInterface *iface)
|
|
{
|
|
unsigned int i;
|
|
GPIOA->BSRR = GPIO_BSRR_BS4;
|
|
for(i=0;i<20;i++) {
|
|
if_spiSend(iface, 0xff);
|
|
}
|
|
GPIOA->BSRR = GPIO_BSRR_BR4;
|
|
}
|
|
/* Borrowed from at91_spi.c (c)2006 Martin Thomas */
|
|
|
|
esint8
|
|
if_initInterface(hwInterface* file, eint8* opts)
|
|
{
|
|
euint32 sc;
|
|
if_spiInit(file);
|
|
if(sd_Init(file)<0) {
|
|
DBG((TXT("Card failed to init, breaking up...\n")));
|
|
return(-1);
|
|
}
|
|
|
|
if(sd_State(file)<0){
|
|
DBG((TXT("Card didn't return the ready state, breaking up...\n")
|
|
));
|
|
return(-2);
|
|
}
|
|
|
|
|
|
|
|
sd_getDriveSize(file, &sc);
|
|
file->sectorCount = sc/512;
|
|
DBG((TXT("Card Capacity is %lu Bytes (%lu Sectors)\n"), sc, file->sectorCount));
|
|
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* Borrowed from lpc2000_spi.c (c)2005 Martin Thomas */
|
|
|
|
esint8
|
|
if_readBuf(hwInterface* file,euint32 address,euint8* buf)
|
|
{
|
|
return(sd_readSector(file,address,buf,512));
|
|
}
|
|
|
|
esint8
|
|
if_writeBuf(hwInterface* file,euint32 address,euint8* buf)
|
|
{
|
|
return(sd_writeSector(file,address, buf));
|
|
}
|
|
|
|
esint8
|
|
if_setPos(hwInterface* file,euint32 address)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
|
|
euint8
|
|
if_spiSend(hwInterface *iface, euint8 outgoing)
|
|
{
|
|
euint8 ingoing;
|
|
SPI1->DR = outgoing;
|
|
while(!(SPI1->SR & SPI_SR_RXNE));
|
|
ingoing = SPI1->DR;
|
|
/* printf(">%02x <%02x\n", outgoing, ingoing); */
|
|
return ingoing;
|
|
}
|
|
|
|
#define MAX_FDS 4
|
|
|
|
static EmbeddedFileSystem sdcard_efs;
|
|
static File file_descriptors[MAX_FDS];
|
|
|
|
static int
|
|
find_free_fd()
|
|
{
|
|
int fd;
|
|
for (fd = 0; fd < MAX_FDS; fd++) {
|
|
if (!file_getAttr(&file_descriptors[fd], FILE_STATUS_OPEN)) {
|
|
return fd;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static File *
|
|
get_file(int fd)
|
|
{
|
|
if (sdcard_efs.myCard.sectorCount == 0) return NULL;
|
|
if (fd >= MAX_FDS || fd < 0) return NULL;
|
|
if (!file_getAttr(&file_descriptors[fd], FILE_STATUS_OPEN)) return NULL;
|
|
return &file_descriptors[fd];
|
|
}
|
|
|
|
int
|
|
cfs_open (const char *name, int flags)
|
|
{
|
|
eint8 mode;
|
|
int fd;
|
|
if (sdcard_efs.myCard.sectorCount == 0) return -1;
|
|
fd = find_free_fd();
|
|
if (fd < 0) return -1;
|
|
if (flags == CFS_READ) {
|
|
mode = MODE_READ;
|
|
} else {
|
|
mode = MODE_APPEND;
|
|
}
|
|
if (file_fopen(&file_descriptors[fd], &sdcard_efs.myFs,
|
|
(char*)name, mode) < 0) {
|
|
return -1;
|
|
}
|
|
return fd;
|
|
}
|
|
|
|
void
|
|
cfs_close(int fd)
|
|
{
|
|
File *file = get_file(fd);
|
|
if (!file) return;
|
|
file_fclose(file);
|
|
fs_flushFs(&sdcard_efs.myFs);
|
|
}
|
|
|
|
int
|
|
cfs_read (int fd, void *buf, unsigned int len)
|
|
{
|
|
File *file = get_file(fd);
|
|
if (!file) return 0;
|
|
return file_read(file, len, (euint8*)buf);
|
|
}
|
|
|
|
int
|
|
cfs_write (int fd, const void *buf, unsigned int len)
|
|
{
|
|
File *file = get_file(fd);
|
|
if (!file) return 0;
|
|
return file_write(file, len, (euint8*)buf);
|
|
}
|
|
|
|
cfs_offset_t
|
|
cfs_seek (int fd, cfs_offset_t offset, int whence)
|
|
{
|
|
File *file = get_file(fd);
|
|
if (!file) return 0;
|
|
/* TODO take whence int account */
|
|
if (file_setpos(file, offset) != 0) return -1;
|
|
return file->FilePtr;
|
|
}
|
|
|
|
int
|
|
cfs_remove(const char *name)
|
|
{
|
|
return (rmfile(&sdcard_efs.myFs,(euint8*)name) == 0) ? 0 : -1;
|
|
}
|
|
|
|
/* Cause a compile time error if expr is false */
|
|
#ifdef __GNUC__
|
|
#define COMPILE_TIME_CHECK(expr) \
|
|
(void) (__builtin_choose_expr ((expr), 0, ((void)0))+3)
|
|
#else
|
|
#define COMPILE_TIME_CHECK(expr)
|
|
#endif
|
|
|
|
#define MAX_DIR_LISTS 4
|
|
DirList dir_lists[MAX_DIR_LISTS];
|
|
|
|
static DirList *
|
|
find_free_dir_list()
|
|
{
|
|
unsigned int l;
|
|
for(l = 0; l < MAX_DIR_LISTS; l++) {
|
|
if (dir_lists[l].fs == NULL) {
|
|
return &dir_lists[l];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
cfs_opendir (struct cfs_dir *dirp, const char *name)
|
|
{
|
|
DirList *dirs;
|
|
COMPILE_TIME_CHECK(sizeof(DirList*) <= sizeof(struct cfs_dir));
|
|
if (sdcard_efs.myCard.sectorCount == 0) return -1;
|
|
dirs = find_free_dir_list();
|
|
if (!dirs) return -1;
|
|
if (ls_openDir(dirs, &sdcard_efs.myFs, (eint8*)name) != 0) {
|
|
dirs->fs = NULL;
|
|
return -1;
|
|
}
|
|
*(DirList**)dirp = dirs;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
cfs_readdir (struct cfs_dir *dirp, struct cfs_dirent *dirent)
|
|
{
|
|
euint8 *start;
|
|
euint8 *end;
|
|
char *to = dirent->name;
|
|
DirList *dirs = *(DirList**)dirp;
|
|
if (sdcard_efs.myCard.sectorCount == 0) return 1;
|
|
if (ls_getNext(dirs) != 0) return 1;
|
|
start = dirs->currentEntry.FileName;
|
|
end = start + 7;
|
|
while(end > start) {
|
|
if (*end > ' ') {
|
|
end++;
|
|
break;
|
|
}
|
|
end--;
|
|
}
|
|
while(start < end) {
|
|
*to++ = *start++;
|
|
}
|
|
start = dirs->currentEntry.FileName + 8;
|
|
end = start + 3;
|
|
if (*start > ' ') {
|
|
*to++ = '.';
|
|
*to++ = *start++;
|
|
while(start < end && *start > ' ') {
|
|
*to++ = *start++;
|
|
}
|
|
}
|
|
*to = '\0';
|
|
if (dirs->currentEntry.Attribute & ATTR_DIRECTORY) {
|
|
dirent->size = 0;
|
|
} else {
|
|
dirent->size = dirs->currentEntry.FileSize;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
cfs_closedir (struct cfs_dir *dirp)
|
|
{
|
|
(*(DirList**)dirp)->fs = NULL;
|
|
}
|
|
|
|
|
|
PROCESS(sdcard_process, "SD card process");
|
|
|
|
PROCESS_THREAD(sdcard_process, ev , data)
|
|
{
|
|
int fd;
|
|
static struct etimer timer;
|
|
PROCESS_BEGIN();
|
|
/* Mark all file descriptors as free */
|
|
for (fd = 0; fd < MAX_FDS; fd++) {
|
|
file_setAttr(&file_descriptors[fd], FILE_STATUS_OPEN,0);
|
|
}
|
|
/* Card not inserted */
|
|
sdcard_efs.myCard.sectorCount = 0;
|
|
init_spi();
|
|
|
|
etimer_set(&timer, CLOCK_SECOND);
|
|
while(1) {
|
|
PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_EXIT ||
|
|
ev== PROCESS_EVENT_TIMER || ev == PROCESS_EVENT_POLL);
|
|
if (ev == PROCESS_EVENT_EXIT) break;
|
|
if (ev == PROCESS_EVENT_TIMER) {
|
|
if (!(GPIOA->IDR & (1<<0))) {
|
|
if (sdcard_efs.myCard.sectorCount == 0) {
|
|
etimer_set(&timer,CLOCK_SECOND/2);
|
|
PROCESS_WAIT_EVENT_UNTIL(ev== PROCESS_EVENT_TIMER);
|
|
if (efs_init(&sdcard_efs,0) == 0) {
|
|
if (event_process) {
|
|
process_post(event_process, sdcard_inserted_event, NULL);
|
|
}
|
|
printf("SD card inserted\n");
|
|
} else {
|
|
printf("SD card insertion failed\n");
|
|
}
|
|
}
|
|
} else {
|
|
if (sdcard_efs.myCard.sectorCount != 0) {
|
|
/* Card removed */
|
|
fs_umount(&sdcard_efs.myFs);
|
|
sdcard_efs.myCard.sectorCount = 0;
|
|
if (event_process) {
|
|
process_post(event_process, sdcard_removed_event, NULL);
|
|
}
|
|
printf("SD card removed\n");
|
|
}
|
|
}
|
|
etimer_set(&timer, CLOCK_SECOND);
|
|
|
|
}
|
|
}
|
|
PROCESS_END();
|
|
}
|
|
|
|
void
|
|
sdcard_init()
|
|
{
|
|
sdcard_inserted_event = process_alloc_event();
|
|
sdcard_removed_event = process_alloc_event();
|
|
process_start(&sdcard_process, NULL);
|
|
}
|
|
|
|
int
|
|
sdcard_ready()
|
|
{
|
|
return sdcard_efs.myCard.sectorCount > 0;
|
|
}
|
|
|
|
void
|
|
sdcard_event_process(struct process *p)
|
|
{
|
|
event_process = p;
|
|
}
|