vtx: fix VTX_SETTINGS_POWER_COUNT and add dummy entries to saPowerNames
[inav.git] / src / main / msc / emfat.c
blob44f7ee7d12896da04193c3233cabd5ea25f64244
1 /*
2 * Derived from
3 * https://github.com/fetisov/emfat/blob/master/project/emfat.c
4 * version: 1.1 (2.04.2017)
5 */
7 /*
8 * The MIT License (MIT)
10 * Copyright (c) 2015 by Sergey Fetisov <fsenok@gmail.com>
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this software and associated documentation files (the "Software"), to deal
14 * in the Software without restriction, including without limitation the rights
15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 * copies of the Software, and to permit persons to whom the Software is
17 * furnished to do so, subject to the following conditions:
19 * The above copyright notice and this permission notice shall be included in all
20 * copies or substantial portions of the Software.
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 * SOFTWARE.
31 #include "common/utils.h"
33 #include "emfat.h"
35 #ifdef __cplusplus
36 extern "C" {
37 #endif
39 #define SECT 512
40 #define CLUST 4096
41 #define SECT_PER_CLUST (CLUST / SECT)
42 #define SIZE_TO_NSECT(s) ((s) == 0 ? 1 : ((s) + SECT - 1) / SECT)
43 #define SIZE_TO_NCLUST(s) ((s) == 0 ? 1 : ((s) + CLUST - 1) / CLUST)
45 #define CLUST_FREE 0x00000000
46 #define CLUST_RESERVED 0x00000001
47 #define CLUST_BAD 0x0FFFFFF7
48 #define CLUST_ROOT_END 0X0FFFFFF8
49 #define CLUST_EOF 0x0FFFFFFF
51 #define MAX_DIR_ENTRY_CNT 16
52 #define FILE_SYS_TYPE_OFF 82
53 #define BYTES_PER_SEC_OFF 11
54 #define SEC_PER_CLUS_OFF 13
55 #define RES_SEC_CNT_OFF 14
56 #define FAT_CNT_OFF 16
57 #define TOT_SEC_CNT_OFF 32
58 #define SEC_PER_FAT 36
59 #define ROOT_DIR_STRT_CLUS_OFF 44
60 #define FS_INFOSECTOR_OFF 48
61 #define BACKUP_BOOT_SEC_OFF 50
62 #define NXT_FREE_CLUS_OFF 492
63 #define FILE_SYS_TYPE_LENGTH 8
64 #define SHRT_FILE_NAME_LEN 11
65 #define STRT_CLUS_LOW_OFF 26
66 #define STRT_CLUS_HIGH_OFF 20
67 #define FILE_SIZE_OFF 28
68 #define ATTR_OFF 11
69 #define FILE_STAT_LEN 21
70 #define CHECK_SUM_OFF 13
71 #define FILE_NAME_SHRT_LEN 8
72 #define FILE_NAME_EXTN_LEN 3
73 #define LONG_FILE_NAME_LEN 255
74 #define LOW_CLUSWORD_MASK 0x0000FFFF
75 #define HIGH_CLUSWORD_MASK 0xFFFF0000
76 #define LONG_FNAME_MASK 0x0F
77 #define LAST_ORD_FIELD_SEQ 0x40
78 #define LFN_END_MARK 0xFFFF
79 #define LFN_TERM_MARK 0x0000
80 #define LFN_FIRST_OFF 0x01
81 #define LFN_SIXTH_OFF 0x0E
82 #define LFN_TWELVETH_OFF 0x1C
83 #define LFN_FIRST_SET_CNT 5
84 #define LFN_SEC_SET_CNT 6
85 #define LFN_THIRD_SET_CNT 2
86 #define LFN_FIRST_SET_LEN 10
87 #define LFN_SEC_SET_LEN 12
88 #define LFN_THIRD_SET_LEN 4
89 #define LFN_EMPTY_LEN 2
90 #define LFN_LEN_PER_ENTRY 13
91 #define FNAME_EXTN_SEP_OFF 6
92 #define FNAME_SEQ_NUM_OFF 7
93 #define BYTES_PER_CLUSTER_ENTRY 4
94 #define DIR_ENTRY_LEN 32
95 #define VOL_ID_LEN 4
96 #define VOL_LABEL_LEN 11
97 #define RESERV_LEN 12
98 #define FS_VER_LEN 2
99 #define OEM_NAME_LEN 8
100 #define JUMP_INS_LEN 3
101 #define MAX_FAT_CNT 2
102 #define SPACE_VAL 32
103 #define FILE_READ 0x01
104 #define FILE_WRITE 0X02
105 #define FILE_CREATE_NEW 0x04
106 #define FILE_CREATE_ALWAYS 0x08
107 #define FILE_APPEND 0x10
108 #define FREE_DIR_ENTRY 0x00
109 #define DEL_DIR_ENTRY 0xE5
110 #define DOT_DIR_ENTRY 0x2E
111 #define ASCII_DIFF 32
112 #define FILE_SEEK_SET 0
113 #define FILE_SEEK_CUR 1
114 #define FILE_SEEK_END 2
115 #define DELIMITER '/'
116 #define EXTN_DELIMITER '.'
117 #define TILDE '~'
118 #define FULL_SHRT_NAME_LEN 13
120 #pragma pack(push, 1)
122 typedef struct
124 uint8_t status; // 0x80 for bootable, 0x00 for not bootable, anything else for invalid
125 uint8_t start_head; // The head of the start
126 uint8_t start_sector; // (S | ((C >> 2) & 0xC0)) where S is the sector of the start and C is the cylinder of the start. Note that S is counted from one.
127 uint8_t start_cylinder; // (C & 0xFF) where C is the cylinder of the start
128 uint8_t PartType;
129 uint8_t end_head;
130 uint8_t end_sector;
131 uint8_t end_cylinder;
132 uint32_t StartLBA; // linear address of first sector in partition. Multiply by sector size (usually 512) for real offset
133 uint32_t EndLBA; // linear address of last sector in partition. Multiply by sector size (usually 512) for real offset
134 } mbr_part_t;
136 typedef struct
138 uint8_t Code[440];
139 uint32_t DiskSig; //This is optional
140 uint16_t Reserved; //Usually 0x0000
141 mbr_part_t PartTable[4];
142 uint8_t BootSignature[2]; //0x55 0xAA for bootable
143 } mbr_t;
145 typedef struct
147 uint8_t jump[JUMP_INS_LEN];
148 uint8_t OEM_name[OEM_NAME_LEN];
149 uint16_t bytes_per_sec;
150 uint8_t sec_per_clus;
151 uint16_t reserved_sec_cnt;
152 uint8_t fat_cnt;
153 uint16_t root_dir_max_cnt;
154 uint16_t tot_sectors;
155 uint8_t media_desc;
156 uint16_t sec_per_fat_fat16;
157 uint16_t sec_per_track;
158 uint16_t number_of_heads;
159 uint32_t hidden_sec_cnt;
160 uint32_t tol_sector_cnt;
161 uint32_t sectors_per_fat;
162 uint16_t ext_flags;
163 uint8_t fs_version[FS_VER_LEN];
164 uint32_t root_dir_strt_cluster;
165 uint16_t fs_info_sector;
166 uint16_t backup_boot_sector;
167 uint8_t reserved[RESERV_LEN];
168 uint8_t drive_number;
169 uint8_t reserved1;
170 uint8_t boot_sig;
171 uint8_t volume_id[VOL_ID_LEN];
172 uint8_t volume_label[VOL_LABEL_LEN];
173 uint8_t file_system_type[FILE_SYS_TYPE_LENGTH];
174 } boot_sector;
176 typedef struct
178 uint32_t signature1; /* 0x41615252L */
179 uint32_t reserved1[120]; /* Nothing as far as I can tell */
180 uint32_t signature2; /* 0x61417272L */
181 uint32_t free_clusters; /* Free cluster count. -1 if unknown */
182 uint32_t next_cluster; /* Most recently allocated cluster */
183 uint32_t reserved2[3];
184 uint32_t signature3;
185 } fsinfo_t;
187 typedef struct
189 uint8_t name[FILE_NAME_SHRT_LEN];
190 uint8_t extn[FILE_NAME_EXTN_LEN];
191 uint8_t attr;
192 uint8_t reserved;
193 uint8_t crt_time_tenth;
194 uint16_t crt_time;
195 uint16_t crt_date;
196 uint16_t lst_access_date;
197 uint16_t strt_clus_hword;
198 uint16_t lst_mod_time;
199 uint16_t lst_mod_date;
200 uint16_t strt_clus_lword;
201 uint32_t size;
202 } dir_entry;
204 typedef struct
206 uint8_t ord_field;
207 uint8_t fname0_4[LFN_FIRST_SET_LEN];
208 uint8_t flag;
209 uint8_t reserved;
210 uint8_t chksum;
211 uint8_t fname6_11[LFN_SEC_SET_LEN];
212 uint8_t empty[LFN_EMPTY_LEN];
213 uint8_t fname12_13[LFN_THIRD_SET_LEN];
214 } lfn_entry;
216 #pragma pack(pop)
218 bool emfat_init_entries(emfat_entry_t *entries)
220 emfat_entry_t *e;
221 int i, n;
223 e = &entries[0];
224 if (e->level != 0 || !e->dir || e->name == NULL) return false;
226 e->priv.top = NULL;
227 e->priv.next = NULL;
228 e->priv.sub = NULL;
229 e->priv.num_subentry = 0;
231 n = 0;
232 for (i = 1; entries[i].name != NULL; i++) {
233 entries[i].priv.top = NULL;
234 entries[i].priv.next = NULL;
235 entries[i].priv.sub = NULL;
236 entries[i].priv.num_subentry = 0;
237 if (entries[i].level == n - 1) {
238 if (n == 0) return false;
239 e = e->priv.top;
240 n--;
243 if (entries[i].level == n + 1) {
244 if (!e->dir) return false;
245 e->priv.sub = &entries[i];
246 entries[i].priv.top = e;
247 e = &entries[i];
248 n++;
249 continue;
252 if (entries[i].level == n) {
253 if (n == 0) return false;
254 e->priv.top->priv.num_subentry++;
255 entries[i].priv.top = e->priv.top;
256 e->priv.next = &entries[i];
257 e = &entries[i];
258 continue;
261 return false;
264 return true;
267 static void lba_to_chs(int lba, uint8_t *cl, uint8_t *ch, uint8_t *dh)
269 int cylinder, head, sector;
270 int sectors = 63;
271 int heads = 255;
272 int cylinders = 1024;
273 sector = lba % sectors + 1;
274 head = (lba / sectors) % heads;
275 cylinder = lba / (sectors * heads);
276 if (cylinder >= cylinders) {
277 *cl = *ch = *dh = 0xff;
278 return;
280 *cl = sector | ((cylinder & 0x300) >> 2);
281 *ch = cylinder & 0xFF;
282 *dh = head;
285 bool emfat_init(emfat_t *emfat, const char *label, emfat_entry_t *entries)
287 uint32_t sect_per_fat;
288 uint32_t clust;
289 uint32_t reserved_clust = 0;
290 emfat_entry_t *e;
291 int i;
293 if (emfat == NULL || label == NULL || entries == NULL) {
294 return false;
297 if (!emfat_init_entries(entries)) {
298 return false;
301 clust = 2;
302 for (i = 0; entries[i].name != NULL; i++) {
303 e = &entries[i];
304 if (e->dir) {
305 e->curr_size = 0;
306 e->max_size = 0;
307 e->priv.first_clust = clust;
308 e->priv.last_clust = clust + SIZE_TO_NCLUST(e->priv.num_subentry * sizeof(dir_entry)) - 1;
309 e->priv.last_reserved = e->priv.last_clust;
310 } else {
311 e->priv.first_clust = clust;
312 e->priv.last_clust = e->priv.first_clust + SIZE_TO_NCLUST(entries[i].curr_size) - 1;
313 e->priv.last_reserved = e->priv.first_clust + SIZE_TO_NCLUST(entries[i].max_size) - 1;
315 reserved_clust += e->priv.last_reserved - e->priv.last_clust;
316 clust = e->priv.last_reserved + 1;
318 clust -= 2;
320 emfat->vol_label = label;
321 emfat->priv.num_entries = i;
322 emfat->priv.boot_lba = 62;
323 emfat->priv.fsinfo_lba = emfat->priv.boot_lba + 1;
324 emfat->priv.fat1_lba = emfat->priv.fsinfo_lba + 1;
325 emfat->priv.num_clust = clust;
326 emfat->priv.free_clust = reserved_clust;
327 sect_per_fat = SIZE_TO_NSECT((uint64_t)emfat->priv.num_clust * 4);
328 emfat->priv.fat2_lba = emfat->priv.fat1_lba + sect_per_fat;
329 emfat->priv.root_lba = emfat->priv.fat2_lba + sect_per_fat;
330 emfat->priv.entries = entries;
331 emfat->priv.last_entry = entries;
332 emfat->disk_sectors = clust * SECT_PER_CLUST + emfat->priv.root_lba;
333 emfat->vol_size = (uint64_t)emfat->disk_sectors * SECT;
334 /* calc cyl number */
335 // i = ((emfat->disk_sectors + 63*255 - 1) / (63*255));
336 // emfat->disk_sectors = i * 63*255;
337 return true;
340 void read_mbr_sector(const emfat_t *emfat, uint8_t *sect)
342 mbr_t *mbr;
343 memset(sect, 0, SECT);
344 mbr = (mbr_t *)sect;
345 mbr->DiskSig = 0;
346 mbr->Reserved = 0;
347 mbr->PartTable[0].status = 0x80;
348 mbr->PartTable[0].PartType = 0x0C;
349 mbr->PartTable[0].StartLBA = emfat->priv.boot_lba;
350 mbr->PartTable[0].EndLBA = emfat->disk_sectors;
351 lba_to_chs(mbr->PartTable[0].StartLBA, &mbr->PartTable[0].start_sector, &mbr->PartTable[0].start_cylinder, &mbr->PartTable[0].start_head);
352 lba_to_chs(emfat->disk_sectors - 1, &mbr->PartTable[0].end_sector, &mbr->PartTable[0].end_cylinder, &mbr->PartTable[0].end_head);
353 mbr->BootSignature[0] = 0x55;
354 mbr->BootSignature[1] = 0xAA;
357 void read_boot_sector(const emfat_t *emfat, uint8_t *sect)
359 boot_sector *bs;
360 memset(sect, 0, SECT);
361 bs = (boot_sector *)sect;
362 bs->jump[0] = 0xEB;
363 bs->jump[1] = 0x58;
364 bs->jump[2] = 0x90;
365 memcpy(bs->OEM_name, "MSDOS5.0", 8);
366 bs->bytes_per_sec = SECT;
367 bs->sec_per_clus = 8; /* 4 kb per cluster */
368 bs->reserved_sec_cnt = 2; /* boot sector & fsinfo sector */
369 bs->fat_cnt = 2; /* two tables */
370 bs->root_dir_max_cnt = 0;
371 bs->tot_sectors = 0;
372 bs->media_desc = 0xF8;
373 bs->sec_per_fat_fat16 = 0;
374 bs->sec_per_track = 63;
375 bs->number_of_heads = 0xFF;
376 bs->hidden_sec_cnt = 62;
377 bs->tol_sector_cnt = emfat->disk_sectors - emfat->priv.boot_lba;
378 bs->sectors_per_fat = emfat->priv.fat2_lba - emfat->priv.fat1_lba;
379 bs->ext_flags = 0;
380 bs->fs_version[0] = 0;
381 bs->fs_version[1] = 0;
382 bs->root_dir_strt_cluster = 2;
383 bs->fs_info_sector = 1;
384 bs->backup_boot_sector = 0; /* not used */
385 bs->drive_number = 128;
386 bs->boot_sig = 0x29;
387 bs->volume_id[0] = 148;
388 bs->volume_id[1] = 14;
389 bs->volume_id[2] = 13;
390 bs->volume_id[3] = 8;
391 memcpy(bs->volume_label, "NO NAME ", VOL_LABEL_LEN);
392 memcpy(bs->file_system_type, "FAT32 ", FILE_SYS_TYPE_LENGTH);
393 sect[SECT - 2] = 0x55;
394 sect[SECT - 1] = 0xAA;
397 #define IS_CLUST_OF(clust, entry) ((clust) >= (entry)->priv.first_clust && (clust) <= (entry)->priv.last_reserved)
399 emfat_entry_t *find_entry(const emfat_t *emfat, uint32_t clust, emfat_entry_t *nearest)
401 if (nearest == NULL) {
402 nearest = emfat->priv.entries;
405 if (nearest->priv.first_clust > clust) {
406 while (nearest >= emfat->priv.entries) { // backward finding
407 if (IS_CLUST_OF(clust, nearest))
408 return nearest;
409 nearest--;
411 } else {
412 while (nearest->name != NULL) { // forward finding
413 if (IS_CLUST_OF(clust, nearest))
414 return nearest;
415 nearest++;
418 return NULL;
421 void read_fsinfo_sector(const emfat_t *emfat, uint8_t *sect)
423 UNUSED(emfat);
425 fsinfo_t *info = (fsinfo_t *)sect;
426 info->signature1 = 0x41615252L;
427 info->signature2 = 0x61417272L;
428 //info->free_clusters = 0;
429 info->free_clusters = emfat->priv.free_clust;
430 //info->next_cluster = emfat->priv.num_clust + 2;
431 info->next_cluster = 0xffffffff;
432 memset(info->reserved1, 0, sizeof(info->reserved1));
433 memset(info->reserved2, 0, sizeof(info->reserved2));
434 info->signature3 = 0xAA550000;
437 void read_fat_sector(emfat_t *emfat, uint8_t *sect, uint32_t index)
439 emfat_entry_t *le;
440 uint32_t *values;
441 uint32_t count;
442 uint32_t curr;
444 values = (uint32_t *)sect;
445 curr = index * 128;
446 count = 128;
448 if (curr == 0) {
449 *values++ = CLUST_ROOT_END;
450 *values++ = 0xFFFFFFFF;
451 count -= 2;
452 curr += 2;
455 le = emfat->priv.last_entry;
456 while (count != 0) {
457 if (!IS_CLUST_OF(curr, le)) {
458 le = find_entry(emfat, curr, le);
459 if (le == NULL) {
460 le = emfat->priv.last_entry;
461 *values = CLUST_RESERVED;
462 values++;
463 count--;
464 curr++;
465 continue;
468 if (le->dir) {
469 if (curr == le->priv.last_clust) {
470 *values = CLUST_EOF;
471 } else {
472 *values = curr + 1;
474 } else {
475 if (curr == le->priv.last_clust) {
476 *values = CLUST_EOF;
477 } else if (curr > le->priv.last_clust) {
478 *values = CLUST_FREE;
479 } else {
480 *values = curr + 1;
483 values++;
484 count--;
485 curr++;
487 emfat->priv.last_entry = le;
490 void fill_entry(dir_entry *entry, const char *name, uint8_t attr, uint32_t clust, const uint32_t cma[3], uint32_t size)
492 int i, l, l1, l2;
493 int dot_pos;
495 memset(entry, 0, sizeof(dir_entry));
497 if (cma) {
498 entry->crt_date = cma[0] >> 16;
499 entry->crt_time = cma[0] & 0xFFFF;
500 entry->lst_mod_date = cma[1] >> 16;
501 entry->lst_mod_time = cma[1] & 0xFFFF;
502 entry->lst_access_date = cma[2] >> 16;
505 l = strlen(name);
506 dot_pos = -1;
508 if ((attr & ATTR_DIR) == 0) {
509 for (i = l - 1; i >= 0; i--) {
510 if (name[i] == '.')
512 dot_pos = i;
513 break;
518 if (dot_pos == -1) {
519 l1 = l > FILE_NAME_SHRT_LEN ? FILE_NAME_SHRT_LEN : l;
520 l2 = 0;
521 } else {
522 l1 = dot_pos;
523 l1 = l1 > FILE_NAME_SHRT_LEN ? FILE_NAME_SHRT_LEN : l1;
524 l2 = l - dot_pos - 1;
525 l2 = l2 > FILE_NAME_EXTN_LEN ? FILE_NAME_EXTN_LEN : l2;
528 memset(entry->name, ' ', FILE_NAME_SHRT_LEN);
529 memcpy(entry->name, name, l1);
530 memset(entry->extn, ' ', FILE_NAME_EXTN_LEN);
531 memcpy(entry->extn, name + dot_pos + 1, l2);
533 for (i = 0; i < FILE_NAME_SHRT_LEN; i++) {
534 if (entry->name[i] >= 'a' && entry->name[i] <= 'z') {
535 entry->name[i] -= 0x20;
539 for (i = 0; i < FILE_NAME_EXTN_LEN; i++) {
540 if (entry->extn[i] >= 'a' && entry->extn[i] <= 'z') {
541 entry->extn[i] -= 0x20;
545 entry->attr = attr;
546 entry->reserved = 24;
547 entry->strt_clus_hword = clust >> 16;
548 entry->strt_clus_lword = clust;
549 entry->size = size;
551 return;
554 void fill_dir_sector(emfat_t *emfat, uint8_t *data, emfat_entry_t *entry, uint32_t rel_sect)
556 dir_entry *de;
557 uint32_t avail;
559 memset(data, 0, SECT);
560 de = (dir_entry *)data;
561 avail = SECT;
563 if (rel_sect == 0) { // 1. first sector of directory
564 if (entry->priv.top == NULL) {
565 fill_entry(de++, emfat->vol_label, ATTR_VOL_LABEL, 0, 0, 0);
566 avail -= sizeof(dir_entry);
567 } else {
568 fill_entry(de++, ".", ATTR_DIR | ATTR_READ, entry->priv.first_clust, 0, 0);
569 if (entry->priv.top->priv.top == NULL) {
570 fill_entry(de++, "..", ATTR_DIR | ATTR_READ, 0, 0, 0);
571 } else {
572 fill_entry(de++, "..", ATTR_DIR | ATTR_READ, entry->priv.top->priv.first_clust, 0, 0);
574 avail -= sizeof(dir_entry) * 2;
576 entry = entry->priv.sub;
577 } else { // 2. not a first sector
578 int n;
579 n = rel_sect * (SECT / sizeof(dir_entry));
580 n -= entry->priv.top == NULL ? 1 : 2;
581 entry = entry->priv.sub;
583 while (n > 0 && entry != NULL) {
584 entry = entry->priv.next;
585 n--;
589 while (entry != NULL && avail >= sizeof(dir_entry)) {
590 if (entry->dir) {
591 fill_entry(de++, entry->name, ATTR_DIR | ATTR_READ, entry->priv.first_clust, entry->cma_time, 0);
592 } else {
593 //fill_entry(de++, entry->name, ATTR_ARCHIVE | ATTR_READ, entry->priv.first_clust, entry->cma_time, entry->curr_size);
594 fill_entry(de++, entry->name, ATTR_ARCHIVE | ATTR_READ | entry->attr, entry->priv.first_clust, entry->cma_time, entry->curr_size);
596 entry = entry->priv.next;
597 avail -= sizeof(dir_entry);
601 void read_data_sector(emfat_t *emfat, uint8_t *data, uint32_t rel_sect)
603 emfat_entry_t *le;
604 uint32_t cluster;
605 cluster = rel_sect / 8 + 2;
606 rel_sect = rel_sect % 8;
608 le = emfat->priv.last_entry;
609 if (!IS_CLUST_OF(cluster, le)) {
610 le = find_entry(emfat, cluster, le);
611 if (le == NULL) {
612 int i;
613 for (i = 0; i < SECT / 4; i++)
614 ((uint32_t *)data)[i] = 0xEFBEADDE;
615 return;
617 emfat->priv.last_entry = le;
620 if (le->dir) {
621 fill_dir_sector(emfat, data, le, rel_sect);
622 return;
625 if (le->readcb == NULL) {
626 memset(data, 0, SECT);
627 } else {
628 uint32_t offset = cluster - le->priv.first_clust;
629 offset = offset * CLUST + rel_sect * SECT;
630 le->readcb(data, SECT, offset + le->offset, le);
633 return;
636 void emfat_read(emfat_t *emfat, uint8_t *data, uint32_t sector, int num_sectors)
638 while (num_sectors > 0) {
639 if (sector >= emfat->priv.root_lba) {
640 read_data_sector(emfat, data, sector - emfat->priv.root_lba);
641 } else if (sector == 0) {
642 read_mbr_sector(emfat, data);
643 } else if (sector == emfat->priv.fsinfo_lba) {
644 read_fsinfo_sector(emfat, data);
645 } else if (sector == emfat->priv.boot_lba) {
646 read_boot_sector(emfat, data);
647 } else if (sector >= emfat->priv.fat1_lba && sector < emfat->priv.fat2_lba) {
648 read_fat_sector(emfat, data, sector - emfat->priv.fat1_lba);
649 } else if (sector >= emfat->priv.fat2_lba && sector < emfat->priv.root_lba) {
650 read_fat_sector(emfat, data, sector - emfat->priv.fat2_lba);
651 } else {
652 memset(data, 0, SECT);
654 data += SECT;
655 num_sectors--;
656 sector++;
660 void write_data_sector(emfat_t *emfat, const uint8_t *data, uint32_t rel_sect)
662 emfat_entry_t *le;
663 uint32_t cluster;
664 cluster = rel_sect / 8 + 2;
665 rel_sect = rel_sect % 8;
667 le = emfat->priv.last_entry;
669 if (!IS_CLUST_OF(cluster, le)) {
670 le = find_entry(emfat, cluster, le);
671 if (le == NULL) return;
672 emfat->priv.last_entry = le;
675 if (le->dir) {
676 // TODO: handle changing a filesize
677 return;
680 if (le->writecb != NULL) {
681 le->writecb(data, SECT, rel_sect * SECT + le->offset, le);
685 #define FEBRUARY 2
686 #define STARTOFTIME 1970
687 #define SECDAY 86400L
688 #define SECYR (SECDAY * 365)
689 #define leapyear(year) ((year) % 4 == 0)
690 #define days_in_year(a) (leapyear(a) ? 366 : 365)
691 #define days_in_month(a) (month_days[(a) - 1])
693 static int month_days[12] = {
694 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
697 uint32_t emfat_cma_time_from_unix(uint32_t tim)
699 register int i;
700 register long tmp, day;
701 int ymd[3];
702 int hms[3];
704 day = tim / SECDAY;
705 tmp = tim % SECDAY;
707 /* Hours, minutes, seconds are easy */
709 hms[0] = tmp / 3600;
710 hms[1] = (tmp % 3600) / 60;
711 hms[2] = (tmp % 3600) % 60;
713 /* Number of years in days */
714 for (i = STARTOFTIME; day >= days_in_year(i); i++)
715 day -= days_in_year(i);
716 ymd[0] = i;
718 /* Number of months in days left */
719 if (leapyear(ymd[0])) {
720 days_in_month(FEBRUARY) = 29;
722 for (i = 1; day >= days_in_month(i); i++) {
723 day -= days_in_month(i);
725 days_in_month(FEBRUARY) = 28;
726 ymd[1] = i;
728 /* Days are what is left over (+1) from all that. */
729 ymd[2] = day + 1;
731 return EMFAT_ENCODE_CMA_TIME(ymd[2], ymd[1], ymd[0], hms[0], hms[1], hms[2]);
734 #ifdef __cplusplus
736 #endif