forked from fossasia/pslab-firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsdcard.c
More file actions
143 lines (116 loc) · 3.8 KB
/
Copy pathsdcard.c
File metadata and controls
143 lines (116 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "../bus/uart/uart.h"
#include "../commands.h"
#include "../helpers/debug.h"
#include "../registers/system/watchdog.h"
#include "fatfs/ff.h"
#include "fatfs/ffconf.h"
#include "sd_spi.h"
#define SFN_MAX 8
#define SFN_SUFFIX_LEN 4 // Period + at most three chars.
#define BUF_MAX FF_MIN_SS
#define SDCARD_DRIVE "0:"
static TCHAR s_sector_buf[BUF_MAX];
_Static_assert(
sizeof(s_sector_buf) == 512,
"SD sector buffer must be 512 bytes"
);
static void get_filename(TCHAR *const fn_buf, UINT const size)
{
for (UINT i = 0; i < size; ++i) {
if (!(fn_buf[i] = UART1_Read())) {
// Received null-terminator.
return;
}
}
// FatFS handles non-terminated strings gracefully, so no need to do a
// manual check for null-termination.
}
response_t SDCARD_write_file(void)
{
// +1 is null-terminator.
size_t const filename_size = SFN_MAX + SFN_SUFFIX_LEN + 1;
TCHAR filename[filename_size];
get_filename(filename, filename_size);
BYTE const mode = UART1_Read();
if (!SD_SPI_IsMediaPresent()) {
UART1_Write(FR_NOT_READY);
return DO_NOT_BOTHER;
}
FATFS drive;
DEBUG_write_u8(f_mount(&drive, SDCARD_DRIVE, 1));
FIL file;
// Host must wait for f_open before sending data.
UART1_Write(f_open(&file, filename, FA_WRITE | mode));
FSIZE_t data_size = UART1_read_u32();
FSIZE_t bytes_written = 0;
for (FSIZE_t block_size, remaining = data_size;
block_size = remaining > BUF_MAX ? BUF_MAX : remaining, remaining;
remaining -= block_size) {
for (UINT i = 0; i < block_size; ++i) {
s_sector_buf[i] = UART1_Read();
}
WATCHDOG_TimerClear();
UINT written = 0;
// Host must wait for f_write before sending more data.
UART1_Write(f_write(&file, s_sector_buf, (UINT)block_size, &written));
bytes_written += written;
}
UART1_write_u32(bytes_written);
DEBUG_write_u8(f_close(&file));
DEBUG_write_u8(f_mount(0, SDCARD_DRIVE, 0));
return DO_NOT_BOTHER;
}
response_t SDCARD_read_file(void)
{
TCHAR filename[SFN_MAX + SFN_SUFFIX_LEN + 1]; // +1 is null-terminator.
get_filename(filename, sizeof filename);
if (!SD_SPI_IsMediaPresent()) {
UART1_Write(FR_NOT_READY);
return DO_NOT_BOTHER;
}
FATFS drive;
DEBUG_write_u8(f_mount(&drive, SDCARD_DRIVE, 1));
FIL file;
DEBUG_write_u8(f_open(&file, filename, FA_READ));
FILINFO info = {0, 0, 0, 0, {0}};
DEBUG_write_u8(f_stat(filename, &info));
UART1_write_u32(info.fsize);
FSIZE_t bytes_read = 0;
for (FSIZE_t block_size, remaining = info.fsize;
block_size = remaining > BUF_MAX ? BUF_MAX : remaining, remaining;
remaining -= block_size) {
WATCHDOG_TimerClear();
UINT read = 0;
f_read(&file, s_sector_buf, (UINT)block_size, &read);
bytes_read += read;
for (UINT i = 0; i < block_size; ++i) {
UART1_Write(s_sector_buf[i]);
}
}
UART1_write_u32(bytes_read);
DEBUG_write_u8(f_close(&file));
DEBUG_write_u8(f_mount(0, SDCARD_DRIVE, 0));
return DO_NOT_BOTHER;
}
response_t SDCARD_get_file_info(void)
{
TCHAR filename[SFN_MAX + SFN_SUFFIX_LEN + 1]; // +1 is null-terminator.
get_filename(filename, sizeof filename);
if (!SD_SPI_IsMediaPresent()) {
UART1_Write(FR_NOT_READY);
return DO_NOT_BOTHER;
}
FATFS drive;
DEBUG_write_u8(f_mount(&drive, SDCARD_DRIVE, 1));
FILINFO info = {0, 0, 0, 0, {0}};
DEBUG_write_u8(f_stat(filename, &info));
UART1_write_u32(info.fsize);
UART1_WriteInt(info.fdate);
UART1_WriteInt(info.ftime);
UART1_Write(info.fattrib);
DEBUG_write_u8(f_mount(0, SDCARD_DRIVE, 0));
return SUCCESS;
}