/FollowMe/Hex-Files/BootLoader_MEGA644p_20MHZ_V0_1.hex |
---|
0,0 → 1,64 |
:10F8000011241FBECFEFD0E1DEBFCDBF11E0A0E0DD |
:10F81000B1E0E0EEFBEF02C005900D92A030B10721 |
:10F82000D9F712E0A0E0B1E001C01D92A230B1070B |
:10F83000E1F70C943B7C0C941D7C0895982F8091EB |
:10F84000C00085FFFCCF9093C60008958091C00052 |
:10F850008823E4F78091C600992708958DE40E94DB |
:10F860001E7C8BE40E941E7C82E40E941E7C8CE441 |
:10F870000E941E7C0895CFEFD0E1DEBFCDBFE0E057 |
:10F88000F0E014915F01772474BE98E10FB6F8940C |
:10F8900090936000109260000FBE7092C5008AE2E3 |
:10F8A0008093C4008091C00082608093C0009093D8 |
:10F8B000C10086E08093C200EF01072D8091C00057 |
:10F8C00087FF0DC0013031F48091C6008A3AB1F152 |
:10F8D00000E005C08091C6008B3109F401E0CE0143 |
:10F8E00021968436910528F11F3F41F0112331F014 |
:10F8F000E0910001F091010109951BC01092C50033 |
:10F900008AE28093C4008AE00E941E7C8DE00E94FF |
:10F910001E7C86E50E941E7C80E30E941E7C8EE297 |
:10F920000E941E7C81E30E941E7C8AE30E941E7C52 |
:10F9300005C080E593EC0197F1F7C0CF0E942E7CC3 |
:10F940000E94267C813611F489E547C1813471F427 |
:10F950000E94267CA82EBB24BA2CAA240E94267CB6 |
:10F960009927A82AB92AB694A79406C1823629F401 |
:10F9700089E50E941E7C81E00BC1823409F083C0BE |
:10F980000E94267C9927D82FCC270E94267C992775 |
:10F99000C82BD92B0E94267C082F12E0812E11E063 |
:10F9A000912EEE24FF2464010894811C911CEC1616 |
:10F9B000FD0618F40E94267C01C08FEFD6018C93BF |
:10F9C0000894E11CF11CBFEFEB16F10461F358F34E |
:10F9D000E4E77E1609F0DEC0063409F03DC0FFEF13 |
:10F9E000AF16F7EFBF0608F033C0DE01A5016627AA |
:10F9F0007727440F551F661F771F6A017B01C2E0FE |
:10FA0000D1E001E08991992729913327322F2227CC |
:10FA1000822B932B0C01FA0100935700E8951124D7 |
:10FA20004E5F5F4F6F4F7F4F129761F785E0F60192 |
:10FA300080935700E89507B600FCFDCF81E18093E5 |
:10FA40005700E89576956795579547955A0194C064 |
:10FA500080E00E941E7C90C0053409F08DC0F50145 |
:10FA60009E01A2E0B1E0E1BD8F2F992782BD8D916B |
:10FA700080BD3196FA9AF99AF999FECF215030401B |
:10FA800091F75F0179C0873609F047C00E94267C54 |
:10FA90009927D82ECC240E94267C9927C82AD92AB7 |
:10FAA0000E94267C863411F5E6016501EE24FF24D0 |
:10FAB000CC0CDD1CEE1CFF1CF60105911491802F6F |
:10FAC0000E941E7C812F99270E941E7C82E090E07C |
:10FAD000A0E0B0E0C80ED91EEA1EFB1E229761F717 |
:10FAE000F694E794D794C79456012ACF853409F049 |
:10FAF00027CF7501E1BC8F2D992782BDF89A089414 |
:10FB0000E11CF11C80B50E941E7C0894C108D1083C |
:10FB1000C114D10479F7570113CF853601F594E765 |
:10FB2000791651F580E090E0A0E0B0E023E0FC0120 |
:10FB300020935700E89507B600FCFDCF80509F4FFB |
:10FB4000AF4FBF4F8F3FE7EF9E07E0E0AE07E0E02B |
:10FB5000BE0768F381E180935700E8950DC08534B6 |
:10FB600069F488E190E02CE00FB6F894A8958093B2 |
:10FB700060000FBE209360008DE02FC08035E1F360 |
:10FB80008C34D1F3803711F483E527C0843721F416 |
:10FB90000E941E7C80E021C0843521F40E94267CD6 |
:10FBA000782EEACF8B3109F4C9CE8A3A09F4C6CE51 |
:10FBB000863529F480E30E941E7C81E30EC08337E2 |
:10FBC00041F489E00E941E7C86E90E941E7C8EE141 |
:10FBD00004C08B3109F4B4CE8FE30E941E7CB0CEFA |
:040000030000F80001 |
:00000001FF |
/FollowMe/Hex-Files/Conrad LEA-4H Config-4Hz.txt |
---|
0,0 → 1,58 |
MON-VER - 0A 04 46 00 35 2E 30 30 20 20 20 20 4A 75 6C 20 31 37 20 32 30 30 36 20 31 35 3A 30 38 3A 31 30 00 01 30 30 30 34 30 30 30 31 00 00 4D 34 48 31 2E 31 43 20 4A 75 6C 20 31 37 20 32 30 30 36 20 31 36 3A 34 32 3A 33 30 00 00 |
CFG-ANT - 06 13 04 00 0B 00 0F 38 |
CFG-DAT - 06 06 02 00 00 00 |
CFG-FXN - 06 0E 24 00 12 00 00 00 C0 D4 01 00 C0 D4 01 00 C0 27 09 00 C0 27 09 00 A0 8C 00 00 40 77 1B 00 00 00 00 00 00 00 00 00 |
CFG-INF - 06 02 08 00 00 00 00 00 00 87 00 00 |
CFG-INF - 06 02 08 00 01 00 00 00 00 00 00 87 |
CFG-INF - 06 02 08 00 03 00 00 00 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 01 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 02 00 01 00 00 |
CFG-MSG - 06 01 06 00 01 03 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 04 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 06 00 01 00 00 |
CFG-MSG - 06 01 06 00 01 08 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 11 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 12 00 01 00 00 |
CFG-MSG - 06 01 06 00 01 20 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 21 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 22 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 30 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 31 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 32 00 00 00 00 |
CFG-MSG - 06 01 06 00 02 10 00 00 00 00 |
CFG-MSG - 06 01 06 00 02 11 00 00 00 00 |
CFG-MSG - 06 01 06 00 02 20 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 01 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 02 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 03 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 06 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 07 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 08 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 09 00 00 00 00 |
CFG-MSG - 06 01 06 00 0B 00 00 00 00 00 |
CFG-MSG - 06 01 06 00 0B 30 00 00 00 00 |
CFG-MSG - 06 01 06 00 0B 31 00 00 00 00 |
CFG-MSG - 06 01 06 00 0D 01 00 00 00 00 |
CFG-MSG - 06 01 06 00 0D 03 00 00 00 00 |
CFG-MSG - 06 01 06 00 F0 00 00 00 00 01 |
CFG-MSG - 06 01 06 00 F0 01 00 00 00 01 |
CFG-MSG - 06 01 06 00 F0 02 00 00 00 01 |
CFG-MSG - 06 01 06 00 F0 03 00 00 00 01 |
CFG-MSG - 06 01 06 00 F0 04 00 00 00 01 |
CFG-MSG - 06 01 06 00 F0 05 00 00 00 01 |
CFG-MSG - 06 01 06 00 F0 06 00 00 00 00 |
CFG-MSG - 06 01 06 00 F0 07 00 00 00 00 |
CFG-MSG - 06 01 06 00 F0 08 00 00 00 01 |
CFG-MSG - 06 01 06 00 F1 00 00 00 00 00 |
CFG-MSG - 06 01 06 00 F1 01 00 00 00 00 |
CFG-MSG - 06 01 06 00 F1 03 00 00 00 00 |
CFG-MSG - 06 01 06 00 F1 04 00 00 00 00 |
CFG-NAV2 - 06 1A 28 00 03 00 00 00 03 03 10 02 50 C3 00 00 0F 0A 05 3C 00 01 00 00 FA 00 FA 00 64 00 2C 01 00 00 00 00 00 00 00 00 00 00 00 00 |
CFG-NMEA - 06 17 04 00 00 23 00 02 |
CFG-PRT - 06 00 14 00 01 00 00 00 D0 08 08 00 00 E1 00 00 01 00 01 00 00 00 00 00 |
CFG-PRT - 06 00 14 00 02 00 00 00 D0 08 08 00 00 E1 00 00 01 00 01 00 00 00 00 00 |
CFG-PRT - 06 00 14 00 03 00 00 00 00 00 00 00 00 00 00 00 03 00 03 00 00 00 00 00 |
CFG-RATE - 06 08 06 00 FA 00 01 00 00 00 |
CFG-RXM - 06 11 02 00 03 00 |
CFG-SBAS - 06 16 08 00 00 00 01 00 00 00 00 00 |
CFG-TP - 06 07 14 00 40 42 0F 00 A0 86 01 00 01 01 00 00 32 00 34 03 00 00 00 00 |
/FollowMe/Hex-Files/Conrad LEA-4H Config-5Hz.txt |
---|
0,0 → 1,58 |
MON-VER - 0A 04 46 00 35 2E 30 30 20 20 20 20 4A 75 6C 20 31 37 20 32 30 30 36 20 31 35 3A 30 38 3A 31 30 00 01 30 30 30 34 30 30 30 31 00 00 4D 34 48 31 2E 31 43 20 4A 75 6C 20 31 37 20 32 30 30 36 20 31 36 3A 34 32 3A 33 30 00 00 |
CFG-ANT - 06 13 04 00 0B 00 0F 38 |
CFG-DAT - 06 06 02 00 00 00 |
CFG-FXN - 06 0E 24 00 12 00 00 00 C0 D4 01 00 C0 D4 01 00 C0 27 09 00 C0 27 09 00 A0 8C 00 00 40 77 1B 00 00 00 00 00 00 00 00 00 |
CFG-INF - 06 02 08 00 00 00 00 00 00 87 00 00 |
CFG-INF - 06 02 08 00 01 00 00 00 00 00 00 87 |
CFG-INF - 06 02 08 00 03 00 00 00 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 01 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 02 00 01 00 00 |
CFG-MSG - 06 01 06 00 01 03 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 04 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 06 00 01 00 00 |
CFG-MSG - 06 01 06 00 01 08 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 11 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 12 00 01 00 00 |
CFG-MSG - 06 01 06 00 01 20 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 21 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 22 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 30 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 31 00 00 00 00 |
CFG-MSG - 06 01 06 00 01 32 00 00 00 00 |
CFG-MSG - 06 01 06 00 02 10 00 00 00 00 |
CFG-MSG - 06 01 06 00 02 11 00 00 00 00 |
CFG-MSG - 06 01 06 00 02 20 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 01 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 02 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 03 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 06 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 07 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 08 00 00 00 00 |
CFG-MSG - 06 01 06 00 0A 09 00 00 00 00 |
CFG-MSG - 06 01 06 00 0B 00 00 00 00 00 |
CFG-MSG - 06 01 06 00 0B 30 00 00 00 00 |
CFG-MSG - 06 01 06 00 0B 31 00 00 00 00 |
CFG-MSG - 06 01 06 00 0D 01 00 00 00 00 |
CFG-MSG - 06 01 06 00 0D 03 00 00 00 00 |
CFG-MSG - 06 01 06 00 F0 00 00 00 00 01 |
CFG-MSG - 06 01 06 00 F0 01 00 00 00 01 |
CFG-MSG - 06 01 06 00 F0 02 00 00 00 01 |
CFG-MSG - 06 01 06 00 F0 03 00 00 00 01 |
CFG-MSG - 06 01 06 00 F0 04 00 00 00 01 |
CFG-MSG - 06 01 06 00 F0 05 00 00 00 01 |
CFG-MSG - 06 01 06 00 F0 06 00 00 00 00 |
CFG-MSG - 06 01 06 00 F0 07 00 00 00 00 |
CFG-MSG - 06 01 06 00 F0 08 00 00 00 01 |
CFG-MSG - 06 01 06 00 F1 00 00 00 00 00 |
CFG-MSG - 06 01 06 00 F1 01 00 00 00 00 |
CFG-MSG - 06 01 06 00 F1 03 00 00 00 00 |
CFG-MSG - 06 01 06 00 F1 04 00 00 00 00 |
CFG-NAV2 - 06 1A 28 00 03 00 00 00 03 03 10 02 50 C3 00 00 0F 0A 05 3C 00 01 00 00 FA 00 FA 00 64 00 2C 01 00 00 00 00 00 00 00 00 00 00 00 00 |
CFG-NMEA - 06 17 04 00 00 23 00 02 |
CFG-PRT - 06 00 14 00 01 00 00 00 D0 08 08 00 00 E1 00 00 01 00 01 00 00 00 00 00 |
CFG-PRT - 06 00 14 00 02 00 00 00 D0 08 08 00 00 E1 00 00 01 00 01 00 00 00 00 00 |
CFG-PRT - 06 00 14 00 03 00 00 00 00 00 00 00 00 00 00 00 03 00 03 00 00 00 00 00 |
CFG-RATE - 06 08 06 00 64 00 02 00 00 00 |
CFG-RXM - 06 11 02 00 03 00 |
CFG-SBAS - 06 16 08 00 00 00 01 00 00 00 00 00 |
CFG-TP - 06 07 14 00 40 42 0F 00 A0 86 01 00 01 01 00 00 32 00 34 03 00 00 00 00 |
/FollowMe/fat16.c |
---|
0,0 → 1,1482 |
#include <stdio.h> |
#include <avr/io.h> |
#include "fat16.h" |
#include "sdc.h" |
#include "printf_P.h" |
//________________________________________________________________________________________________________________________________________ |
// Module name: fat16.c |
// Compiler used: avr-gcc 3.4.5 |
// Last Modifikation: 28.03.2008 |
// Version: 1.25 |
// Authors: Stephan Busker |
// Description: Source files for FAT16 implementation with read and write-access using AVR-Mikrocontrollers |
// Copyright (C) 2007 Stephan Busker |
//........................................................................................................................................ |
// Functions: extern u8 FAT16_Init(void); |
// u8 fopen_(s8 *fname,s8 mode, File *file); |
// void fclose_(File *file); |
// u32 fread_(void *buffer, u32 size, u32 count, File *file); |
// u32 fwrite_(void *buffer, u32 size, u32 count, File *file); |
// s16 fseek_(File *file, s32 offset, s16 origin); |
// s8 fgets_(s8 *string, s16 count, File *file); |
// u8 fputchar_(File *file,s8 c); |
// u8 fputs_(File *file,s8 *string); |
// s8 * fgets(s8 *, s16, File); |
// u8 fexist_(u8*, File *file); |
// u8 mkdir__(s8 *name); |
// u8 chdir__(s8 *name); |
// u8 findfirst_(s8 *fname, Find *item, u8 attribute); |
// u8 findnext_(Find *item); |
// u8 fdelete_(s8 *fname) |
// u8 rmdir_(s8 *dname) |
//........................................................................................................................................ |
// ext. functions: extern u8 SDC_GetSector (u32,u8 *); |
// extern u8 SDC_PutSector (u32,u8 *); |
//........................................................................................................................................ |
// |
// URL: www.Mikro-Control.de |
// mailto: stephan.busker@mikro-control.de |
//________________________________________________________________________________________________________________________________________ |
u8 text[80]; |
//________________________________________________________________________________________________________________________________________ |
// |
// Global variables needed for read- or write-acces to the FAT16- filesystem. |
// |
//________________________________________________________________________________________________________________________________________ |
u8 SectorsPerCluster = 0; // how many sectors does a cluster contain? |
u8 FatCopies = 0; // Numbers of copies of the FAT |
u16 PossibleRootEntries = 0; // Possible number of entries in the root directory. |
u16 SectorsPerFat = 0; // how many sectors does a fat16 contain? |
u32 ReservedSectors = 0; // Sectors reserved by the filesystem. |
u32 FirstPartitionSector = 0; // Distance in sectors between the first partition and the master bootrecord. |
u32 FileAllocationTable = 0; // pointer to the first FAT |
u32 RootDirectory = 0; // Pointer to the rootdirectory of the first partition. |
u32 FirstDataCluster = 0; // Pointer to the first cluster containing data (cluster0). |
u32 CWD = 0; // Pointer startcluster to the current working directory |
struct DirEntry *DirectoryEntry; // Pointer to an entry of the directory. |
struct FatEntry *Fat; // Pointer to an entry of the fat (next clusterposition). |
File FilePointer[__MAX_FILES_USED]; // Allocate Memmoryspace for each filepointer used. |
//________________________________________________________________________________________________________________________________________ |
// Funtion: InitFat16(void); |
// |
// Description: This function reads the Masterbootrecord and finds the position of the Volumebootrecord, the FAT and the Rootdirectory |
// and stores the information in global variables. |
// |
// Returnvalue: The function returns "0" if the filesystem could not be initialized because no partition was found on the disc. |
//________________________________________________________________________________________________________________________________________ |
u8 FAT16_Init(void) |
{ |
u8 retvalue = 0; |
u8 cnt = 0; |
struct VBR_Entry *VBR; // Pointer to the VolumeBootRecord. |
struct MBR_Entry *MBR; // Pointer to the masterbootrecord. |
File *file; |
for(cnt=0;cnt<__MAX_FILES_USED;cnt++) |
{ |
FilePointer[cnt].state = _UNUSED; // declare the filepointers as unused. |
} |
file = &FilePointer[0]; |
while((SDC_Init() != 0) && (cnt++<200)); // initialise the sdcard. |
if(cnt <200) //sdcard initialised succesfully |
{ |
SDC_GetSector((u32)_MBR_SECTOR,file->buffer); // Read the MasterBootRecord from mmc. |
MBR = (struct MBR_Entry *) file->buffer; |
FirstPartitionSector = MBR->PartitionEntry1.NoSectorsBeforePartition; |
if((MBR->PartitionEntry1.Type == _FAT16_32_MB_BIOS_Extension) || |
(MBR->PartitionEntry1.Type == _FAT16_ST_32_MB) || |
(MBR->PartitionEntry1.Type == _FAT16_LT_32_MB)) |
{ |
SDC_GetSector(FirstPartitionSector,file->buffer); // Read the volume bootrecord from mmc. |
VBR = (struct VBR_Entry *) file->buffer; // Enter the VBR using the structure VBR_Entry. |
SectorsPerCluster = VBR->SectorsPerCluster; // Number of sectors per cluster. Depends on the memorysize of the sd-card. |
FatCopies = VBR->NoFATCopies; // Number of fatcopies. |
PossibleRootEntries = VBR->MaxRootEntries; // How many Entries are possible in the rootdirectory (FAT16 allows max. 512 entries). |
SectorsPerFat = VBR->SectorsPerFAT; // The number of sectors per FAT. |
ReservedSectors = VBR->ReservedSectors; // calculate the sectorpositon of the FAT, the Rootdirectory and the first Datacluster. |
FileAllocationTable = (u32)(FirstPartitionSector + (u32)ReservedSectors); // Calculate the position of the FileAllocationTable. |
RootDirectory = (u32)((u32)FileAllocationTable + (u32)((u32)SectorsPerFat*(u32)FatCopies)); // Calculate the position of the Rootdirectory. |
FirstDataCluster = (u32)((u32)RootDirectory + ((u32)(PossibleRootEntries>>4))); // Calculate the position of the first datacluster. |
CWD = RootDirectory; // The actual directory is the rootdirectory. |
retvalue = 1; |
} |
} |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: File * fopen_(u8*, u8 *); |
// |
// Description: This function looks for the file in the directory specified by the variable "CWD" of the drive. If the file is found the number of the |
// corrosponding datacluster is returned to main. Only modes 'r' (reading) and 'a' append are implemented yet. |
// |
// Return: 0 = faild to open speicified file |
// 1 = file opened |
//________________________________________________________________________________________________________________________________________ |
File * fopen_(s8 *fname, s8 mode) |
{ |
File *file; |
file = ReserveFilePointer(); // reserve a filepointer. |
if(file != NULL) // A free filepointer was found. |
{ |
file->mode = mode; // mode of fileoperation (read,write) |
if(SeekFileInDirectory(fname, file)) // if file was found |
{ |
if(mode == 'a') // open existing file for writing (append data at the end of the file) |
{ |
fseek_(file, 0, SEEK_END); // fseek points to the end of the file |
} |
else if(mode == 'r') |
{ |
return(file); |
} |
else |
{ |
fclose_(file); |
file = NULL; |
} |
} |
else |
{ |
if((mode == 'a') || (mode == 'w')) // specified file doesn't exist so create new file for writing data. |
{ |
if(CreateFileInDirectory(fname,file)) // Could an entry for the new file in the rootdirectory be created? |
{ |
return(file); |
} |
else |
{ |
fclose_(file); |
file = NULL; |
} |
} |
} |
} |
return(file); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: fflush_(File *file); |
// |
// Description: This function writes the data already in the buffer but not yet written to the file. |
// |
//________________________________________________________________________________________________________________________________________ |
s16 fflush_(File *file) |
{ |
u16 time=0; |
u16 date=0; |
if(file && ((file->mode =='a') || (file->mode =='w'))) |
{ |
if(file->byte_index > 0) // has data been added to the file? |
{ |
SDC_PutSector((u32)(file->cluster_pointer + file->sector_index),file->buffer);// save the data still in the buffer |
} |
SDC_GetSector((u32)file->directory_sector,file->buffer); // read the directoryentry for this file. |
DirectoryEntry = (struct DirEntry *)file->buffer; |
DirectoryEntry[file->directory_index].size = (u32) file->filesize; |
DirectoryEntry[file->directory_index].time = (u16) time; |
DirectoryEntry[file->directory_index].date = (u16) date; |
SDC_PutSector((u32)file->directory_sector,file->buffer); |
} |
return(0); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: fclose_(File *file); |
// |
// Description: This function closes the open file by writing the remaining data from the buffer to the device and entering the filesize |
// in the directory entry. |
//________________________________________________________________________________________________________________________________________ |
void fclose_(File *file) |
{ |
if(file != NULL) |
{ |
fflush_(file); // save buffered data to the disk |
} |
FreeFilePointer(file); // and free the filepointer. |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u32 fread_(void *buffer, s32 size, s32 count, File *file); |
// |
// Description: This function reads count objects of the specified size from the actual position of the file to the specified buffer. |
// |
// Returnvalue: The function returns the number of objects (not bytes) read from the file. |
// |
//________________________________________________________________________________________________________________________________________ |
u32 fread_(void *buffer, u32 size, u32 count, File *file) |
{ |
u32 object_cnt = 0; // count the number of objects read from the file. |
u32 object_size = 0; // count the number of bytes read from the actual object. |
u8 *buff_pnt = 0; // a pointer to the actual bufferposition. |
u8 success = 1; // no error occured during read operation to the file. |
buff_pnt = (u8 *) buffer; // cast the void pointer to an u8 * |
while((object_cnt < count) && success) |
{ |
object_size = size; |
while((size > 0) && success) |
{ |
*buff_pnt = (u8) fgetchar_(file); // read a byte from the buffer to the opened file. |
buff_pnt++; |
size--; |
} |
if(success) object_cnt++; |
} |
return(object_cnt); // return the number of objects succesfully read from the file |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u32 fwrite_(void *buffer, s32 size, s32 count, File *file); |
// |
// Description: This function writes count objects of the specified size from the buffer to the actual positon within the file. |
// |
// Returnvalue: The function returns the number of objects (not bytes) written to the file. |
// |
//________________________________________________________________________________________________________________________________________ |
u32 fwrite_(void *buffer, u32 size, u32 count, File *file) |
{ |
u32 object_cnt = 0; // count the number of objects written to the file. |
u32 object_size = 0; // count the number of bytes written from the actual object. |
u8 *buff_pnt = 0; // a pointer to the actual bufferposition. |
u8 success = 1; // no error occured during write operation to the file. |
buff_pnt = (u8 *) buffer; // cast the void pointer to an u8 * |
while((object_cnt < count) && success) |
{ |
object_size = size; |
while((size > 0) && success) |
{ |
success = fputchar_(file, *buff_pnt); // write a byte from the buffer to the opened file. |
buff_pnt++; |
size--; |
} |
if(success) object_cnt++; |
} |
return(object_cnt); // return the number of objects succesfully written to the file |
} // (!!!!! objects and not bytes !!!!) |
//________________________________________________________________________________________________________________________________________ |
// Funtion: s16 fseek_(File *, s32, s16) |
// |
// Description: This function sets the pointer of the stream relative to the position |
// specified by origin (SEEK_SET, SEEK_CUR, SEEK_END). |
// |
//________________________________________________________________________________________________________________________________________ |
s16 fseek_(File *file, s32 offset, s16 origin) |
{ |
s32 fposition = 0; |
s16 retvalue = 1; |
u32 temp = 0; |
//...................................................... |
if(origin == SEEK_SET) // Fileposition relative to the beginning of the file. |
{ |
fposition = 0; |
} |
//...................................................... |
else if(origin == SEEK_END) // Fileposition relative to the end of the file. |
{ |
fposition = (s32) file->filesize; |
} |
//...................................................... |
else if(origin == SEEK_CUR) // Fileposition relative to the current position of the file. |
{ |
fposition = file->fileposition; |
} |
fposition += offset; |
if((fposition >= 0) && (fposition <= (s32)file->filesize)) // is the pointer still within the file? |
{ |
retvalue = 0; |
file->sector_index = 0; |
file->byte_index = 0; |
file->fileposition = 0; |
file->cluster_pointer = file->start_cluster; |
while(file->fileposition < fposition) |
{ |
file->fileposition++; |
if(file->byte_index < 511) |
{ |
file->byte_index++; |
} |
else |
{ |
file->byte_index=0; // reading at the beginning of new sector. |
file->sector_index++; // continue reading in next sector |
if(file->sector_index >= SectorsPerCluster) // When end of cluster is reached, the next datacluster has to be searched in the FAT. |
{ |
if(file->fileposition < fposition) |
{ |
file->sector_index = 0; // start reading new cluster at first sector of the cluster. |
GetNextCluster(file); // Sets the clusterpointer of the file to the next datacluster. |
} |
} |
} |
} |
if(file->byte_index) |
{ |
temp = (u32)((u32)file->cluster_pointer + (u32)file->sector_index); |
SDC_GetSector((u32)temp,file->buffer); // FileBuffer will be written at once at the end of the cluster and has to be updated. |
} |
} |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: fgetchar_(File *file); |
// |
// Description: This function reads and returns one character from the specified file. |
// |
// Returnvalue: The function returns the character read from the specified memorylocation as u8 casted to s16 or EOF. |
//________________________________________________________________________________________________________________________________________ |
s16 fgetchar_(File *file) |
{ |
s16 c = EOF; |
u32 temp1; |
if(file->filesize > 0) // wen the end of the file is not reached, get the next character. |
{ |
temp1 = (u32)file->cluster_pointer; // calculate the adress of the next character to be read. |
temp1 += (u32)file->sector_index; |
if(file->sector_in_buffer != temp1) // Has the content of the buffer been modified and has to be updated? |
{ |
SDC_GetSector((u32)temp1,file->buffer); // Read the calculated cluster. |
file->sector_in_buffer = (u32)temp1; |
} |
c = (s16) file->buffer[file->byte_index]; |
file->filesize--; // decrement the number of characters available. |
if(file->byte_index < 511) // continue reading from this sector until the end of the sector is reached. |
{ |
file->byte_index++; |
} |
else // has the end of an sector been reached-> |
{ |
file->byte_index=0; // continue reading at the beginning - |
file->sector_index++; // of new sector. |
if(file->sector_index >= SectorsPerCluster) // When the end of an cluster is reached, the next datacluster has to be searched in the FAT. |
{ |
file->sector_index = 0; // start reading new cluster at first sector of the cluster. |
GetNextCluster(file); // Sets the clusterpointer of the file to the next datacluster. |
} |
} |
} |
return(c); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: fputchar_(File *file, s8 *); |
// |
// Description: This function writes a byte to the specified file and takes care of writing the necessary FAT- Entries. |
// |
// Returnvalue: The function returns a value of 0 if the data could not be written. |
//________________________________________________________________________________________________________________________________________ |
u8 fputchar_(File *file,s8 c) |
{ |
u32 ul_temp = 0; |
u8 retvalue = 1; |
if(file->sector_index >= SectorsPerCluster) // if end of the cluster is reached, find next free cluster |
{ |
file->sector_index = 0; |
if(!AppendCluster(file)) retvalue = 0; // append a new and free cluster at the end of the file. |
} |
file->buffer[file->byte_index] = c; // write databyte into the buffer. The byte will be written to the device at once |
if(file->filesize == file->fileposition) file->filesize++; // a character has been written to the file so the size is inkremented but only when the character has been added at the end of the file. |
file->fileposition++; // the actual positon within the file. |
// if the buffer contains the complete sectordata. |
if(file->byte_index < 511) // if the end of this sector is not reached yet |
{ |
file->byte_index++; // the next byte will be written to the next byteposition in this sector. |
} |
else // otherwise the data in the sectorbuffer will be written to the device and the next sector will be selected. |
{ |
ul_temp = (u32)file->cluster_pointer; |
ul_temp += (u32)file->sector_index; |
SDC_PutSector((u32)ul_temp,file->buffer); |
file->byte_index=0; // and the next byte will be written at the beginning of this new sector. |
file->sector_index++; |
if(file->sector_index >= SectorsPerCluster) // if end of the cluster is reached, find next free cluster |
{ |
file->sector_index = 0; |
if(!AppendCluster(file)) retvalue = 0; // append a new and free cluster at the end of the file. |
} |
} |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: fputs_(File *file, s8 *string); |
// |
// Description: This function writes a string to the specified file. |
// |
//________________________________________________________________________________________________________________________________________ |
u8 fputs_(File *file,s8 * string) |
{ |
u8 i=0; |
while(string[i] != 0) |
{ |
fputchar_(file,string[i]); |
i++; |
} |
return(0); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: s8 * fgets_(s8 *string, s16 count, File *file) |
// |
// Description: This function reads a string from the file to the specifies string. |
// |
// Returnvalue: A pointer to the string written from the file. |
//________________________________________________________________________________________________________________________________________ |
s8 * fgets_(s8 *string, s16 count, File *file) |
{ |
s16 buff_pnt = 0; |
s16 buff_tmp = 0; |
u8 state = 0; // Variable used for a statemachine to recognize the end of a line. |
while(count > 1) // read the count-1 characters from the file to the string. |
{ |
buff_tmp = fgetchar_(file); // read a character from the opened file. |
switch(state) |
{ |
case 0: |
if(buff_tmp == 0x0D) state++; |
break; |
case 1: |
if(buff_tmp == 0x0A) |
{ |
count = 1; |
} |
state = 0; |
break; |
} |
if(buff_tmp == EOF) {buff_tmp = 0; count = 1;} // is the end of the file reached, terminate the string with zero. |
string[buff_pnt] = (s8) buff_tmp; |
count--; |
buff_pnt++; |
} |
string[buff_pnt] = 0; |
return(string); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u8 fexist_(u8*, File *file); |
// |
// Description: This function searches the specified file and returns 0 if the file was not found. |
// |
// |
// Return: 0 = file does not exist |
// 1 = file exists |
//________________________________________________________________________________________________________________________________________ |
u8 fexist_(s8 *fname) |
{ |
File *file; |
file = ReserveFilePointer(); |
if(file != NULL) |
{ |
if((file = fopen_(fname,'r'))!= NULL) |
{ |
fclose_(file); |
return(1); |
} |
else |
{ |
return(0); |
} |
} |
else |
{ |
return(0); |
} |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: GetNextCluster(File *file); |
// |
// Description: This function finds the next datacluster of the file specified with File *file. |
// |
// Returnvalue: The function returns "0" if the last cluster has already been reached. |
//________________________________________________________________________________________________________________________________________ |
u16 GetNextCluster(File *file) |
{ |
u32 fat_pointer = 0; |
u32 fat_sector_offset = 0; |
u32 ul_tmp = 0; |
u8 retvalue = 0; // no new cluster found yet. |
if((file->cluster_pointer >= RootDirectory) && (file->cluster_pointer < (RootDirectory + 31))) |
{ // Is the next cluster searched within the rootdirectory and available? |
file->cluster_pointer++; // the rootdirectory is a linear adress space of 32 clusters. |
retvalue = 1; // and the next cluster has been found. |
} |
else if(file->cluster_pointer > (RootDirectory + 31)) // The specified cluster is within the FAT. |
{ |
fat_sector_offset = ((file->cluster_pointer) - (FirstDataCluster)); // Calculate index of actual cluster within the FAT. |
fat_sector_offset /= SectorsPerCluster; // calculate the index of the actual sector within the FAT. |
fat_sector_offset += 2; // In Fat16 clusterpositions have an offset of two. |
fat_pointer = (fat_sector_offset%0x100); // Calculate the sector within the cluster. |
fat_sector_offset = (fat_sector_offset>>8); // and the position within the sector. |
SDC_GetSector((u32)(FileAllocationTable + fat_sector_offset),file->buffer); |
file->sector_in_buffer = (FileAllocationTable + fat_sector_offset); // Mark that new sector has been read. |
ul_tmp = (u32)file->buffer[((fat_pointer << 1)+1)]; // Read next sector information from calculated clusterposition. |
ul_tmp = (ul_tmp << 8); |
ul_tmp |= (u32)file->buffer[(fat_pointer << 1)]; |
ul_tmp -=2; // next datacluster is clusterposition in fat - 2. |
ul_tmp *= SectorsPerCluster; // calculate sectorposition of new cluster |
ul_tmp += FirstDataCluster; // in relation to first datacluster of the disk. |
if(ul_tmp < 0xfff7) // has a new cluster been read or was the end of the fat reached? |
{ |
file->cluster_pointer = (u32) ul_tmp; // continue reading the file at the beginning of new datacluster. |
retvalue = 1; // a new cluster was found. |
} |
} |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u16 FindNextFreeCluster(void) |
// |
// Description: This function looks in the FAT to find the next free datacluster |
// |
// Returnvalue: The function returns the adress of the next free cluster found within the fAT. |
//________________________________________________________________________________________________________________________________________ |
u16 FindNextFreeCluster(File *file) |
{ |
u32 fat_pointer = 0; // Pointer to the first sector of the FAT. |
u32 ul_tmp = 0; // temporary variable used to calculate a sectornumber. |
u16 fat_sector_offset = 0; // index to a sector within the FAT. |
u16 fat_entry = 0; // index to an fatentry within the actual sector (256 fatentries are possible within one sector). |
u16 free_cluster = 0; // a pointer to the first sector of the next free cluster. |
fat_pointer = (u32) FileAllocationTable; // start searching for empty cluster at the beginning of the fat. |
// if the end of the fat is not reached yet and no free cluster has been found |
while((fat_sector_offset < SectorsPerFat) && (!free_cluster)) |
{ |
ul_tmp = (u32) ((u32)fat_pointer + (u32)fat_sector_offset); |
SDC_GetSector((u32)ul_tmp,file->buffer); // read next sector of FAT. |
file->sector_in_buffer = ul_tmp; // remember the number of the sector in FileBuffer. |
Fat = (struct FatEntry *)file->buffer; |
for(fat_entry=0;fat_entry<256;fat_entry++) // look for an free cluster at all entries in this sector of the fat. |
{ |
if(Fat[fat_entry].next_cluster == 0x0000) // empty cluster found!! |
{ |
Fat[fat_entry].next_cluster = 0xffff; // mark this fat-entry as used and save it to the device. |
SDC_PutSector((u32)file->sector_in_buffer,file->buffer); |
free_cluster = fat_entry; // the relative position of the free cluster found in this sector of the FAT. |
free_cluster += (fat_sector_offset << 8); // calculate the absolute position of the free cluster in the FAT; |
fat_entry = 256; // terminate the search for a free cluster in this sector. |
} |
} |
fat_sector_offset++; |
} |
return(free_cluster); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u16 AppendCluster(File *file); |
// |
// Description: This function finds the next free datacluster on the disk and appends it to the specified file. |
// |
// Returnvalue: This funktion returns 1 if a cluster was appended to the specified file. |
//________________________________________________________________________________________________________________________________________ |
u8 AppendCluster(File *file) |
{ |
u16 free_cluster = 0; |
u32 fat_pointer = 0; |
u8 retvalue = 0; |
free_cluster = FindNextFreeCluster(file); // the next free cluster found on the disk. |
if(free_cluster) retvalue = 1; // A free cluster was found and can be added to the end of the file. |
fat_pointer = FileAllocationTable; // Set Pointer to the beginnig of the FAT. |
fat_pointer += (u32)((u32)GetFatClusterOffset(file) >> 8); // find the sector in the FAT with 256 entries per sector. |
SDC_GetSector(fat_pointer,file->buffer); |
Fat = (struct FatEntry *)file->buffer; |
Fat[GetFatSectorIndex(file)].next_cluster = free_cluster; // append the free cluster to the end of the file in the FAT. |
SDC_PutSector((u32)fat_pointer,file->buffer); // save the modified sector to the FAT. |
fat_pointer = (u32)free_cluster; |
fat_pointer -= 2; |
fat_pointer *= SectorsPerCluster; |
fat_pointer += FirstDataCluster; |
file->cluster_pointer = fat_pointer; // continue wrtiting to the file in the new and free datacluster. |
return(retvalue); // return 1 when a new cluster was appended to the file |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: void DeleteClusterChain(u16 startcluster); |
// |
// Description: This function frees all the clusters used for file from the fat. |
// |
// Returnvalue: none |
//________________________________________________________________________________________________________________________________________ |
void DeleteClusterChain(u16 startcluster) |
{ |
u16 fat_index = 0; |
u16 fat_sector_offset = 0; |
u32 sector_in_buffer = 0; |
u32 ul_temp = 0; |
u8 buffer[512]; |
fat_index = (startcluster % 0x100); // Calculate the sector within the cluster. |
fat_sector_offset = (startcluster >> 8); // and the position within the sector. |
ul_temp = (u32)(FileAllocationTable + fat_sector_offset); |
do |
{ |
if(sector_in_buffer != ul_temp) |
{ |
sector_in_buffer = ul_temp; |
SDC_GetSector(ul_temp,buffer); |
} |
Fat = (struct FatEntry *)buffer; |
startcluster = Fat[fat_index].next_cluster; |
Fat[fat_index].next_cluster = 0x0000; // free the cluster within the fat. |
fat_index = (startcluster % 0x100); // Calculate the sector within the cluster. |
fat_sector_offset = (startcluster >> 8); // and the position within the sector. |
ul_temp = (u32)(FileAllocationTable + fat_sector_offset); |
if((sector_in_buffer != ul_temp) || (startcluster == 0xffff)) |
{ |
SDC_PutSector(sector_in_buffer,buffer); |
} |
} |
while(startcluster != 0xffff); // last cluster has been deleted. |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u16 GetFatClusterIndex(File *file); |
// |
// Description: This function returns the clusterindex of the cluster specified by file->cluster_pointer of the specified file. |
// |
//________________________________________________________________________________________________________________________________________ |
u16 GetFatClusterOffset(File *file) |
{ |
u32 fat_sector_offset = 0; |
fat_sector_offset = ((file->cluster_pointer) - (FirstDataCluster)); // Calculate index of actual cluster in FAT. |
fat_sector_offset /= SectorsPerCluster; |
fat_sector_offset += 2; // In Fat16 clusterpositions have an offset of two. |
return((u16)fat_sector_offset); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u16 GetFatSectorIndex(File *file); |
// |
// Description: This function returns the sectorindex of the cluster specified by file->cluster_pointer of the specified file. |
// |
//________________________________________________________________________________________________________________________________________ |
u16 GetFatSectorIndex(File *file) |
{ |
u16 fat_pointer = 0; |
fat_pointer = GetFatClusterOffset(file); |
fat_pointer = fat_pointer % 0x100; // Calculate the clusterposition in the fat |
return(fat_pointer); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u16 CreateFileInDirectory(u8 *, File *) |
// |
// Description: This function looks for the next free position in the directory and creates an entry. The type of an directoryentry is |
// specified by the attribute. |
// bit0: unused |
// bit1: archive |
// bit2: read_only |
// bit3: system |
// bit4: directory |
// bit5: volume |
//________________________________________________________________________________________________________________________________________ |
u8 CreateFileInDirectory(s8 *fname, File *file) |
{ |
u16 rootentry = 0; // index to an entry in the rootdirectory. |
u16 cnt_enries_searched = 0; // count the number of rootentries which have been searched already. |
u8 i = 0; |
u16 sector_offset = 0; // index to the sector of the Rootentry which is searched momentarily |
u8 retvalue = 0; |
u32 cluster_temp = 0; |
u16 cluster = 0; |
s8 name[11] = " "; |
SeperateFileName(fname,name); |
cluster_temp = (u32)FindNextFreeCluster(file); // the next free cluster on the disk. |
if(cluster_temp) // if a free cluster is available: |
{ |
cluster = (u16)cluster_temp; // remember the index of the free datacluster found for the directory entry. |
cluster_temp -=2; // Clusterposition is ((position in FAT)-2). first two entries in FAT are reserved. |
cluster_temp *= SectorsPerCluster; // Calculate relative sectorindex of first datacluster. |
file->start_cluster = (FirstDataCluster + cluster_temp); // Calculate absolute sectorposition of first datacluster. |
file->cluster_pointer = file->start_cluster; // start reading the file with the first sector of the first datacluster. |
// directory starts at sector specified by dir_sector. This can be the rootdirectory or any other directory. |
do |
{ // search the next 16 rootentries in this sector of the roordirectory. |
rootentry=0; |
SDC_GetSector((u32)(CWD + sector_offset),file->buffer); // Read the Rootdirectory. |
DirectoryEntry = (struct DirEntry *)file->buffer; |
while((rootentry<16) && (!retvalue)) |
{ |
if((DirectoryEntry[rootentry].attribute == 0) || (DirectoryEntry[rootentry].attribute == 0xE5)) // empty directory entry found |
{ |
for(i=0;i<11;i++) DirectoryEntry[rootentry].name[i] = name[i]; // Kopie the filename and the file extension to the directoryentry. |
DirectoryEntry[rootentry].attribute = _FILE; // Set the fileattribute to archive to reserve the directoryentry. |
DirectoryEntry[rootentry].startcluster = cluster; // copy the location of the first datacluster to the directoryentry. |
DirectoryEntry[rootentry].size = 0; // the new createted file has no content yet. |
file->directory_sector = (u32) (CWD + sector_offset); |
file->directory_index = (u8) rootentry; |
retvalue = 1; |
SDC_PutSector((u32)(CWD + sector_offset),file->buffer); |
} |
rootentry++; |
cnt_enries_searched++; |
} |
if(!retvalue) // file not found in this sector so take next sector. |
{ |
rootentry = 0; |
sector_offset++; |
} |
} |
while((cnt_enries_searched< PossibleRootEntries) && (!retvalue)); |
} |
return(retvalue); // return 1 if file has been created otherwise return 0. |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u16 SeekFileInDirectory(s8 *fname, File *) |
// |
// Description: this function searches all possible entries withint the actual directory for the specified object. |
// |
// Returnvalue: This function returns 1 if the directoryentry specified was found. |
//________________________________________________________________________________________________________________________________________ |
u8 SeekFileInDirectory(s8 *fname, File *file) |
{ |
u16 rootentry=0; |
u16 end_of_directory_not_reached = 0; // the directory has been read completely without a result. |
u8 i=0; |
u8 retvalue = 0; |
u32 cluster_temp = 0; |
s8 name[11] = " "; |
SeperateFileName(fname,name); |
file->cluster_pointer = CWD; // start looking for the file in the actual directory. |
// directory starts at sector specified by dir_sector. This can be the rootdirectory or any other directory. |
do |
{ // search the next 16 rootentries in this sector of the roordirectory. |
rootentry=0; |
SDC_GetSector((u32) file->cluster_pointer,file->buffer); // Read the Rootdirectory. |
DirectoryEntry = (struct DirEntry *)file->buffer; |
while((!retvalue)&&(rootentry<16)) |
{ |
i=0; |
if(DirectoryEntry[rootentry].name[0] != 0xe5) // ignore deleted items. |
{ |
while((i<=10)&&(DirectoryEntry[rootentry].name[i] == name[i])) |
{ |
i++; |
} |
} |
if((i==11) && (DirectoryEntry[rootentry].attribute & _FILE)) // entry found!! -> reading startcluster of entry from offset 26. |
{ |
cluster_temp = (u32)DirectoryEntry[rootentry].startcluster; |
cluster_temp -=2; // Clusterposition is ((position in FAT)-2). first two entries in FAT are reserved. |
cluster_temp *= (u32)SectorsPerCluster; // Calculate positon of first cluster. |
file->start_cluster = (FirstDataCluster + cluster_temp); |
file->directory_sector = (u32) file->cluster_pointer; |
file->cluster_pointer = file->start_cluster; // start reading the file with the first cluster. |
file->filesize = (u32) DirectoryEntry[rootentry].size; |
file->directory_index = (u8) rootentry; |
retvalue = 1; |
} |
rootentry++; |
} |
if(!retvalue) // file not found in this sector so take next sector. |
{ |
end_of_directory_not_reached = GetNextCluster(file); |
} |
} |
while((end_of_directory_not_reached) && (!retvalue)); |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: void SeperateFileName(u8*); |
// |
// Description: This function seperates the filename and the fileattribute and brings them into the needed format ('test.txt' -> 'TEST TXT'); |
// |
//________________________________________________________________________________________________________________________________________ |
void SeperateFileName(s8 *fname, s8 *name) |
{ |
u8 readpointer = 0; |
u8 writepointer = 0; |
u8 attribute = 1; |
u8 i = 0; |
while((writepointer<=10) && (fname[readpointer]!=0)) // the rootdirectoryentry is 8bytes for filename and 3bytes for fileattribute. |
{ // the filename in the rootdirectory is in the format "TEST TXT" without the dot. |
if(fname[readpointer]=='.') // seperating filename and attribute. |
{ |
if(attribute) // is the filename "." or ".." ? |
{ |
name[writepointer] = fname[readpointer]; |
readpointer++; |
writepointer++; |
} |
else |
{ |
if(fname[(readpointer-1)] != '*') |
{ |
for(i=writepointer;i<8;i++) |
{ |
name[i] = ' '; |
} |
} |
readpointer++; |
writepointer = 8; |
} |
} |
else if(fname[readpointer] == '*') // wildcard found within the filename + extension. |
{ |
if(writepointer < 8) // in extension. |
{ |
readpointer++; |
writepointer = 8; |
} |
else // in filename. |
{ |
writepointer = 11; // jump to the end of the string to terminate this function. |
} |
attribute = 0; |
} |
else |
{ |
if((fname[readpointer]>96) && (fname[readpointer]<123)) |
{ |
name[writepointer]=(fname[readpointer] - 32); // all characters must be upper case. |
} |
else |
{ |
name[writepointer]=fname[readpointer]; |
} |
readpointer++; |
writepointer++; |
attribute = 0; |
} |
} |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: File * ReserveFilePointer_(void); |
// |
// Description: This function looks for a free filepointer and reserves it. |
// |
// |
// Return: NULL = faild to reserve a filepointer |
// otherwise filepointer |
//________________________________________________________________________________________________________________________________________ |
File * ReserveFilePointer(void) |
{ |
File *file; |
file = NULL; |
u8 temp; |
for(temp = 0;temp<__MAX_FILES_USED;temp++) |
{ |
if(FilePointer[temp].state == _UNUSED) // free filepointer found? |
{ |
file = &FilePointer[temp]; |
FilePointer[temp].state = _USED; // mark as used. |
FilePointer[temp].mode = 0; // type of access (read/write) not defined yet. |
FilePointer[temp].start_cluster = 0; // Sectorpointer to the first sector of the first datacluster of the file. |
FilePointer[temp].cluster_pointer = 0; // Pointer to the cluster which is edited at the moment. |
FilePointer[temp].sector_index = 0; // The sector which is edited at the moment (cluster_pointer + sector_index). |
FilePointer[temp].byte_index = 0; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index). |
FilePointer[temp].filesize = 0; // the size of the opend file in bytes. |
FilePointer[temp].fileposition = 0; // pointer to a character within the file 0 < fileposition < filesize |
FilePointer[temp].sector_in_buffer = 0; // the last sector read, wich is still in the sectorbuffer. |
FilePointer[temp].directory_sector = 0; // the sectorposition where the directoryentry has been made. |
FilePointer[temp].directory_index = 0; // the index to the directoryentry within the specified sector. |
FilePointer[temp].attribute = 0; // the attribute of the file opened. |
break; |
} |
} |
return(file); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: void FreeFilePointer_(File *); |
// |
// Description: This function free's the filepointer by marking it as unused. |
// |
// |
// Return: none |
// |
//________________________________________________________________________________________________________________________________________ |
void FreeFilePointer(File *file) |
{ |
u8 cnt = 0; |
for(cnt=0;cnt<__MAX_FILES_USED;cnt++) // Is the filepointeradress vaild? |
{ |
if(&FilePointer[cnt] == file) // filepointer found therefore it must be valid |
{ |
FilePointer[cnt].state = _UNUSED; // and can be marked as unused. |
} |
} |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: void DelteDirectoryEntry(Find *) |
// |
// Description: This function deletes the directoryentry of the specified item. |
// |
// |
// returnvalue: 1 if the directory could be created. |
//________________________________________________________________________________________________________________________________________ |
void DeleteDirectoryEntry(Find *item) |
{ |
u8 buffer[512]; |
SDC_GetSector((u32) item->cluster_pointer,buffer); // Read the Rootdirectory. |
DirectoryEntry = (struct DirEntry *)buffer; |
DirectoryEntry[(item->directory_index)-1].attribute = 0; // free the directoryentry. |
DirectoryEntry[(item->directory_index)-1].name[0] = 0xE5; // free the directoryentry. |
SDC_PutSector((u32) item->cluster_pointer,buffer); // Read the Rootdirectory. |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u8 CreateSubDirectory(u8 *) |
// |
// Description: This function creates an directory within the directory specified by CWD |
// |
// |
// returnvalue: 1 if the directory could be created. |
//________________________________________________________________________________________________________________________________________ |
u8 CreateSubDirectory(s8 *fname) |
{ |
u16 index = 0; // index to an entry in the rootdirectory. |
u16 cnt_entries_searched = 0; // count the number of rootentries which have been searched already. |
u16 i = 0; |
u16 sector_offset = 0; // index to the sector of the entry which is searched momentarily |
u8 retvalue = 0; |
u32 cluster_temp = 0; |
u16 cluster = 0; |
File file; |
u8 name[11] = {" "}; |
SeperateFileName(fname,name); |
cluster_temp = (u32)FindNextFreeCluster(&file); // the next free cluster on the disk. |
if(cluster_temp) // if a free cluster is available: |
{ |
cluster = (u16)cluster_temp; // remember the index of the free datacluster found for the directory entry. |
cluster_temp -=2; // Clusterposition is ((position in FAT)-2). first two entries in FAT are reserved. |
cluster_temp *= SectorsPerCluster; // Calculate relative sectorindex of first datacluster. |
file.start_cluster = (FirstDataCluster + cluster_temp); // Calculate absolute sectorposition of first datacluster. |
file.cluster_pointer = file.start_cluster; // start reading the file with the first sector of the first datacluster. |
// -Initialise new cluster to zero-------------------------------------------------------- |
for(i=0;i<512;i++) |
{ |
file.buffer[i] = 0; // initialise buffer to zero |
} |
for(sector_offset=0;sector_offset<SectorsPerCluster;sector_offset++) // initialise all sectors of new cluster with buffer. |
{ |
SDC_PutSector((u32)(file.start_cluster + sector_offset),file.buffer); // save the initialised sector to the card. |
} |
// -Create directoryentry "." ------------------------------------------------------------- |
DirectoryEntry = (struct DirEntry *)file.buffer; |
DirectoryEntry[0].name[0] = '.'; |
DirectoryEntry[0].attribute = _DIRECTORY; |
DirectoryEntry[0].startcluster = cluster; |
// -Create directoryentry "." ------------------------------------------------------------- |
DirectoryEntry[1].name[0] = '.'; |
DirectoryEntry[1].name[1] = '.'; |
DirectoryEntry[1].attribute = _DIRECTORY; |
if(CWD == RootDirectory) |
{ |
DirectoryEntry[1].startcluster = 0; |
} |
else |
{ |
cluster_temp = (CWD - FirstDataCluster); |
cluster_temp /= SectorsPerCluster; |
cluster_temp -= 2; |
DirectoryEntry[1].startcluster = (u16) cluster_temp; |
} |
SDC_PutSector((u32) file.start_cluster,file.buffer); // save the initialised sector to the card. |
// -create directoryentry within the cwd -------------------------------------------------- |
sector_offset = 0; |
cnt_entries_searched = 0; |
do |
{ // search the next 16 rootentries in this sector of the roordirectory. |
index=0; |
SDC_GetSector((u32)(CWD + sector_offset),file.buffer); // Read the actual directory. |
DirectoryEntry = (struct DirEntry *)file.buffer; |
while((index<16) && (!retvalue)) |
{ |
if((DirectoryEntry[index].attribute == 0) || (DirectoryEntry[index].attribute == 0xE5)) // empty directory entry found |
{ |
for(i=0;i<11;i++) DirectoryEntry[index].name[i] = name[i]; // Kopie the filename and the file extension to the directoryentry. |
DirectoryEntry[index].attribute = _DIRECTORY; // Set the fileattribute to archive to reserve the directoryentry. |
DirectoryEntry[index].startcluster = cluster; // copy the location of the first datacluster to the directoryentry. |
DirectoryEntry[index].size = 0; // the new createted file has no content yet. |
file.directory_sector = (u32) (CWD + sector_offset); |
file.directory_index = (u8) index; |
retvalue = 1; |
SDC_PutSector((u32)(CWD + sector_offset),file.buffer); |
} |
index++; |
cnt_entries_searched++; |
} |
if(!retvalue) // file not found in this sector so take next sector. |
{ |
index = 0; |
sector_offset++; |
} |
} |
while((cnt_entries_searched< PossibleRootEntries) && (!retvalue)); |
} |
return(retvalue); // return 1 if file has been created otherwise return 0. |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u16 SeekSubDirectory(s8 *fname) |
// |
// Description: looks for the specified directory within the CWD. |
// |
// Returnvalue: If the specified directory was found the startcluster is returned. otherwise 0. |
//________________________________________________________________________________________________________________________________________ |
u16 SeekSubDirectory(s8 *fname) |
{ |
u16 index = 0; |
u16 end_of_directory_not_reached = 0; // the directory has been read completely without a result. |
u8 i = 0; |
u16 cluster_temp = 0; |
s8 name[11] = " "; |
File file; |
SeperateFileName(fname,name); |
file.cluster_pointer = CWD; // start looking for the file in the actual directory. |
file.start_cluster = CWD; // start looking for the file in the actual directory. |
// directory starts at sector specified by dir_sector. This can be the rootdirectory or any other directory. |
do |
{ // search the next 16 rootentries in this sector of the roordirectory. |
index=0; |
SDC_GetSector((u32) file.cluster_pointer,file.buffer); // Read the Rootdirectory. |
DirectoryEntry = (struct DirEntry *)file.buffer; |
while((!cluster_temp)&&(index<16)) |
{ |
i=0; |
if(DirectoryEntry[index].name[0] != 0xe5) // ignore deleted items. |
{ |
while((i<=10)&&(DirectoryEntry[index].name[i] == name[i])) |
{ |
i++; |
} |
} |
if((i==11) && (DirectoryEntry[index].attribute & _DIRECTORY)) // entry found!! -> reading startcluster of entry from offset 26. |
{ |
cluster_temp = (u16)DirectoryEntry[index].startcluster; |
} |
index++; |
} |
if(!cluster_temp) // file not found in this sector so take next sector. |
{ |
end_of_directory_not_reached = GetNextCluster(&file); |
} |
} |
while((end_of_directory_not_reached) && (!cluster_temp)); |
return(cluster_temp); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u8 mkdir_(u8 *) |
// |
// Description: This function checks if the directory to be created already exists. If not the directory will be created. |
// |
// |
// returnvalue: 1 if the directory could be created. |
//________________________________________________________________________________________________________________________________________ |
u8 mkdir_(s8 *fname) |
{ |
u8 retvalue = 0; |
retvalue = SeekSubDirectory(fname); // check wether the specified directory already exists. |
if(!retvalue) |
{ |
CreateSubDirectory(fname); // if directory doesn't exist, create it. |
retvalue = 1; |
} |
else |
{ |
retvalue = 0; |
} |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u8 chdir_(u8 *) |
// |
// Description: This function changes the CWD to the directory specified. |
// |
// |
// returnvalue: 1 if the directory could be changed. |
//________________________________________________________________________________________________________________________________________ |
u8 chdir_(s8 *fname) |
{ |
u8 retvalue = 0; |
u8 name[11] = {" "}; |
u32 ultemp = 0; |
SeperateFileName(fname,name); |
ultemp = (u32)SeekSubDirectory(name); |
if(ultemp >= 2) |
{ |
ultemp -=2; // Clusterposition is ((position in FAT)-2). first two entries in FAT are reserved. |
ultemp *= SectorsPerCluster; // Calculate relative sectorindex of first datacluster. |
ultemp += FirstDataCluster; |
CWD = ultemp; |
retvalue = 1; |
} |
else |
{ |
CWD = RootDirectory; |
retvalue = 1; |
} |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u8 FindItem(s8 *fname, Find *) |
// |
// Description: finds an item (file or directory) within common working directory (cwd). Wildcards '*' or '?' will be considered. |
// |
// Returnvalue: If an item was found this function returns '1' else '0'. |
//________________________________________________________________________________________________________________________________________ |
u8 FindItem(Find *item) |
{ |
u16 index = 0; |
u16 end_of_directory_not_reached = 0; // the directory has been read completely without a result. |
u8 i = 0; |
u8 readpointer = 0; |
u8 writepointer = 0; |
u8 retvalue = 0; |
File file; |
file.cluster_pointer = item->cluster_pointer; |
file.start_cluster = item->cluster_pointer; |
index = item->directory_index; |
// directory starts at sector specified by dir_sector. This can be the rootdirectory or any other directory. |
do |
{ // search the next 16 rootentries in this sector of the roordirectory. |
SDC_GetSector((u32) file.cluster_pointer,file.buffer); // Read the Rootdirectory. |
DirectoryEntry = (struct DirEntry *)file.buffer; |
while((!retvalue)&&(index<16)) |
{ |
i=0; |
if(DirectoryEntry[index].name[0] != 0xe5) // ignore deleted items. |
{ |
while((i<=10)&&((DirectoryEntry[index].name[i] == item->searchstring[i]) || (item->searchstring[i]=='*') || item->searchstring[i]=='?')) |
{ |
i++; |
} |
} |
if((i==11) && (DirectoryEntry[index].attribute & item->attribute)) |
{ |
for(readpointer=0;readpointer<=10;readpointer++) |
{ |
if(DirectoryEntry[index].name[readpointer] != ' ') |
{ |
item->name[writepointer] = DirectoryEntry[index].name[readpointer]; // copy the name of the item found to the find_structure. |
writepointer++; |
} |
else if((readpointer==7) && (DirectoryEntry[index].attribute == _FILE)) // if the item found is a file |
{ |
if(DirectoryEntry[index].name[readpointer] != ' ') |
{ |
item->name[writepointer] = DirectoryEntry[index].name[readpointer]; // copy the name of the item found to the find_structure. |
writepointer++; |
} |
item->name[writepointer] = '.'; // then seperate the name and the extension by a '.' at index 8. |
writepointer++; |
} |
} |
item->startcluster = (u16)DirectoryEntry[index].startcluster; |
item->directory_index = ++index; |
item->cluster_pointer = file.cluster_pointer; |
retvalue = 1; |
} |
index++; |
} |
if(!retvalue) // file not found in this sector so take next sector. |
{ |
end_of_directory_not_reached = GetNextCluster(&file); |
} |
index = 0; |
} |
while((end_of_directory_not_reached) && (!retvalue)); |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u8 findfirst(s8 *fname, Find *) |
// |
// Description: finds the first item (file or directory) within common working directory (cwd). Wildcards '*' or '?' will be considered. |
// |
// Returnvalue: If an item was found this function returns '1' else '0'. |
//________________________________________________________________________________________________________________________________________ |
u8 findfirst_(s8 *fname, Find *item, u8 attribute) |
{ |
u8 retvalue = 0; |
u8 i = 0; |
for(i=0;i<=11;i++) |
{ |
item->searchstring[i] = '*'; // initialise the searchstring with wildcards. |
item->name[i] = 0; |
} |
SeperateFileName(fname,item->searchstring); |
item->cluster_pointer = CWD; // findfirst_ starts at the beginning of the cwd. |
item->directory_index = 0; |
item->attribute = attribute; |
retvalue = FindItem(item); |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u8 findnext(Find *) |
// |
// Description: finds the first item (file or directory) within common working directory (cwd). Wildcards '*' or '?' will be considered. |
// |
// Returnvalue: If an item was found this function returns '1' else '0'. |
//________________________________________________________________________________________________________________________________________ |
u8 findnext_(Find *item) |
{ |
u8 retvalue = 0; |
u8 i = 0; |
for(i=0;i<=11;i++) |
{ |
item->name[i] = 0; |
} |
retvalue = FindItem(item); |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u8 fdelete(s8 *fname) |
// |
// Description: Deletes the file specified by fname. |
// |
// Returnvalue: |
//________________________________________________________________________________________________________________________________________ |
u8 fdelete_(s8 *fname) |
{ |
u8 retvalue = 0; |
Find item; |
printf("\n\rDeleting file"); |
retvalue = findfirst_(fname,&item, _FILE); // look for the item to be deleted. |
if(retvalue); // item found? |
{ |
printf("\n\r"); |
printf("%s", item.name); |
DeleteClusterChain(item.startcluster); // delete all fatentries of the item. |
DeleteDirectoryEntry(&item); // free the directoryentry. |
do |
{ |
printf("\n\r"); |
printf("%s", item.name); |
retvalue = findnext_(&item); |
if(retvalue) |
{ |
DeleteClusterChain(item.startcluster); // delete all fatentries of the item. |
DeleteDirectoryEntry(&item); // free the directoryentry. |
} |
} |
while(retvalue); |
} |
printf("\n\rDone"); |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: u8 rmdir(s8 *fname) |
// |
// Description: Deletes the directory specified by dname. |
// |
// Returnvalue: |
//________________________________________________________________________________________________________________________________________ |
u8 rmdir_(s8 *dname) |
{ |
u8 retvalue = 0; |
Find item; |
printf("\n\rDeleting folder"); |
retvalue = findfirst_(dname,&item, _DIRECTORY); // look for the item to be deleted. |
if(retvalue); // item found? |
{ |
printf("\n\r"); |
printf("%s", item.name); |
DeleteClusterChain(item.startcluster); // delete all fatentries of the item. |
DeleteDirectoryEntry(&item); // free the directoryentry. |
do |
{ |
printf("\n\r"); |
printf("%s", item.name); |
retvalue = findnext_(&item); |
if(retvalue) |
{ |
DeleteClusterChain(item.startcluster); // delete all fatentries of the item. |
DeleteDirectoryEntry(&item); // free the directoryentry. |
} |
} |
while(retvalue); |
} |
printf("\n\rDone"); |
return(retvalue); |
} |
/FollowMe/fat16.h |
---|
0,0 → 1,267 |
#ifndef __fat16_h |
#define __fat16_h |
//________________________________________________________________________________________________________________________________________ |
// |
// Userspecific definitions |
// |
//________________________________________________________________________________________________________________________________________ |
#define __MAX_FILES_USED 1 // The number of files that can be opened simultaneously. |
//________________________________________________________________________________________________________________________________________ |
// |
// Datatype definitions |
// |
//________________________________________________________________________________________________________________________________________ |
typedef unsigned char u8; |
typedef signed char s8; |
typedef unsigned short u16; |
typedef signed short s16; |
typedef unsigned long u32; |
typedef signed long s32; |
//________________________________________________________________________________________________________________________________________ |
// |
// Structure of a filepointer |
// |
//________________________________________________________________________________________________________________________________________ |
#define _UNUSED 1 // Bits used in the attribute of an directory entry. |
#define _USED 2 |
#define _ARCHIVE 2 |
#define _READ_ONLY 4 |
#define _SYSTEM 8 |
#define _DIRECTORY 16 |
#define _FILE 32 |
typedef struct afile |
{ |
u32 start_cluster; // Sectorpointer to the first sector of the first datacluster of the file. |
u32 cluster_pointer; // Pointer to the cluster which is edited at the moment. |
u8 sector_index; // The sector which is edited at the moment (cluster_pointer + sector_index). |
u16 byte_index; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index). |
u8 mode; // mode of fileoperation (read,write) |
u32 filesize; // the size of the opend file in bytes. |
u32 fileposition; // pointer to a character within the file 0 < fileposition < filesize |
u32 sector_in_buffer; // the last sector read, wich is still in the sectorbuffer. |
u32 directory_root_sector; // pointer to the root of the |
u32 directory_sector; // the sectorposition where the directoryentry has been made. |
u8 directory_index; // the index to the directoryentry within the specified sector. |
u8 attribute; // the attribute of the file opened. |
u8 buffer[512]; // Buffer for read and write operation from or to the mmc. |
u8 state; // state of the filepointer (used/unused/...) |
} File; |
//________________________________________________________________________________________________________________________________________ |
// |
// Structure of an item to find within the cwd |
// |
//________________________________________________________________________________________________________________________________________ |
typedef struct find |
{ |
u8 name[12]; // filename + extension or directoryname of the item found within the cwd. |
u8 searchstring[13]; |
u32 cluster_pointer; // Sectorpointer to the sector of the item searched within the cwd. |
u16 startcluster; // pointer to the first datacluster of the item found in the cwd. |
u32 filesize; // the size of the opend file in bytes. |
u32 directory_sector; // the sector within the actual cluster where the directoryentry was found. |
u8 directory_index; // the index to the directoryentry within the specified sector. |
u8 attribute; // the attribute of the file opened. |
} Find; |
//________________________________________________________________________________________________________________________________________ |
// |
// Directoryentries |
// |
//________________________________________________________________________________________________________________________________________ |
struct DirEntry |
{ |
u8 name[8]; // 8 bytes name. |
u8 extension[3]; // 3 bytes extension. |
u8 attribute; // attribute of the directory entry (unused,archive,read-only,system,directory,volume) |
u8 reserved[10]; // reserved bytes within the directory entry. |
u16 time; // time and |
u16 date; // date of last write acces to the file or directory. |
u16 startcluster; // first cluster of the file or directory. |
u32 size; // size of the file or directory in bytes. |
} __attribute__((packed)); |
//________________________________________________________________________________________________________________________________________ |
// |
// Structure of an entry within the fileallocationtable. |
// |
//________________________________________________________________________________________________________________________________________ |
struct FatEntry |
{ |
u16 next_cluster; // the next cluster of the file. |
} __attribute__((packed)); |
//________________________________________________________________________________________________________________________________________ |
// |
// Partitions |
// |
//________________________________________________________________________________________________________________________________________ |
#define _EMPTY 0x00 |
#define _FAT12 0x01 |
#define _FAT16_ST_32_MB 0x04 |
#define _EXTENDED 0x05 |
#define _FAT16_LT_32_MB 0x06 |
#define _HPFS 0x07 |
#define _FAT32 0x0B |
#define _FAT32_BIOS_Extension 0x0C |
#define _FAT16_32_MB_BIOS_Extension 0x0E |
#define _EXTENDED_BIOS_Extension 0x0F |
#define _EISA 0x12 |
#define _DYNAMIC 0x42 |
#define _Linux_Swap 0x82 |
#define _Linux_Native 0x83 |
#define _Linux_LVM 0x8E |
#define _FreeBSD 0xA5 |
#define _OpenBSD 0xA6 |
#define _NetBSD 0xA9 |
struct PartitionEntry |
{ |
u8 PartitionState; |
u8 BeginningHead; |
u16 BeginningCylinder; |
u8 Type; |
u8 EndHead; |
u16 EndCylinder; |
u32 NoSectorsBeforePartition; |
u32 NoSectorsPartition ; |
} __attribute__((packed)); |
//________________________________________________________________________________________________________________________________________ |
// |
// Structure of the VolumeBootRecord |
// |
//________________________________________________________________________________________________________________________________________ |
struct VBR_Entry |
{ |
u8 dummy[11]; |
u16 bps; |
u8 SectorsPerCluster; |
u16 ReservedSectors; |
u8 NoFATCopies; |
u16 MaxRootEntries; |
u16 dummy2; |
u8 dummy3; |
u16 SectorsPerFAT; |
} __attribute__((packed)); |
//________________________________________________________________________________________________________________________________________ |
// |
// Structure of the MasterBootRecord |
// |
//________________________________________________________________________________________________________________________________________ |
#define _MBR_SECTOR 0 // The MasterBootRecord is located in sector 0 |
struct MBR_Entry |
{ |
u8 ExecutableCode[446]; |
struct PartitionEntry PartitionEntry1; |
struct PartitionEntry PartitionEntry2; |
struct PartitionEntry PartitionEntry3; |
struct PartitionEntry PartitionEntry4; |
u16 ExecutableMarker; |
} __attribute__((packed)); |
//________________________________________________________________________________________________________________________________________ |
// |
// API to the FAT16 filesystem |
// |
//________________________________________________________________________________________________________________________________________ |
extern u8 FAT16_Init(void); |
extern File * fopen_(s8 *fname,s8 mode); |
extern s16 fflush_(File *file); |
extern void fclose_(File *file); |
extern u32 fread_(void *buffer, u32 size, u32 count, File *file); |
extern u32 fwrite_(void *buffer, u32 size, u32 count, File *file); |
extern s16 fseek_(File *file, s32 offset, s16 origin); |
extern s16 fgetchar_(File *file); |
extern u8 fputchar_(File *file,s8 c); |
extern u8 fputs_(File *file,s8 *string); |
extern s8 * fgets_(s8 *s, s16 count, File *file); |
extern s16 frename_(s8 *oldname, s8 *newname); |
extern u8 fexist_(s8*fname); |
extern u8 mkdir_(s8*fname); |
extern u8 chdir_(s8 *fname); |
extern u8 findfirst_(s8 *fname, Find *item, u8 attribute); |
extern u8 findnext_(Find *item); |
//________________________________________________________________________________________________________________________________________ |
// |
// Functions needed internaly for the fat16 implementation |
// |
//________________________________________________________________________________________________________________________________________ |
extern u8 SeekFileInDirectory(s8*fname, File *file); |
extern u8 CreateFileInDirectory(s8*fname, File *file); |
extern u16 FindNextFreeCluster(File *file); |
extern void SeperateFileName(s8*fname, s8*name); |
extern u8 ScanSubDirectories(s8*fname, File *file); |
extern u16 GetNextCluster(File *file); |
extern u8 AppendCluster(File *file); |
extern u16 GetFatClusterOffset(File *file); |
extern u16 GetFatSectorIndex(File *file); |
extern File * ReserveFilePointer(void); |
extern u16 SeekSubDirectory(s8 *fname); |
extern u8 CreateSubDirectory_(s8 *fname); |
extern u8 FindItem(Find *); |
extern void FreeFilePointer(File *file); |
//________________________________________________________________________________________________________________________________________ |
// |
// Vaiables needed internaly for the fat16 implementation |
// |
//________________________________________________________________________________________________________________________________________ |
extern u8 SectorsPerCluster; |
extern u32 CWD; |
#endif |
/FollowMe/led.c |
---|
0,0 → 1,23 |
#include <inttypes.h> |
#include "led.h" |
// initializes the LED control outputs |
void LED_Init(void) |
{ |
#ifdef USE_SDLOGGER |
// set PB0 as output (control of red LED) |
DDRB |= (1<<DDB0); |
LEDRED_OFF; |
#endif |
#ifdef USE_FOLLOWME |
// set PB0 as output (control of yellow LED) |
DDRB |= (1<<DDB0); |
LEDYELLOW_OFF; |
// set PB1 as output (control of red LED) |
DDRB |= (1<<DDB1); |
LEDRED_OFF; |
#endif |
} |
/FollowMe/led.h |
---|
0,0 → 1,25 |
#ifndef _LED_H |
#define _LED_H |
#include <avr/io.h> |
#ifdef USE_SDLOGGER |
#define LEDRED_OFF PORTB |= (1<<PORTB0) |
#define LEDRED_ON PORTB &= ~(1<<PORTB0) |
#define LEDRED_TOGGLE PORTB ^= (1<<PORTB0) |
#endif |
#ifdef USE_FOLLOWME |
#define LEDYELLOW_OFF PORTB |= (1<<PORTB0) |
#define LEDYELLOW_ON PORTB &= ~(1<<PORTB0) |
#define LEDYELLOW_TOGGLE PORTB ^= (1<<PORTB0) |
#define LEDRED_OFF PORTB |= (1<<PORTB1) |
#define LEDRED_ON PORTB &= ~(1<<PORTB1) |
#define LEDRED_TOGGLE PORTB ^= (1<<PORTB1) |
#endif |
void LED_Init(void); |
#endif //_LED_H |
/FollowMe/main.c |
---|
0,0 → 1,115 |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// + Copyright (c) 04.2007 Holger Buss |
// + Nur für den privaten Gebrauch |
// + www.MikroKopter.com |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// + Es gilt für das gesamte Projekt (Hardware, Software, Binärfiles, Sourcecode und Dokumentation), |
// + dass eine Nutzung (auch auszugsweise) nur für den privaten und nicht-kommerziellen Gebrauch zulässig ist. |
// + Sollten direkte oder indirekte kommerzielle Absichten verfolgt werden, ist mit uns (info@mikrokopter.de) Kontakt |
// + bzgl. der Nutzungsbedingungen aufzunehmen. |
// + Eine kommerzielle Nutzung ist z.B.Verkauf von MikroKoptern, Bestückung und Verkauf von Platinen oder Bausätzen, |
// + Verkauf von Luftbildaufnahmen, usw. |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// + Werden Teile des Quellcodes (mit oder ohne Modifikation) weiterverwendet oder veröffentlicht, |
// + unterliegen sie auch diesen Nutzungsbedingungen und diese Nutzungsbedingungen incl. Copyright müssen dann beiliegen |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// + Sollte die Software (auch auszugesweise) oder sonstige Informationen des MikroKopter-Projekts |
// + auf anderen Webseiten oder Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de" |
// + eindeutig als Ursprung verlinkt und genannt werden |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// + Keine Gewähr auf Fehlerfreiheit, Vollständigkeit oder Funktion |
// + Benutzung auf eigene Gefahr |
// + Wir übernehmen keinerlei Haftung für direkte oder indirekte Personen- oder Sachschäden |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// + Die Portierung der Software (oder Teile davon) auf andere Systeme (ausser der Hardware von www.mikrokopter.de) ist nur |
// + mit unserer Zustimmung zulässig |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// + Die Funktion printf_P() unterliegt ihrer eigenen Lizenz und ist hiervon nicht betroffen |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// + Redistributions of source code (with or without modifications) must retain the above copyright notice, |
// + this list of conditions and the following disclaimer. |
// + * Neither the name of the copyright holders nor the names of contributors may be used to endorse or promote products derived |
// + from this software without specific prior written permission. |
// + * The use of this project (hardware, software, binary files, sources and documentation) is only permittet |
// + for non-commercial use (directly or indirectly) |
// + Commercial use (for excample: selling of MikroKopters, selling of PCBs, assembly, ...) is only permitted |
// + with our written permission |
// + * If sources or documentations are redistributet on other webpages, out webpage (http://www.MikroKopter.de) must be |
// + clearly linked as origin |
// + * porting to systems other than hardware from www.mikrokopter.de is not allowed |
// + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
// + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
// + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
// + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
// + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
// + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
// + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
// + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
// + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
// + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// + POSSIBILITY OF SUCH DAMAGE. |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
#include <avr/boot.h> |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include "main.h" |
#include "timer0.h" |
#include "uart0.h" |
#include "uart1.h" |
#include "fat16.h" |
#include "led.h" |
#include "menu.h" |
#include "printf_P.h" |
int main (void) |
{ |
// disable interrupts global |
cli(); |
// disable watchdog |
MCUSR &=~(1<<WDRF); |
WDTCSR |= (1<<WDCE)|(1<<WDE); |
WDTCSR = 0; |
// initalize modules |
LED_Init(); |
TIMER0_Init(); |
USART0_Init(); |
USART1_Init(); |
// enable interrupts global |
sei(); |
#ifdef USE_SDLOGGER |
printf("\n\rHW: SD-Logger"); |
#endif |
#ifdef USE_FOLLOWME |
printf("\n\rHW: Follow-Me"); |
#endif |
printf("\n\rFollow Me\n\rSoftware:V%d.%d%c ",VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH + 'a'); |
printf("\n\r=============================="); |
printf("\n\r"); |
// try to initialize the SD-Card File system |
printf("\n\rInit FAT16..."); |
if(FAT16_Init()) |
{ |
printf("ok"); |
} |
else |
{ |
printf("failed"); |
} |
LCD_Clear(); |
while (1) |
{ |
USART0_ProcessRxData(); |
USART0_TransmitTxData(); |
} |
return (1); |
} |
/FollowMe/main.h |
---|
0,0 → 1,21 |
#ifndef _MAIN_H |
#define _MAIN_H |
#include <avr/io.h> |
/* |
#if defined (__AVR_ATmega644P__) |
#define SYSCLK 20000000L //crystal freqency in Hz |
#endif |
*/ |
#define SYSCLK F_CPU |
#endif //_MAIN_H |
/FollowMe/makefile |
---|
0,0 → 1,430 |
#-------------------------------------------------------------------- |
# MCU name |
MCU = atmega644p |
F_CPU = 20000000 |
#------------------------------------------------------------------- |
VERSION_MAJOR = 0 |
VERSION_MINOR = 1 |
VERSION_PATCH = 0 |
VERSION_SERIAL_MAJOR = 10 # Serial Protocol Major Version |
VERSION_SERIAL_MINOR = 0 # Serial Protocol Minor Version |
#------------------------------------------------------------------- |
#OPTIONS |
# Use one of the motor setups |
#BOARD = FOLLOWME |
BOARD = SDLOGGER |
#------------------------------------------------------------------- |
# get SVN revision |
REV := $(shell sh -c "cat .svn/entries | sed -n '4p'") |
ifeq ($(MCU), atmega644p) |
FUSE_SETTINGS = -u -U lfuse:w:0xff:m -U hfuse:w:0xdf:m |
HEX_NAME = MEGA644p_$(BOARD) |
endif |
ifeq ($(F_CPU), 20000000) |
QUARZ = 20MHZ |
endif |
# Output format. (can be srec, ihex, binary) |
FORMAT = ihex |
# Target file name (without extension). |
ifeq ($(VERSION_PATCH), 0) |
TARGET = FollowMe_$(HEX_NAME)_V$(VERSION_MAJOR)_$(VERSION_MINOR)a_SVN$(REV) |
endif |
ifeq ($(VERSION_PATCH), 1) |
TARGET = FollowMe_$(HEX_NAME)_V$(VERSION_MAJOR)_$(VERSION_MINOR)b_SVN$(REV) |
endif |
ifeq ($(VERSION_PATCH), 2) |
TARGET = FollowMe_$(HEX_NAME)_V$(VERSION_MAJOR)_$(VERSION_MINOR)c_SVN$(REV) |
endif |
ifeq ($(VERSION_PATCH), 3) |
TARGET = FollowMe_$(HEX_NAME)_V$(VERSION_MAJOR)_$(VERSION_MINOR)d_SVN$(REV) |
endif |
ifeq ($(VERSION_PATCH), 4) |
TARGET = FollowMe_$(HEX_NAME)_V$(VERSION_MAJOR)_$(VERSION_MINOR)e_SVN$(REV) |
endif |
ifeq ($(VERSION_PATCH), 5) |
TARGET = FollowMe_$(HEX_NAME)_V$(VERSION_MAJOR)_$(VERSION_MINOR)f_SVN$(REV) |
endif |
ifeq ($(VERSION_PATCH), 6) |
TARGET = FollowMe_$(HEX_NAME)_V$(VERSION_MAJOR)_$(VERSION_MINOR)g_SVN$(REV) |
endif |
ifeq ($(VERSION_PATCH), 7) |
TARGET = FollowMe_$(HEX_NAME)_V$(VERSION_MAJOR)_$(VERSION_MINOR)h_SVN$(REV) |
endif |
ifeq ($(VERSION_PATCH), 8) |
TARGET = FollowMe_$(HEX_NAME)_V$(VERSION_MAJOR)_$(VERSION_MINOR)i_SVN$(REV) |
endif |
ifeq ($(VERSION_PATCH), 9) |
TARGET = FollowMe_$(HEX_NAME)_V$(VERSION_MAJOR)_$(VERSION_MINOR)j_SVN$(REV) |
endif |
ifeq ($(VERSION_PATCH), 10) |
TARGET = FollowMe_$(HEX_NAME)_V$(VERSION_MAJOR)_$(VERSION_MINOR)k_SVN$(REV) |
endif |
# Optimization level, can be [0, 1, 2, 3, s]. 0 turns off optimization. |
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) |
OPT = s |
########################################################################################################## |
# List C source files here. (C dependencies are automatically generated.) |
SRC = main.c uart0.c uart1.c printf_P.c timer0.c menu.c led.c ubx.c ssc.c sdc.c fat16.c |
########################################################################################################## |
# List Assembler source files here. |
# Make them always end in a capital .S. Files ending in a lowercase .s |
# will not be considered source files but generated files (assembler |
# output from the compiler), and will be deleted upon "make clean"! |
# Even though the DOS/Win* filesystem matches both .s and .S the same, |
# it will preserve the spelling of the filenames, and gcc itself does |
# care about how the name is spelled on its command-line. |
ASRC = |
# List any extra directories to look for include files here. |
# Each directory must be seperated by a space. |
EXTRAINCDIRS = |
# Optional compiler flags. |
# -g: generate debugging information (for GDB, or for COFF conversion) |
# -O*: optimization level |
# -f...: tuning, see gcc manual and avr-libc documentation |
# -Wall...: warning level |
# -Wa,...: tell GCC to pass this to the assembler. |
# -ahlms: create assembler listing |
CFLAGS = -O$(OPT) \ |
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums \ |
-Wall -Wstrict-prototypes \ |
-Wa,-adhlns=$(<:.c=.lst) \ |
$(patsubst %,-I%,$(EXTRAINCDIRS)) |
# Set a "language standard" compiler flag. |
# Unremark just one line below to set the language standard to use. |
# gnu99 = C99 + GNU extensions. See GCC manual for more information. |
#CFLAGS += -std=c89 |
#CFLAGS += -std=gnu89 |
#CFLAGS += -std=c99 |
CFLAGS += -std=gnu99 |
CFLAGS += -DF_CPU=$(F_CPU) -DVERSION_MAJOR=$(VERSION_MAJOR) -DVERSION_MINOR=$(VERSION_MINOR) -DVERSION_PATCH=$(VERSION_PATCH) -DVERSION_SERIAL_MAJOR=$(VERSION_SERIAL_MAJOR) -DVERSION_SERIAL_MINOR=$(VERSION_SERIAL_MINOR) |
ifeq ($(BOARD), FOLLOWME) |
CFLAGS += -DUSE_FOLLOWME |
endif |
ifeq ($(BOARD), SDLOGGER) |
CFLAGS += -DUSE_SDLOGGER |
endif |
# Optional assembler flags. |
# -Wa,...: tell GCC to pass this to the assembler. |
# -ahlms: create listing |
# -gstabs: have the assembler create line number information; note that |
# for use in COFF files, additional information about filenames |
# and function names needs to be present in the assembler source |
# files -- see avr-libc docs [FIXME: not yet described there] |
ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs |
# Optional linker flags. |
# -Wl,...: tell GCC to pass this to linker. |
# -Map: create map file |
# --cref: add cross reference to map file |
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref |
# Additional libraries |
# Minimalistic printf version |
#LDFLAGS += -Wl,-u,vfprintf -lprintf_min |
# Floating point printf version (requires -lm below) |
#LDFLAGS += -Wl,-u,vfprintf -lprintf_flt |
# -lm = math library |
LDFLAGS += -lm |
##LDFLAGS += -T./linkerfile/avr5.x |
# Programming support using avrdude. Settings and variables. |
# Programming hardware: alf avr910 avrisp bascom bsd |
# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500 |
# |
# Type: avrdude -c ? |
# to get a full listing. |
# |
#AVRDUDE_PROGRAMMER = dt006 |
#AVRDUDE_PROGRAMMER = stk200 |
#AVRDUDE_PROGRAMMER = ponyser |
AVRDUDE_PROGRAMMER = avrispv2 |
#falls Ponyser ausgewählt wird, muss sich unsere avrdude-Configdatei im Bin-Verzeichnis des Compilers befinden |
#AVRDUDE_PORT = com1 # programmer connected to serial device |
#AVRDUDE_PORT = lpt1 # programmer connected to parallel port |
AVRDUDE_PORT = usb # programmer connected to USB |
#AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex |
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex $(FUSE_SETTINGS) |
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep |
#avrdude -c avrispv2 -P usb -p m32 -U flash:w:blink.hex |
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) |
# Uncomment the following if you want avrdude's erase cycle counter. |
# Note that this counter needs to be initialized first using -Yn, |
# see avrdude manual. |
#AVRDUDE_ERASE += -y |
# Uncomment the following if you do /not/ wish a verification to be |
# performed after programming the device. |
AVRDUDE_FLAGS += -V |
# Increase verbosity level. Please use this when submitting bug |
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude> |
# to submit bug reports. |
#AVRDUDE_FLAGS += -v -v |
# --------------------------------------------------------------------------- |
# Define directories, if needed. |
DIRAVR = c:/winavr |
DIRAVRBIN = $(DIRAVR)/bin |
DIRAVRUTILS = $(DIRAVR)/utils/bin |
DIRINC = . |
DIRLIB = $(DIRAVR)/avr/lib |
# Define programs and commands. |
SHELL = sh |
CC = avr-gcc |
OBJCOPY = avr-objcopy |
OBJDUMP = avr-objdump |
SIZE = avr-size |
# Programming support using avrdude. |
AVRDUDE = avrdude |
REMOVE = rm -f |
COPY = cp |
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex |
ELFSIZE = $(SIZE) -A $(TARGET).elf |
# Define Messages |
# English |
MSG_ERRORS_NONE = Errors: none |
MSG_BEGIN = -------- begin -------- |
MSG_END = -------- end -------- |
MSG_SIZE_BEFORE = Size before: |
MSG_SIZE_AFTER = Size after: |
MSG_COFF = Converting to AVR COFF: |
MSG_EXTENDED_COFF = Converting to AVR Extended COFF: |
MSG_FLASH = Creating load file for Flash: |
MSG_EEPROM = Creating load file for EEPROM: |
MSG_EXTENDED_LISTING = Creating Extended Listing: |
MSG_SYMBOL_TABLE = Creating Symbol Table: |
MSG_LINKING = Linking: |
MSG_COMPILING = Compiling: |
MSG_ASSEMBLING = Assembling: |
MSG_CLEANING = Cleaning project: |
# Define all object files. |
OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) |
# Define all listing files. |
LST = $(ASRC:.S=.lst) $(SRC:.c=.lst) |
# Combine all necessary flags and optional flags. |
# Add target processor to flags. |
#ALL_CFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU) -I. $(CFLAGS) |
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) |
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) |
# Default target. |
all: begin gccversion sizebefore $(TARGET).elf $(TARGET).hex $(TARGET).eep \ |
$(TARGET).lss $(TARGET).sym sizeafter finished end |
# Eye candy. |
# AVR Studio 3.x does not check make's exit code but relies on |
# the following magic strings to be generated by the compile job. |
begin: |
@echo |
@echo $(MSG_BEGIN) |
finished: |
@echo $(MSG_ERRORS_NONE) |
end: |
@echo $(MSG_END) |
@echo |
# Display size of file. |
sizebefore: |
@if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); echo; fi |
sizeafter: |
@if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); echo; fi |
# Display compiler version information. |
gccversion : |
@$(CC) --version |
# Convert ELF to COFF for use in debugging / simulating in |
# AVR Studio or VMLAB. |
COFFCONVERT=$(OBJCOPY) --debugging \ |
--change-section-address .data-0x800000 \ |
--change-section-address .bss-0x800000 \ |
--change-section-address .noinit-0x800000 \ |
--change-section-address .eeprom-0x810000 |
coff: $(TARGET).elf |
@echo |
@echo $(MSG_COFF) $(TARGET).cof |
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof |
extcoff: $(TARGET).elf |
@echo |
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof |
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof |
# Program the device. |
program: $(TARGET).hex $(TARGET).eep |
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) |
# Create final output files (.hex, .eep) from ELF output file. |
%.hex: %.elf |
@echo |
@echo $(MSG_FLASH) $@ |
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ |
%.eep: %.elf |
@echo |
@echo $(MSG_EEPROM) $@ |
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ |
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@ |
# Create extended listing file from ELF output file. |
%.lss: %.elf |
@echo |
@echo $(MSG_EXTENDED_LISTING) $@ |
$(OBJDUMP) -h -S $< > $@ |
# Create a symbol table from ELF output file. |
%.sym: %.elf |
@echo |
@echo $(MSG_SYMBOL_TABLE) $@ |
avr-nm -n $< > $@ |
# Link: create ELF output file from object files. |
.SECONDARY : $(TARGET).elf |
.PRECIOUS : $(OBJ) |
%.elf: $(OBJ) |
@echo |
@echo $(MSG_LINKING) $@ |
$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) |
# Compile: create object files from C source files. |
%.o : %.c |
@echo |
@echo $(MSG_COMPILING) $< |
$(CC) -c $(ALL_CFLAGS) $< -o $@ |
# Compile: create assembler files from C source files. |
%.s : %.c |
$(CC) -S $(ALL_CFLAGS) $< -o $@ |
# Assemble: create object files from assembler source files. |
%.o : %.S |
@echo |
@echo $(MSG_ASSEMBLING) $< |
$(CC) -c $(ALL_ASFLAGS) $< -o $@ |
# Target: clean project. |
clean: begin clean_list finished end |
clean_list : |
@echo |
@echo $(MSG_CLEANING) |
# $(REMOVE) $(TARGET).hex |
$(REMOVE) $(TARGET).eep |
$(REMOVE) $(TARGET).obj |
$(REMOVE) $(TARGET).cof |
$(REMOVE) $(TARGET).elf |
$(REMOVE) $(TARGET).map |
$(REMOVE) $(TARGET).obj |
$(REMOVE) $(TARGET).a90 |
$(REMOVE) $(TARGET).sym |
$(REMOVE) $(TARGET).lnk |
$(REMOVE) $(TARGET).lss |
$(REMOVE) $(OBJ) |
$(REMOVE) $(LST) |
$(REMOVE) $(SRC:.c=.s) |
$(REMOVE) $(SRC:.c=.d) |
# Automatically generate C source code dependencies. |
# (Code originally taken from the GNU make user manual and modified |
# (See README.txt Credits).) |
# |
# Note that this will work with sh (bash) and sed that is shipped with WinAVR |
# (see the SHELL variable defined above). |
# This may not work with other shells or other seds. |
# |
%.d: %.c |
set -e; $(CC) -MM $(ALL_CFLAGS) $< \ |
| sed 's,\(.*\)\.o[ :]*,\1.o \1.d : ,g' > $@; \ |
[ -s $@ ] || rm -f $@ |
# Remove the '-' if you want to see the dependency files generated. |
-include $(SRC:.c=.d) |
# Listing of phony targets. |
.PHONY : all begin finish end sizebefore sizeafter gccversion coff extcoff \ |
clean clean_list program |
/FollowMe/menu.c |
---|
0,0 → 1,129 |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// + Copyright (c) 04.2007 Holger Buss |
// + only for non-profit use |
// + www.MikroKopter.com |
// + see the File "License.txt" for further Informations |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
#include <stdlib.h> |
#include <inttypes.h> |
#include "main.h" |
#include "uart0.h" |
#include "printf_P.h" |
#include "ubx.h" |
uint8_t MaxMenuItem = 1; |
uint8_t MenuItem = 0; |
uint8_t RemoteKeys = 0; |
#define KEY1 0x01 |
#define KEY2 0x02 |
#define KEY3 0x04 |
#define KEY4 0x08 |
#define KEY5 0x10 |
#define DISPLAYBUFFSIZE 80 |
int8_t DisplayBuff[DISPLAYBUFFSIZE] = "Hello World"; |
uint8_t DispPtr = 0; |
/************************************/ |
/* Clear LCD Buffer */ |
/************************************/ |
void LCD_Clear(void) |
{ |
uint8_t i; |
for( i = 0; i < DISPLAYBUFFSIZE; i++) DisplayBuff[i] = ' '; |
} |
/************************************/ |
/* Update Menu on LCD */ |
/************************************/ |
// Display with 20 characters in 4 lines |
void LCD_PrintMenu(void) |
{ |
if(RemoteKeys & KEY1) |
{ |
if(MenuItem) MenuItem--; |
else MenuItem = MaxMenuItem; |
} |
if(RemoteKeys & KEY2) |
{ |
if(MenuItem == MaxMenuItem) MenuItem = 0; |
else MenuItem++; |
} |
if((RemoteKeys & KEY1) && (RemoteKeys & KEY2)) MenuItem = 0; |
LCD_Clear(); |
if(MenuItem > MaxMenuItem) MenuItem = MaxMenuItem; |
// print menu item number in the upper right corner |
if(MenuItem < 10) |
{ |
LCD_printfxy(17,0,"[%i]",MenuItem); |
} |
else |
{ |
LCD_printfxy(16,0,"[%i]",MenuItem); |
} |
switch(MenuItem) |
{ |
case 0:// Version Info Menu Item |
LCD_printfxy(0,0,"+ Follow Me +"); |
#ifdef USE_SDLOGGER |
LCD_printfxy(0,1,"HW: SD-Logger"); |
#endif |
#ifdef USE_FOLLOWME |
LCD_printfxy(0,1,"HW: Follow-Me"); |
#endif |
LCD_printfxy(0,2,"SW: %d.%d%c", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH+'a'); |
LCD_printfxy(0,3," "); |
break; |
case 1://GPS Lat/Lon coords |
if (GPSInfo.status == INVALID) |
{ |
LCD_printfxy(0,0,"No GPS data!"); |
} |
else |
{ |
switch (GPSInfo.satfix) |
{ |
case SATFIX_NONE: |
LCD_printfxy(0,0,"Sats: %d Fix: No", GPSInfo.satnum); |
break; |
case SATFIX_2D: |
LCD_printfxy(0,0,"Sats: %d Fix: 2D", GPSInfo.satnum); |
break; |
case SATFIX_3D: |
LCD_printfxy(0,0,"Sats: %d Fix: 3D", GPSInfo.satnum); |
break; |
default: |
LCD_printfxy(0,0,"Sats: %d Fix: ??", GPSInfo.satnum); |
break; |
} |
int16_t i1,i2,i3; |
i1 = (int16_t)(GPSInfo.longitude/10000000L); |
i2 = abs((int16_t)((GPSInfo.longitude%10000000L)/10000L)); |
i3 = abs((int16_t)(((GPSInfo.longitude%10000000L)%10000L)/10L)); |
LCD_printfxy(0,1,"Lon: %d.%.3d%.3d deg",i1, i2, i3); |
i1 = (int16_t)(GPSInfo.latitude/10000000L); |
i2 = abs((int16_t)((GPSInfo.latitude%10000000L)/10000L)); |
i3 = abs((int16_t)(((GPSInfo.latitude%10000000L)%10000L)/10L)); |
LCD_printfxy(0,2,"Lat: %d.%.3d%.3d deg",i1, i2, i3); |
i1 = (int16_t)(GPSInfo.altitude/1000L); |
i2 = abs((int16_t)(GPSInfo.altitude%1000L)); |
LCD_printfxy(0,3,"Alt: %d.%.3d m",i1, i2); |
} |
break; |
default: MaxMenuItem = MenuItem - 1; |
MenuItem = 0; |
break; |
} |
RemoteKeys = 0; |
} |
/FollowMe/menu.h |
---|
0,0 → 1,17 |
#ifndef _MENU_H |
#define _MENU_H |
#include <inttypes.h> |
#define DISPLAYBUFFSIZE 80 |
extern void LCD_PrintMenu(void); |
extern void LCD_Clear(void); |
extern int8_t DisplayBuff[DISPLAYBUFFSIZE]; |
extern uint8_t DispPtr; |
extern uint8_t MenuItem; |
extern uint8_t MaxMenuItem; |
extern uint8_t RemoteKeys; |
#endif //_MENU_H |
/FollowMe/old_macros.h |
---|
0,0 → 1,47 |
/* |
For backwards compatibility only. |
Ingo Busker ingo@mikrocontroller.com |
*/ |
#ifndef cbi |
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) |
#endif |
#ifndef sbi |
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) |
#endif |
#ifndef inb |
#define inb(sfr) _SFR_BYTE(sfr) |
#endif |
#ifndef outb |
#define outb(sfr, val) (_SFR_BYTE(sfr) = (val)) |
#endif |
#ifndef inw |
#define inw(sfr) _SFR_WORD(sfr) |
#endif |
#ifndef outw |
#define outw(sfr, val) (_SFR_WORD(sfr) = (val)) |
#endif |
#ifndef outp |
#define outp(val, sfr) outb(sfr, val) |
#endif |
#ifndef inp |
#define inp(sfr) inb(sfr) |
#endif |
#ifndef BV |
#define BV(bit) _BV(bit) |
#endif |
#ifndef PRG_RDB |
#define PRG_RDB pgm_read_byte |
#endif |
/FollowMe/printf_P.c |
---|
0,0 → 1,483 |
// Die Funktion printf_P() unterliegt ihrer eigenen Lizenz und ist nicht von der Lizenz für den MikroKopter-Teil unterstellt |
/* |
Copyright (C) 1993 Free Software Foundation |
This file is part of the GNU IO Library. This library is free |
software; you can redistribute it and/or modify it under the |
terms of the GNU General Public License as published by the |
Free Software Foundation; either version 2, or (at your option) |
any later version. |
This library is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this library; see the file COPYING. If not, write to the Free |
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
As a special exception, if you link this library with files |
compiled with a GNU compiler to produce an executable, this does not cause |
the resulting executable to be covered by the GNU General Public License. |
This exception does not however invalidate any other reasons why |
the executable file might be covered by the GNU General Public License. */ |
/* |
* Copyright (c) 1990 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. [rescinded 22 July 1999] |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
/****************************************************************************** |
This file is a patched version of printf called _printf_P |
It is made to work with avr-gcc for Atmel AVR MCUs. |
There are some differences from standard printf: |
1. There is no floating point support (with fp the code is about 8K!) |
2. Return type is void |
3. Format string must be in program memory (by using macro printf this is |
done automaticaly) |
4. %n is not implemented (just remove the comment around it if you need it) |
5. If LIGHTPRINTF is defined, the code is about 550 bytes smaller and the |
folowing specifiers are disabled : |
space # * . - + p s o O |
6. A function void uart_sendchar(char c) is used for output. The UART must |
be initialized before using printf. |
Alexander Popov |
sasho@vip.orbitel.bg |
******************************************************************************/ |
/* |
* Actual printf innards. |
* |
* This code is large and complicated... |
*/ |
#include <string.h> |
#ifdef __STDC__ |
#include <stdarg.h> |
#else |
#include <varargs.h> |
#endif |
#include "old_macros.h" |
#include "printf_P.h" |
#include "menu.h" |
#include "uart0.h" |
//#define LIGHTPRINTF |
char PrintZiel; |
char Putchar(char zeichen) |
{ |
if(PrintZiel == OUT_LCD) { DisplayBuff[DispPtr++] = zeichen; return(1);} |
else return(uart_putchar(zeichen)); |
} |
void PRINT(const char * ptr, unsigned int len) |
{ |
for(;len;len--) Putchar(*ptr++); |
} |
void PRINTP(const char * ptr, unsigned int len) |
{ |
for(;len;len--) Putchar(pgm_read_byte(ptr++)); |
} |
void PAD_SP(signed char howmany) |
{ |
for(;howmany>0;howmany--) Putchar(' '); |
} |
void PAD_0(signed char howmany) |
{ |
for(;howmany>0;howmany--) Putchar('0'); |
} |
#define BUF 40 |
/* |
* Macros for converting digits to letters and vice versa |
*/ |
#define to_digit(c) ((c) - '0') |
#define is_digit(c) ((c)<='9' && (c)>='0') |
#define to_char(n) ((n) + '0') |
/* |
* Flags used during conversion. |
*/ |
#define LONGINT 0x01 /* long integer */ |
#define LONGDBL 0x02 /* long double; unimplemented */ |
#define SHORTINT 0x04 /* short integer */ |
#define ALT 0x08 /* alternate form */ |
#define LADJUST 0x10 /* left adjustment */ |
#define ZEROPAD 0x20 /* zero (as opposed to blank) pad */ |
#define HEXPREFIX 0x40 /* add 0x or 0X prefix */ |
void _printf_P (char ziel,char const *fmt0, ...) /* Works with string from FLASH */ |
{ |
va_list ap; |
register const char *fmt; /* format string */ |
register char ch; /* character from fmt */ |
register int n; /* handy integer (short term usage) */ |
register char *cp; /* handy char pointer (short term usage) */ |
const char *fmark; /* for remembering a place in fmt */ |
register unsigned char flags; /* flags as above */ |
signed char width; /* width from format (%8d), or 0 */ |
signed char prec; /* precision from format (%.3d), or -1 */ |
char sign; /* sign prefix (' ', '+', '-', or \0) */ |
unsigned long _ulong=0; /* integer arguments %[diouxX] */ |
#define OCT 8 |
#define DEC 10 |
#define HEX 16 |
unsigned char base; /* base for [diouxX] conversion */ |
signed char dprec; /* a copy of prec if [diouxX], 0 otherwise */ |
signed char dpad; /* extra 0 padding needed for integers */ |
signed char fieldsz; /* field size expanded by sign, dpad etc */ |
/* The initialization of 'size' is to suppress a warning that |
'size' might be used unitialized. It seems gcc can't |
quite grok this spaghetti code ... */ |
signed char size = 0; /* size of converted field or string */ |
char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ |
char ox[2]; /* space for 0x hex-prefix */ |
PrintZiel = ziel; // bestimmt, LCD oder UART |
va_start(ap, fmt0); |
fmt = fmt0; |
/* |
* Scan the format for conversions (`%' character). |
*/ |
for (;;) { |
for (fmark = fmt; (ch = pgm_read_byte(fmt)) != '\0' && ch != '%'; fmt++) |
/* void */; |
if ((n = fmt - fmark) != 0) { |
PRINTP(fmark, n); |
} |
if (ch == '\0') |
goto done; |
fmt++; /* skip over '%' */ |
flags = 0; |
dprec = 0; |
width = 0; |
prec = -1; |
sign = '\0'; |
rflag: ch = PRG_RDB(fmt++); |
reswitch: |
#ifdef LIGHTPRINTF |
if (ch=='o' || ch=='u' || (ch|0x20)=='x') { |
#else |
if (ch=='u' || (ch|0x20)=='x') { |
#endif |
if (flags&LONGINT) { |
_ulong=va_arg(ap, unsigned long); |
} else { |
register unsigned int _d; |
_d=va_arg(ap, unsigned int); |
_ulong = flags&SHORTINT ? (unsigned long)(unsigned short)_d : (unsigned long)_d; |
} |
} |
#ifndef LIGHTPRINTF |
if(ch==' ') { |
/* |
* ``If the space and + flags both appear, the space |
* flag will be ignored.'' |
* -- ANSI X3J11 |
*/ |
if (!sign) |
sign = ' '; |
goto rflag; |
} else if (ch=='#') { |
flags |= ALT; |
goto rflag; |
} else if (ch=='*'||ch=='-') { |
if (ch=='*') { |
/* |
* ``A negative field width argument is taken as a |
* - flag followed by a positive field width.'' |
* -- ANSI X3J11 |
* They don't exclude field widths read from args. |
*/ |
if ((width = va_arg(ap, int)) >= 0) |
goto rflag; |
width = -width; |
} |
flags |= LADJUST; |
flags &= ~ZEROPAD; /* '-' disables '0' */ |
goto rflag; |
} else if (ch=='+') { |
sign = '+'; |
goto rflag; |
} else if (ch=='.') { |
if ((ch = PRG_RDB(fmt++)) == '*') { |
n = va_arg(ap, int); |
prec = n < 0 ? -1 : n; |
goto rflag; |
} |
n = 0; |
while (is_digit(ch)) { |
n = n*10 + to_digit(ch); |
ch = PRG_RDB(fmt++); |
} |
prec = n < 0 ? -1 : n; |
goto reswitch; |
} else |
#endif /* LIGHTPRINTF */ |
if (ch=='0') { |
/* |
* ``Note that 0 is taken as a flag, not as the |
* beginning of a field width.'' |
* -- ANSI X3J11 |
*/ |
if (!(flags & LADJUST)) |
flags |= ZEROPAD; /* '-' disables '0' */ |
goto rflag; |
} else if (ch>='1' && ch<='9') { |
n = 0; |
do { |
n = 10 * n + to_digit(ch); |
ch = PRG_RDB(fmt++); |
} while (is_digit(ch)); |
width = n; |
goto reswitch; |
} else if (ch=='h') { |
flags |= SHORTINT; |
goto rflag; |
} else if (ch=='l') { |
flags |= LONGINT; |
goto rflag; |
} else if (ch=='c') { |
*(cp = buf) = va_arg(ap, int); |
size = 1; |
sign = '\0'; |
} else if (ch=='D'||ch=='d'||ch=='i') { |
if(ch=='D') |
flags |= LONGINT; |
if (flags&LONGINT) { |
_ulong=va_arg(ap, long); |
} else { |
register int _d; |
_d=va_arg(ap, int); |
_ulong = flags&SHORTINT ? (long)(short)_d : (long)_d; |
} |
if ((long)_ulong < 0) { |
_ulong = -_ulong; |
sign = '-'; |
} |
base = DEC; |
goto number; |
} else |
/* |
if (ch=='n') { |
if (flags & LONGINT) |
*va_arg(ap, long *) = ret; |
else if (flags & SHORTINT) |
*va_arg(ap, short *) = ret; |
else |
*va_arg(ap, int *) = ret; |
continue; // no output |
} else |
*/ |
#ifndef LIGHTPRINTF |
if (ch=='O'||ch=='o') { |
if (ch=='O') |
flags |= LONGINT; |
base = OCT; |
goto nosign; |
} else if (ch=='p') { |
/* |
* ``The argument shall be a pointer to void. The |
* value of the pointer is converted to a sequence |
* of printable characters, in an implementation- |
* defined manner.'' |
* -- ANSI X3J11 |
*/ |
/* NOSTRICT */ |
_ulong = (unsigned int)va_arg(ap, void *); |
base = HEX; |
flags |= HEXPREFIX; |
ch = 'x'; |
goto nosign; |
} else if (ch=='s') { // print a string from RAM |
if ((cp = va_arg(ap, char *)) == NULL) { |
cp=buf; |
cp[0] = '('; |
cp[1] = 'n'; |
cp[2] = 'u'; |
cp[4] = cp[3] = 'l'; |
cp[5] = ')'; |
cp[6] = '\0'; |
} |
if (prec >= 0) { |
/* |
* can't use strlen; can only look for the |
* NUL in the first `prec' characters, and |
* strlen() will go further. |
*/ |
char *p = (char*)memchr(cp, 0, prec); |
if (p != NULL) { |
size = p - cp; |
if (size > prec) |
size = prec; |
} else |
size = prec; |
} else |
size = strlen(cp); |
sign = '\0'; |
} else |
#endif /* LIGHTPRINTF */ |
if(ch=='U'||ch=='u') { |
if (ch=='U') |
flags |= LONGINT; |
base = DEC; |
goto nosign; |
} else if (ch=='X'||ch=='x') { |
base = HEX; |
/* leading 0x/X only if non-zero */ |
if (flags & ALT && _ulong != 0) |
flags |= HEXPREFIX; |
/* unsigned conversions */ |
nosign: sign = '\0'; |
/* |
* ``... diouXx conversions ... if a precision is |
* specified, the 0 flag will be ignored.'' |
* -- ANSI X3J11 |
*/ |
number: if ((dprec = prec) >= 0) |
flags &= ~ZEROPAD; |
/* |
* ``The result of converting a zero value with an |
* explicit precision of zero is no characters.'' |
* -- ANSI X3J11 |
*/ |
cp = buf + BUF; |
if (_ulong != 0 || prec != 0) { |
register unsigned char _d,notlastdigit; |
do { |
notlastdigit=(_ulong>=base); |
_d = _ulong % base; |
if (_d<10) { |
_d+='0'; |
} else { |
_d+='a'-10; |
if (ch=='X') _d&=~0x20; |
} |
*--cp=_d; |
_ulong /= base; |
} while (notlastdigit); |
#ifndef LIGHTPRINTF |
// handle octal leading 0 |
if (base==OCT && flags & ALT && *cp != '0') |
*--cp = '0'; |
#endif |
} |
size = buf + BUF - cp; |
} else { //default |
/* "%?" prints ?, unless ? is NUL */ |
if (ch == '\0') |
goto done; |
/* pretend it was %c with argument ch */ |
cp = buf; |
*cp = ch; |
size = 1; |
sign = '\0'; |
} |
/* |
* All reasonable formats wind up here. At this point, |
* `cp' points to a string which (if not flags&LADJUST) |
* should be padded out to `width' places. If |
* flags&ZEROPAD, it should first be prefixed by any |
* sign or other prefix; otherwise, it should be blank |
* padded before the prefix is emitted. After any |
* left-hand padding and prefixing, emit zeroes |
* required by a decimal [diouxX] precision, then print |
* the string proper, then emit zeroes required by any |
* leftover floating precision; finally, if LADJUST, |
* pad with blanks. |
*/ |
/* |
* compute actual size, so we know how much to pad. |
*/ |
fieldsz = size; |
dpad = dprec - size; |
if (dpad < 0) |
dpad = 0; |
if (sign) |
fieldsz++; |
else if (flags & HEXPREFIX) |
fieldsz += 2; |
fieldsz += dpad; |
/* right-adjusting blank padding */ |
if ((flags & (LADJUST|ZEROPAD)) == 0) |
PAD_SP(width - fieldsz); |
/* prefix */ |
if (sign) { |
PRINT(&sign, 1); |
} else if (flags & HEXPREFIX) { |
ox[0] = '0'; |
ox[1] = ch; |
PRINT(ox, 2); |
} |
/* right-adjusting zero padding */ |
if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) |
PAD_0(width - fieldsz); |
/* leading zeroes from decimal precision */ |
PAD_0(dpad); |
/* the string or number proper */ |
PRINT(cp, size); |
/* left-adjusting padding (always blank) */ |
if (flags & LADJUST) |
PAD_SP(width - fieldsz); |
} |
done: |
va_end(ap); |
} |
/FollowMe/printf_P.h |
---|
0,0 → 1,19 |
#ifndef _PRINTF_P_H_ |
#define _PRINTF_P_H_ |
#include <avr/pgmspace.h> |
#define OUT_V24 0 |
#define OUT_LCD 1 |
void _printf_P (char, char const *fmt0, ...); |
extern char PrintZiel; |
#define printf_P(format, args...) _printf_P(OUT_V24,format , ## args) |
#define printf(format, args...) _printf_P(OUT_V24,PSTR(format) , ## args) |
#define LCD_printfxy(x,y,format, args...) { DispPtr = y * 20 + x; _printf_P(OUT_LCD,PSTR(format) , ## args);} |
#define LCD_printf(format, args...) { _printf_P(OUT_LCD,PSTR(format) , ## args);} |
#endif |
/FollowMe/sdc.c |
---|
0,0 → 1,254 |
#include <avr/io.h> |
#include <util/delay.h> |
#include "fat16.h" |
#include "sdc.h" |
#include "ssc.h" |
//________________________________________________________________________________________________________________________________________ |
// Module name: mmc.c |
// Compiler used: avr-gcc 3.4.5 |
// Last Modifikation: 24.07.2007 |
// Version: 1.05 |
// Authors: Stephan Busker |
// Description: Source files for connecting to an sdcard using the SSC |
// |
//........................................................................................................................................ |
// Functions: u8 SDC_init(void); |
// u8 SDC_PutCommand (u8*CMD); |
// u8 SDC_PutSector(u32 addr,u8*Buffer); |
// u8 SDC_GetSector(u32 addr,u8*Buffer); |
// void SDC_GetBlock(u8*CMD,u8*Buffer,u16 Bytes); |
// |
////........................................................................................................................................ |
// ext. functions: extern void SSC_Init(void); |
// extern u8 SSC_GetChar (void); |
// extern void SSC_PutChar (u8); |
// extern void SSC_Enable(void); |
// extern void SSC_Disable(void); |
//........................................................................................................................................ |
// |
// URL: www.Mikro-Control.de |
// mailto: stephan.busker@mikro-control.de |
//________________________________________________________________________________________________________________________________________ |
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_Init(void); |
// |
// Description: This function initialises the SDCard to spi-mode. |
// |
// |
// Returnvalue: the function returns 0 if the initialisation was successfull otherwise the function returns an errorcode. |
//________________________________________________________________________________________________________________________________________ |
u8 SDC_Init(void) |
{ |
u8 Timeout = 0; |
u8 CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95}; |
u16 a = 0; |
u8 b = 0; |
SSC_Init(); // Initialise SSC to transmit data to the sdcard. |
_delay_ms(10); // before initialising the sdcard wait for 10ms |
for (b=0;b<0x0f;b++) // sending 74Clocks brings the sdcard into spimode. |
{ |
_delay_us(1); // wait at least 1us between the characters. |
SSC_PutChar(0xff); |
} |
while(SDC_PutCommand (CMD) !=1) // Sending CMD0 (Reset) to the sdcard. |
{ |
if (Timeout++ > 200) |
{ |
return(1); |
} |
} |
Timeout = 0; |
CMD[0] = 0x41; |
CMD[5] = 0xFF; |
while( SDC_PutCommand (CMD) !=0) // Sending CMD1 to the sdcard. |
{ |
if (Timeout++ > 100) |
{ |
return(2); |
} |
} |
SSC_Disable(); // disable sdcard. |
return(0); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_PutCommand(* CMD); |
// |
// Description: This function initialises the SDCard to spi-mode. |
// |
// |
// Returnvalue: the function returns 0 if the initialisation was successfull otherwise the function returns an errorcode. |
//________________________________________________________________________________________________________________________________________ |
u8 SDC_PutCommand (u8*CMD) |
{ |
u8 tmp = 0xff; |
u8 Timeout = 0; |
u16 a = 0; |
#ifdef SSC_RX_FIFO |
SSC_ClearRxFifo(); |
#endif |
SSC_Disable(); // disable chipselect |
SSC_PutChar(0xFF); // Send 8 Clocks to the sdcard while card is not selected. |
SSC_Enable(); // enable chipselect. |
if (*CMD == 0x41) _delay_ms(10); // if command is CMD0 generate a short delay. |
for (a = 0;a<0x06;a++) // send the command sequence to the sdcard (6 bytes) |
{ |
SSC_PutChar(*CMD++); |
} |
#ifdef SSC_RX_FIFO |
SSC_ClearRxFifo(); |
#endif |
while (tmp == 0xff) // Wait for response from sdcard. |
{ |
tmp = SSC_GetChar(); |
if (Timeout++ > 100) |
{ |
break; // or timeout. |
} |
} |
return(tmp); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_PutSector(void); |
// |
// Description: This function writes one sector of data to the SSC |
// |
// |
// Returnvalue: none |
//________________________________________________________________________________________________________________________________________ |
u8 SDC_PutSector(u32 addr,u8*Buffer) |
{ |
u8 tmp; |
u8 CMD[] = {0x58,0x00,0x00,0x00,0x00,0xFF}; |
addr = addr << 9; // convert sectoradress to byteadress |
CMD[1] = ((addr & 0xFF000000) >>24 ); |
CMD[2] = ((addr & 0x00FF0000) >>16 ); |
CMD[3] = ((addr & 0x0000FF00) >>8 ); |
tmp = SDC_PutCommand (CMD); // send command to sdcard. |
if (tmp != 0) |
{ |
return(tmp); |
} |
#ifdef SSC_RX_FIFO |
SSC_ClearRxFifo(); |
#endif |
for (u8 a=0;a<100;a++) // wait until sdcard is ready |
{ |
SSC_GetChar(); |
} |
SSC_PutChar(0xFE); // send start of header to the SSC |
for (u16 a=0;a<512;a++) // transmitt one sector (normaly 512bytes) of data to the sdcard. |
{ |
SSC_PutChar(*Buffer++); |
} |
SSC_PutChar(0xFF); // write two bytes of crc to the sdcard (not used in spi-mode) |
SSC_PutChar(0xFF); |
#ifdef SSC_RX_FIFO |
SSC_ClearRxFifo(); |
#endif |
while (SSC_GetChar() != 0xff){}; // wait untile the sdcard is ready. |
SSC_Disable(); // disable sdcard. |
return(0); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_GetSector(u32 addr,u8*Buffer); |
// |
// Description: This function reads one sector of data from the SSC |
// |
// |
// Returnvalue: none |
//________________________________________________________________________________________________________________________________________ |
u8 SDC_GetSector(u32 addr,u8*Buffer) |
{ |
u8 CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF}; |
addr = addr << 9; // convert sectoradress to byteadress. |
CMD[1] = ((addr & 0xFF000000) >>24 ); |
CMD[2] = ((addr & 0x00FF0000) >>16 ); |
CMD[3] = ((addr & 0x0000FF00) >>8 ); |
SDC_GetBlock(CMD,Buffer,512); // read specified sector from sdcard. |
return(0); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_GetBlock(void); |
// |
// Description: This function reads one block of data of s16 bytes from the SSC. |
// |
// |
// Returnvalue: the function returns 0 if the initialisation was successfull otherwise the function returns an errorcode. |
//________________________________________________________________________________________________________________________________________ |
void SDC_GetBlock(u8*CMD,u8*Buffer,u16 Bytes) |
{ |
if (SDC_PutCommand (CMD) != 0) // Send command to the sdcard. |
{ |
return; |
} |
#ifdef SSC_RX_FIFO |
SSC_ClearRxFifo(); |
#endif |
while (SSC_GetChar() != 0xfe){}; // wait until the sdcard is ready to transmitt data. |
for (u16 a=0;a<Bytes;a++) // read the block from the SSC (normaly 512Bytes) |
{ |
*Buffer++ = SSC_GetChar(); |
} |
SSC_GetChar(); // Read two bytes CRC- checksum (not used in spi-mode) |
SSC_GetChar(); |
SSC_Disable(); // disable sdcard. |
} |
/FollowMe/sdc.h |
---|
0,0 → 1,33 |
#ifndef _SDC_H_ |
#define _SDC_H_ |
extern u8 SDC_Init(void); |
//________________________________________________________________________________________________________________________________________ |
// |
// Functions needed for access to the sdcard. |
// |
//________________________________________________________________________________________________________________________________________ |
extern u8 SSC_GetChar(void); |
extern void SSC_PutChar(u8); |
extern void MMC_Read_Block(u8 *,u8 *,u16); |
//________________________________________________________________________________________________________________________________________ |
// |
// Functions needed internaly for the fat16 implementation |
// |
//________________________________________________________________________________________________________________________________________ |
extern u8 SDC_GetSector (u32,u8 *); |
extern u8 SDC_PutSector (u32,u8 *); |
extern u8 SDC_PutCommand (u8 *); |
extern void SDC_GetBlock(u8 *CMD,u8 *Buffer,u16 Bytes); |
#define nop() __asm__ __volatile__ ("nop" ::) |
#endif |
/FollowMe/ssc.c |
---|
0,0 → 1,166 |
#include <avr/io.h> |
#include "fat16.h" |
#include "ssc.h" |
//________________________________________________________________________________________________________________________________________ |
// Module name: fat16.c |
// Compiler used: avr-gcc 3.4.5 |
// Last Modifikation: 24.07.2007 |
// Version: 1.03 |
// Authors: Stephan Busker |
// Description: Source files for access to the synchrnous serial channel. |
// Copyright (C) 2007 Stephan Busker |
//........................................................................................................................................ |
// Functions: extern void SSC_Init(void); |
// extern u8 SSC_GetChar (void); |
// extern void SSC_PutChar (u8 Byte); |
// extern void SSC_Disable(void); |
// extern void SSC_Enable(void); |
//........................................................................................................................................ |
// ext. functions: extern u8 SDC_GetSector (u32,u8*); |
// extern u8 SDC_PutSector (u32,u8*); |
//........................................................................................................................................ |
// |
// URL: www.Mikro-Control.de |
// mailto: stephan.busker@mikro-control.de |
//________________________________________________________________________________________________________________________________________ |
//________________________________________________________________________________________________________________________________________ |
// Funtion: SSC_Init(void); |
// |
// Description: This function initialises the synchronus serial channel to the sdcard. |
// |
// |
// Returnvalue: none |
//________________________________________________________________________________________________________________________________________ |
void SSC_Init(void) |
{ |
MMC_Direction_REG &=~(1<<SPI_DI); // Set the direction of the ssc-port |
MMC_Direction_REG |= (1<<SPI_Clock); // _______ _______ |
MMC_Direction_REG |= (1<<SPI_DO); // CS \________________________/ |
MMC_Direction_REG |= (1<<MMC_Chip_Select); // |
MMC_Direction_REG |= (1<<SPI_SS); // ___ ___ ___ |
// clk __________/ \___/ \___/ \_________ |
// |
SSC_Disable(); // ___ ___ |
// data_________/ \___________/ \___________ |
// initialise ssc, clock = Idel low |
// devide clock by 32 |
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<CPOL); // Enable SSC in mastermode, invert clockpolarity (idle high) |
SPSR = SPSR|(1<<SPI2X); |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: void SSC_ClearRxFifo(void); |
// |
// Description: Clears the fifo of the ssc if the controller used has a builtin fifo. |
// |
// |
// Returnvalue: none |
//________________________________________________________________________________________________________________________________________ |
void SSC_ClearRxFifo(void) |
{ |
// enter your code here to clear the rx-fifo of the ssc. |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: SSC_GetChar(void); |
// |
// Description: This function reads one byte from the SSC |
// |
// |
// Returnvalue: the byte received. |
//________________________________________________________________________________________________________________________________________ |
u8 SSC_GetChar (void) |
{ |
u8 Byte = 0; |
SPDR = 0x00; // read one byte of data from the SSC |
while(!(SPSR & (1<<SPIF))){}; // wait until the data has been read. |
Byte = SPDR; |
#ifdef __MMC_INTERFACE_INVERTED |
return (~Byte); |
#else |
return (Byte); // the byte received |
#endif |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: SSC_PutChar(u8 Byte); |
// |
// Description: This function writes one byte to the SSC |
// |
// |
// Returnvalue: none |
//________________________________________________________________________________________________________________________________________ |
void SSC_PutChar (u8 Byte) |
{ |
#ifdef __MMC_INTERFACE_INVERTED |
SPDR = ~Byte; // send one byte of data to the SSC |
#else |
SPDR = Byte; // send one byte of data to the SSC |
#endif |
SPDR = ~Byte; // send one byte of data to the SSC |
while(!(SPSR & (1<<SPIF))) // wait until data was send. |
{ |
} |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: SSC_Disable(void); |
// |
// Description: This function enables chipselect of the sdcard (active low) |
// |
// |
// Returnvalue: none |
//________________________________________________________________________________________________________________________________________ |
void SSC_Disable(void) |
{ |
#ifdef __MMC_INTERFACE_INVERTED |
MMC_Write &= ~(1<<MMC_Chip_Select); // disable chipselect of the sdcard (active low). |
#else |
MMC_Write |= (1<<MMC_Chip_Select); // enable chipselect of the sdcard (active low). |
#endif |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: SSC_Enable(void); |
// |
// Description: This function disables chipselect of the sdcard (active low) |
// |
// |
// Returnvalue: none |
//________________________________________________________________________________________________________________________________________ |
void SSC_Enable(void) |
{ |
#ifdef __MMC_INTERFACE_INVERTED |
MMC_Write |= (1<<MMC_Chip_Select); // enable chipselect of the sdcard (active low). |
#else |
MMC_Write &= ~(1<<MMC_Chip_Select); // disable chipselect of the sdcard (active low). |
#endif |
} |
/FollowMe/ssc.h |
---|
0,0 → 1,42 |
#ifndef __SSC_H |
#define __SSC_H |
//-------------------------------------- Hardware specific definitions -------------------------------------- |
#define MMC_Write PORTB //Port an der die MMC/SD-card angeschlossen ist (SPI Port) |
#define MMC_Read PINB |
#define MMC_Direction_REG DDRB |
#ifdef USE_SDLOGGER |
#define __MMC_INTERFACE_INVERTED // the interface between the controller and the MMC/SD-card uses an inverting leveltranslator (transistorinverter) |
#endif // and therefore the signals to or from the memorycard have to be inverted. |
#ifdef USE_FOLLOWME // uses resitors, therefore its not inverted |
//#define __MMC_INTERFACE_INVERTED // the interface between the controller and the MMC/SD-card uses an inverting leveltranslator (transistorinverter) |
#endif |
#define SPI_DI 6 //Port Pin that is connected to the DO of the MMC/SD-card |
#define SPI_DO 5 //Port Pin that is connected to DI of the MMC/SD-card |
#define SPI_Clock 7 //Port Pin that is connected the CLK of the MMC/SD-card |
#define SPI_SS 4 //Slave Select is not used in SPI Master Mode, but must be defined |
#define MMC_Chip_Select 4 //Port Pin an dem Chip Select der MMC/SD-Karte angeschlossen ist |
//________________________________________________________________________________________________________________________________________ |
// |
// Functions needed for accessing the sdcard. |
// |
//________________________________________________________________________________________________________________________________________ |
extern void SSC_Init(void); |
extern u8 SSC_GetChar (void); |
extern void SSC_PutChar (u8); |
extern void SSC_Enable(void); |
extern void SSC_Disable(void); |
extern void SSC_ClearRxFifo(void); |
#endif |
/FollowMe/timer0.c |
---|
0,0 → 1,92 |
#include <inttypes.h> |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include "main.h" |
volatile uint16_t CountMilliseconds = 0; |
/*****************************************************/ |
/* Initialize Timer 0 */ |
/*****************************************************/ |
// timer 0 is used for the PWM generation to control the offset voltage at the air pressure sensor |
// Its overflow interrupt routine is used to generate the beep signal and the flight control motor update rate |
void TIMER0_Init(void) |
{ |
uint8_t sreg = SREG; |
// disable all interrupts before reconfiguration |
cli(); |
// Timer/Counter 0 Control Register A |
// Waveform Generation Mode is Fast PWM (Bits WGM02 = 0, WGM01 = 1, WGM00 = 1) |
// Clear OC0A on Compare Match, set OC0A at BOTTOM, noninverting PWM (Bits COM0A1 = 1, COM0A0 = 0) |
// Clear OC0B on Compare Match, set OC0B at BOTTOM, (Bits COM0B1 = 1, COM0B0 = 0) |
TCCR0A &= ~((1<<COM0A0)|(1<<COM0B0)); |
TCCR0A |= (1<<COM0A1)|(1<<COM0B1)|(1<<WGM01)|(1<<WGM00); |
// Timer/Counter 0 Control Register B |
// set clock devider for timer 0 to SYSKLOCK/8 = 20MHz / 8 = 2.5MHz |
// i.e. the timer increments from 0x00 to 0xFF with an update rate of 2.5 MHz |
// hence the timer overflow interrupt frequency is 2.5 MHz / 256 = 9.765 kHz |
// divider 8 (Bits CS02 = 0, CS01 = 1, CS00 = 0) |
TCCR0B &= ~((1<<FOC0A)|(1<<FOC0B)|(1<<WGM02)); |
TCCR0B = (TCCR0B & 0xF8)|(0<<CS02)|(1<<CS01)|(0<<CS00); |
// initialize the Output Compare Register A & B used for PWM generation on port PB3 & PB4 |
OCR0A = 0; // for PB3 |
OCR0B = 120; // for PB4 |
// init Timer/Counter 0 Register |
TCNT0 = 0; |
// Timer/Counter 0 Interrupt Mask Register |
// enable timer overflow interrupt only |
TIMSK0 &= ~((1<<OCIE0B)|(1<<OCIE0A)); |
TIMSK0 |= (1<<TOIE0); |
SREG = sreg; |
} |
/*****************************************************/ |
/* Interrupt Routine of Timer 0 */ |
/*****************************************************/ |
ISR(TIMER0_OVF_vect) // 9.765 kHz |
{ |
static uint8_t cnt = 0; |
if(!cnt--) // every 10th run (9.765kHz/10 = 976Hz) |
{ |
cnt = 9; |
CountMilliseconds++; // increment millisecond counter |
} |
} |
// ----------------------------------------------------------------------- |
uint16_t SetDelay (uint16_t t) |
{ |
return(CountMilliseconds + t - 1); |
} |
// ----------------------------------------------------------------------- |
int8_t CheckDelay(uint16_t t) |
{ |
return(((t - CountMilliseconds) & 0x8000) >> 8); // check sign bit |
} |
// ----------------------------------------------------------------------- |
void Delay_ms(uint16_t w) |
{ |
unsigned int t_stop; |
t_stop = SetDelay(w); |
while (!CheckDelay(t_stop)); |
} |
/FollowMe/timer0.h |
---|
0,0 → 1,14 |
#ifndef _TIMER0_H |
#define _TIMER0_H |
#include <inttypes.h> |
extern volatile uint16_t CountMilliseconds; |
extern void TIMER0_Init(void); |
extern void Delay_ms(uint16_t w); |
extern void Delay_ms_Mess(uint16_t w); |
extern uint16_t SetDelay (uint16_t t); |
extern int8_t CheckDelay (uint16_t t); |
#endif //_TIMER0_H |
/FollowMe/uart0.c |
---|
0,0 → 1,515 |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
// + Copyright (c) 04.2007 Holger Buss |
// + only for non-profit use |
// + www.MikroKopter.com |
// + see the File "License.txt" for further Informations |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include <avr/wdt.h> |
#include <stdarg.h> |
#include <string.h> |
#include "main.h" |
#include "menu.h" |
#include "timer0.h" |
#include "uart0.h" |
#include "ubx.h" |
#include "led.h" |
#define FC_ADDRESS 1 |
#define NC_ADDRESS 2 |
#define MK3MAG_ADDRESS 3 |
#define FM_ADDRESS 10 // FOLLOW ME |
#define FALSE 0 |
#define TRUE 1 |
//int8_t test __attribute__ ((section (".noinit"))); |
uint8_t Request_VerInfo = FALSE; |
uint8_t Request_Display = FALSE; |
uint8_t Request_Display1 = FALSE; |
uint8_t Request_ExternalControl = FALSE; |
uint8_t Request_DebugData = FALSE; |
uint8_t Request_DebugLabel = 255; |
uint8_t DisplayLine = 0; |
volatile uint8_t txd_buffer[TXD_BUFFER_LEN]; |
volatile uint8_t rxd_buffer_locked = FALSE; |
volatile uint8_t rxd_buffer[RXD_BUFFER_LEN]; |
volatile uint8_t txd_complete = TRUE; |
volatile uint8_t ReceivedBytes = 0; |
volatile uint8_t *pRxData = 0; |
volatile uint8_t RxDataLen = 0; |
uint8_t PcAccess = 100; |
ExternControl_t ExternControl; |
DebugOut_t DebugOut; |
UART_VersionInfo_t UART_VersionInfo; |
uint16_t DebugData_Timer; |
uint16_t DebugData_Interval = 500; // in 1ms |
const uint8_t ANALOG_LABEL[32][16] = |
{ |
//1234567890123456 |
"Debug0 ", //0 |
"Debug1 ", |
"Debug2 ", |
"Debug3 ", |
"Debug4 ", |
"Debug5 ", //5 |
"Debug6 ", |
"Debug7 ", |
"Debug8 ", |
"Debug9 ", |
"Debug10 ", //10 |
"Debug11 ", |
"Debug12 ", |
"Debug13 ", |
"Debug14 ", |
"Debug15 ", //15 |
"Debug16 ", |
"Debug17 ", |
"Debug18 ", |
"Debug19 ", |
"Debug20 ", //20 |
"Debug21 ", |
"Debug22 ", |
"Debug23 ", |
"Debug24 ", |
"Debug25 ", //25 |
"Debug26 ", |
"Debug27 ", |
"Debug28 ", |
"Debug29 ", |
"Debug30 ", //30 |
"Debug31 " |
}; |
/****************************************************************/ |
/* Initialization of the USART0 */ |
/****************************************************************/ |
void USART0_Init (void) |
{ |
uint8_t sreg = SREG; |
uint16_t ubrr = (uint16_t) ((uint32_t) SYSCLK/(8 * USART0_BAUD) - 1); |
// disable all interrupts before configuration |
cli(); |
// disable RX-Interrupt |
UCSR0B &= ~(1 << RXCIE0); |
// disable TX-Interrupt |
UCSR0B &= ~(1 << TXCIE0); |
// set direction of RXD0 and TXD0 pins |
// set RXD0 (PD0) as an input pin |
PORTD |= (1 << PORTD0); |
DDRD &= ~(1 << DDD0); |
// set TXD0 (PD1) as an output pin |
PORTD |= (1 << PORTD1); |
DDRD |= (1 << DDD1); |
// USART0 Baud Rate Register |
// set clock divider |
UBRR0H = (uint8_t)(ubrr >> 8); |
UBRR0L = (uint8_t)ubrr; |
// USART0 Control and Status Register A, B, C |
// enable double speed operation in |
UCSR0A |= (1 << U2X0); |
// enable receiver and transmitter in |
UCSR0B = (1 << TXEN0) | (1 << RXEN0); |
// set asynchronous mode |
UCSR0C &= ~(1 << UMSEL01); |
UCSR0C &= ~(1 << UMSEL00); |
// no parity |
UCSR0C &= ~(1 << UPM01); |
UCSR0C &= ~(1 << UPM00); |
// 1 stop bit |
UCSR0C &= ~(1 << USBS0); |
// 8-bit |
UCSR0B &= ~(1 << UCSZ02); |
UCSR0C |= (1 << UCSZ01); |
UCSR0C |= (1 << UCSZ00); |
// flush receive buffer |
while ( UCSR0A & (1<<RXC0) ) UDR0; |
// enable interrupts at the end |
// enable RX-Interrupt |
UCSR0B |= (1 << RXCIE0); |
// enable TX-Interrupt |
UCSR0B |= (1 << TXCIE0); |
// initialize the debug timer |
DebugData_Timer = SetDelay(DebugData_Interval); |
// unlock rxd_buffer |
rxd_buffer_locked = FALSE; |
pRxData = 0; |
RxDataLen = 0; |
// no bytes to send |
txd_complete = TRUE; |
UART_VersionInfo.SWMajor = VERSION_MAJOR; |
UART_VersionInfo.SWMinor = VERSION_MINOR; |
UART_VersionInfo.SWPatch = VERSION_PATCH; |
UART_VersionInfo.ProtoMajor = VERSION_SERIAL_MAJOR; |
UART_VersionInfo.ProtoMinor = VERSION_SERIAL_MINOR; |
// restore global interrupt flags |
SREG = sreg; |
} |
/****************************************************************/ |
/* USART0 transmitter ISR */ |
/****************************************************************/ |
ISR(USART0_TX_vect) |
{ |
static uint16_t ptr_txd_buffer = 0; |
uint8_t tmp_tx; |
if(!txd_complete) // transmission not completed |
{ |
ptr_txd_buffer++; // die [0] wurde schon gesendet |
tmp_tx = txd_buffer[ptr_txd_buffer]; |
// if terminating character or end of txd buffer was reached |
if((tmp_tx == '\r') || (ptr_txd_buffer == TXD_BUFFER_LEN)) |
{ |
ptr_txd_buffer = 0; // reset txd pointer |
txd_complete = 1; // stop transmission |
} |
UDR0 = tmp_tx; // send current byte will trigger this ISR again |
} |
// transmission completed |
else ptr_txd_buffer = 0; |
} |
/****************************************************************/ |
/* USART0 receiver ISR */ |
/****************************************************************/ |
ISR(USART0_RX_vect) |
{ |
static uint16_t crc; |
static uint8_t ptr_rxd_buffer = 0; |
uint8_t crc1, crc2; |
uint8_t c; |
c = UDR0; // catch the received byte |
if(rxd_buffer_locked) return; // if rxd buffer is locked immediately return |
// the rxd buffer is unlocked |
if((ptr_rxd_buffer == 0) && (c == '#')) // if rxd buffer is empty and syncronisation character is received |
{ |
rxd_buffer[ptr_rxd_buffer++] = c; // copy 1st byte to buffer |
crc = c; // init crc |
} |
#if 0 |
else if (ptr_rxd_buffer == 1) // handle address |
{ |
rxd_buffer[ptr_rxd_buffer++] = c; // copy byte to rxd buffer |
crc += c; // update crc |
} |
#endif |
else if (ptr_rxd_buffer < RXD_BUFFER_LEN) // collect incomming bytes |
{ |
if(c != '\r') // no termination character |
{ |
rxd_buffer[ptr_rxd_buffer++] = c; // copy byte to rxd buffer |
crc += c; // update crc |
} |
else // termination character was received |
{ |
// the last 2 bytes are no subject for checksum calculation |
// they are the checksum itself |
crc -= rxd_buffer[ptr_rxd_buffer-2]; |
crc -= rxd_buffer[ptr_rxd_buffer-1]; |
// calculate checksum from transmitted data |
crc %= 4096; |
crc1 = '=' + crc / 64; |
crc2 = '=' + crc % 64; |
// compare checksum to transmitted checksum bytes |
if((crc1 == rxd_buffer[ptr_rxd_buffer-2]) && (crc2 == rxd_buffer[ptr_rxd_buffer-1])) |
{ // checksum valid |
rxd_buffer[ptr_rxd_buffer] = '\r'; // set termination character |
ReceivedBytes = ptr_rxd_buffer + 1;// store number of received bytes |
rxd_buffer_locked = TRUE; // lock the rxd buffer |
// if 2nd byte is an 'R' enable watchdog that will result in an reset |
if(rxd_buffer[2] == 'R') {wdt_enable(WDTO_250MS);} // Reset-Commando |
} |
else |
{ // checksum invalid |
rxd_buffer_locked = FALSE; // unlock rxd buffer |
} |
ptr_rxd_buffer = 0; // reset rxd buffer pointer |
} |
} |
else // rxd buffer overrun |
{ |
ptr_rxd_buffer = 0; // reset rxd buffer |
rxd_buffer_locked = FALSE; // unlock rxd buffer |
} |
} |
// -------------------------------------------------------------------------- |
void AddCRC(uint16_t datalen) |
{ |
uint16_t tmpCRC = 0, i; |
for(i = 0; i < datalen; i++) |
{ |
tmpCRC += txd_buffer[i]; |
} |
tmpCRC %= 4096; |
txd_buffer[i++] = '=' + tmpCRC / 64; |
txd_buffer[i++] = '=' + tmpCRC % 64; |
txd_buffer[i++] = '\r'; |
txd_complete = FALSE; |
UDR0 = txd_buffer[0]; // initiates the transmittion (continued in the TXD ISR) |
} |
// -------------------------------------------------------------------------- |
void SendOutData(uint8_t cmd, uint8_t addr, uint8_t numofbuffers, ...) // uint8_t *pdata, uint8_t len, ... |
{ |
va_list ap; |
uint16_t pt = 0; |
uint8_t a,b,c; |
uint8_t ptr = 0; |
uint8_t *pdata = 0; |
int len = 0; |
txd_buffer[pt++] = '#'; // Start character |
txd_buffer[pt++] = 'a' + addr; // Address (a=0; b=1,...) |
txd_buffer[pt++] = cmd; // Command |
va_start(ap, numofbuffers); |
if(numofbuffers) |
{ |
pdata = va_arg(ap, uint8_t*); |
len = va_arg(ap, int); |
ptr = 0; |
numofbuffers--; |
} |
while(len) |
{ |
if(len) |
{ |
a = pdata[ptr++]; |
len--; |
if((!len) && numofbuffers) |
{ |
pdata = va_arg(ap, uint8_t*); |
len = va_arg(ap, int); |
ptr = 0; |
numofbuffers--; |
} |
} |
else a = 0; |
if(len) |
{ |
b = pdata[ptr++]; |
len--; |
if((!len) && numofbuffers) |
{ |
pdata = va_arg(ap, uint8_t*); |
len = va_arg(ap, int); |
ptr = 0; |
numofbuffers--; |
} |
} |
else b = 0; |
if(len) |
{ |
c = pdata[ptr++]; |
len--; |
if((!len) && numofbuffers) |
{ |
pdata = va_arg(ap, uint8_t*); |
len = va_arg(ap, int); |
ptr = 0; |
numofbuffers--; |
} |
} |
else c = 0; |
txd_buffer[pt++] = '=' + (a >> 2); |
txd_buffer[pt++] = '=' + (((a & 0x03) << 4) | ((b & 0xf0) >> 4)); |
txd_buffer[pt++] = '=' + (((b & 0x0f) << 2) | ((c & 0xc0) >> 6)); |
txd_buffer[pt++] = '=' + ( c & 0x3f); |
} |
va_end(ap); |
AddCRC(pt); // add checksum after data block and initates the transmission |
} |
// -------------------------------------------------------------------------- |
void Decode64(void) |
{ |
uint8_t a,b,c,d; |
uint8_t x,y,z; |
uint8_t ptrIn = 3; |
uint8_t ptrOut = 3; |
uint8_t len = ReceivedBytes - 6; |
while(len) |
{ |
a = rxd_buffer[ptrIn++] - '='; |
b = rxd_buffer[ptrIn++] - '='; |
c = rxd_buffer[ptrIn++] - '='; |
d = rxd_buffer[ptrIn++] - '='; |
//if(ptrIn > ReceivedBytes - 3) break; |
x = (a << 2) | (b >> 4); |
y = ((b & 0x0f) << 4) | (c >> 2); |
z = ((c & 0x03) << 6) | d; |
if(len--) rxd_buffer[ptrOut++] = x; else break; |
if(len--) rxd_buffer[ptrOut++] = y; else break; |
if(len--) rxd_buffer[ptrOut++] = z; else break; |
} |
pRxData = &rxd_buffer[3]; |
RxDataLen = ptrOut - 3; |
} |
// -------------------------------------------------------------------------- |
void USART0_ProcessRxData(void) |
{ |
// if data in the rxd buffer are not locked immediately return |
if(!rxd_buffer_locked) return; |
Decode64(); // decode data block in rxd_buffer |
switch(rxd_buffer[1] - 'a') |
{ |
case FM_ADDRESS: |
switch(rxd_buffer[2]) |
{ |
default: |
//unsupported command received |
break; |
} // case FC_ADDRESS: |
default: // any Slave Address |
switch(rxd_buffer[2]) |
{ |
case 'a':// request for labels of the analog debug outputs |
Request_DebugLabel = pRxData[0]; |
if(Request_DebugLabel > 31) Request_DebugLabel = 31; |
PcAccess = 255; |
break; |
case 'h':// request for display columns |
PcAccess = 255; |
RemoteKeys |= pRxData[0]; |
if(RemoteKeys) DisplayLine = 0; |
Request_Display = TRUE; |
break; |
case 'l':// request for display columns |
PcAccess = 255; |
MenuItem = pRxData[0]; |
Request_Display1 = TRUE; |
break; |
case 'v': // request for version and board release |
Request_VerInfo = TRUE; |
break; |
case 'd': // request for the debug data |
DebugData_Interval = (uint16_t) pRxData[0] * 10; |
if(DebugData_Interval > 0) Request_DebugData = TRUE; |
break; |
case 'g':// get external control data |
Request_ExternalControl = TRUE; |
break; |
default: |
LEDRED_TOGGLE; |
//unsupported command received |
break; |
} |
break; // default: |
} |
// unlock the rxd buffer after processing |
pRxData = 0; |
RxDataLen = 0; |
rxd_buffer_locked = FALSE; |
} |
//############################################################################ |
//Routine für die Serielle Ausgabe |
int16_t uart_putchar (int8_t c) |
//############################################################################ |
{ |
if (c == '\n') |
uart_putchar('\r'); |
// wait until previous character was send |
loop_until_bit_is_set(UCSR0A, UDRE0); |
// send character |
UDR0 = c; |
return (0); |
} |
//--------------------------------------------------------------------------------------------- |
void USART0_TransmitTxData(void) |
{ |
if(!txd_complete) return; |
if(Request_VerInfo && txd_complete) |
{ |
SendOutData('V', FM_ADDRESS, 1, (uint8_t *) &UART_VersionInfo, sizeof(UART_VersionInfo)); |
Request_VerInfo = FALSE; |
} |
if(Request_Display && txd_complete) |
{ |
LCD_PrintMenu(); |
SendOutData('H', FM_ADDRESS, 2, &DisplayLine, sizeof(DisplayLine), &DisplayBuff[DisplayLine * 20], 20); |
DisplayLine++; |
if(DisplayLine >= 4) DisplayLine = 0; |
Request_Display = FALSE; |
} |
if(Request_Display1 && txd_complete) |
{ |
LCD_PrintMenu(); |
SendOutData('L', FM_ADDRESS, 3, &MenuItem, sizeof(MenuItem), &MaxMenuItem, sizeof(MaxMenuItem), DisplayBuff, sizeof(DisplayBuff)); |
Request_Display1 = FALSE; |
} |
if(Request_DebugLabel != 0xFF) // Texte für die Analogdaten |
{ |
SendOutData('A', FM_ADDRESS, 2, (uint8_t *) &Request_DebugLabel, sizeof(Request_DebugLabel), ANALOG_LABEL[Request_DebugLabel], 16); |
Request_DebugLabel = 0xFF; |
} |
if(Request_ExternalControl && txd_complete) |
{ |
SendOutData('G', FM_ADDRESS, 1,(uint8_t *) &ExternControl, sizeof(ExternControl)); |
Request_ExternalControl = FALSE; |
} |
if( ((DebugData_Interval && CheckDelay(DebugData_Timer)) || Request_DebugData) && txd_complete) |
{ |
SendOutData('D', FM_ADDRESS, 1,(uint8_t *) &DebugOut, sizeof(DebugOut)); |
DebugData_Timer = SetDelay(DebugData_Interval); |
Request_DebugData = FALSE; |
} |
} |
/FollowMe/uart0.h |
---|
0,0 → 1,59 |
#ifndef _UART0_H |
#define _UART0_H |
#define RXD_BUFFER_LEN 150 |
// must be at least 4('#'+Addr+'CmdID'+'\r')+ (80 * 4)/3 = 111 bytes |
#define TXD_BUFFER_LEN 150 |
#define RXD_BUFFER_LEN 150 |
#include <inttypes.h> |
//Baud rate of the USART |
#define USART0_BAUD 57600 |
extern void USART0_Init (void); |
extern void USART0_TransmitTxData(void); |
extern void USART0_ProcessRxData(void); |
extern int16_t uart_putchar(int8_t c); |
extern uint8_t PcAccess; |
extern uint8_t RemotePollDisplayLine; |
typedef struct |
{ |
uint8_t Digital[2]; |
uint8_t RemoteButtons; |
int8_t Nick; |
int8_t Roll; |
int8_t Yaw; |
uint8_t Gas; |
int8_t Height; |
uint8_t free; |
uint8_t Frame; |
uint8_t Config; |
} __attribute__((packed)) ExternControl_t; |
extern ExternControl_t ExternControl; |
typedef struct |
{ |
uint8_t Digital[2]; |
uint16_t Analog[32]; // Debugvalues |
} __attribute__((packed)) DebugOut_t; |
extern DebugOut_t DebugOut; |
typedef struct |
{ |
uint8_t SWMajor; |
uint8_t SWMinor; |
uint8_t ProtoMajor; |
uint8_t ProtoMinor; |
uint8_t SWPatch; |
uint8_t Reserved[5]; |
} __attribute__((packed)) UART_VersionInfo_t; |
#endif //_UART0_H |
/FollowMe/uart1.c |
---|
0,0 → 1,94 |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include "main.h" |
#include "uart1.h" |
#include "ubx.h" |
/****************************************************************/ |
/* Initialization of the USART1 */ |
/****************************************************************/ |
void USART1_Init (void) |
{ |
// USART1 Control and Status Register A, B, C and baud rate register |
uint8_t sreg = SREG; |
uint16_t ubrr = (uint16_t) ((uint32_t) SYSCLK/(8 * USART1_BAUD) - 1); |
// disable all interrupts before reconfiguration |
cli(); |
// disable RX-Interrupt |
UCSR1B &= ~(1 << RXCIE1); |
// disable TX-Interrupt |
UCSR1B &= ~(1 << TXCIE1); |
// disable DRE-Interrupt |
UCSR1B &= ~(1 << UDRIE1); |
// set direction of RXD1 and TXD1 pins |
// set RXD1 (PD2) as an input pin |
PORTD |= (1 << PORTD2); |
DDRD &= ~(1 << DDD2); |
// set TXD1 (PD3) as an output pin |
PORTD |= (1 << PORTD3); |
DDRD |= (1 << DDD3); |
// USART0 Baud Rate Register |
// set clock divider |
UBRR1H = (uint8_t)(ubrr>>8); |
UBRR1L = (uint8_t)ubrr; |
// enable double speed operation |
UCSR1A |= (1 << U2X1); |
// enable receiver and transmitter |
UCSR1B = (1 << TXEN1) | (1 << RXEN1); |
// set asynchronous mode |
UCSR1C &= ~(1 << UMSEL11); |
UCSR1C &= ~(1 << UMSEL10); |
// no parity |
UCSR1C &= ~(1 << UPM11); |
UCSR1C &= ~(1 << UPM10); |
// 1 stop bit |
UCSR1C &= ~(1 << USBS1); |
// 8-bit |
UCSR1B &= ~(1 << UCSZ12); |
UCSR1C |= (1 << UCSZ11); |
UCSR1C |= (1 << UCSZ10); |
// flush receive buffer explicit |
while ( UCSR1A & (1<<RXC1) ) UDR1; |
// enable interrupts at the end |
// enable RX-Interrupt |
UCSR1B |= (1 << RXCIE1); |
// enable TX-Interrupt |
UCSR1B |= (1 << TXCIE1); |
// enable DRE interrupt |
//UCSR1B |= (1 << UDRIE1); |
// restore global interrupt flags |
SREG = sreg; |
} |
/****************************************************************/ |
/* USART1 transmitter ISR */ |
/****************************************************************/ |
/*ISR(USART1_TX_vect) |
{ |
} |
*/ |
/****************************************************************/ |
/* USART1 receiver ISR */ |
/****************************************************************/ |
ISR(USART1_RX_vect) |
{ |
uint8_t c; |
c = UDR1; // get data byte |
ubx_parser(c); // and put it into the ubx protocol parser |
} |
/FollowMe/uart1.h |
---|
0,0 → 1,25 |
#ifndef _UART1_H |
#define _UART1_H |
#define USART1_BAUD 57600 |
/* |
Initialize the USART und activate the receiver and transmitter |
as well as the receive-interrupt. The IO-FIFOs are initialized. |
The global interrupt-enable-flag (I-Bit in SREG) is not changed |
*/ |
extern void USART1_Init (void); |
/* |
The character c is stored in the output buffer. If the character was pushed sucessfully to |
the output buffer then the return value is 1. In case of an output buffer overflow the return value is 0. |
The isr is activated, which will send the data from the outbut buffer to the UART. |
*/ |
extern int USART1_putc (const uint8_t c); |
/* |
extern uint8_t USART1_getc_wait(void); |
extern int16_t USART1_getc_nowait(void); |
*/ |
#endif //_UART1_H |
/FollowMe/ubx.c |
---|
0,0 → 1,237 |
#include <inttypes.h> |
#include "ubx.h" |
#include <avr/io.h> |
// ubx protocol parser state machine |
#define UBXSTATE_IDLE 0 |
#define UBXSTATE_SYNC1 1 |
#define UBXSTATE_SYNC2 2 |
#define UBXSTATE_CLASS 3 |
#define UBXSTATE_LEN1 4 |
#define UBXSTATE_LEN2 5 |
#define UBXSTATE_DATA 6 |
#define UBXSTATE_CKA 7 |
#define UBXSTATE_CKB 8 |
// ublox protocoll identifier |
#define UBX_CLASS_NAV 0x01 |
#define UBX_ID_POSLLH 0x02 |
#define UBX_ID_SOL 0x06 |
#define UBX_ID_VELNED 0x12 |
#define UBX_SYNC1_CHAR 0xB5 |
#define UBX_SYNC2_CHAR 0x62 |
typedef struct { |
uint32_t ITOW; // ms GPS Millisecond Time of Week |
int32_t Frac; // ns remainder of rounded ms above |
int16_t week; // GPS week |
uint8_t GPSfix; // GPSfix Type, range 0..6 |
uint8_t Flags; // Navigation Status Flags |
int32_t ECEF_X; // cm ECEF X coordinate |
int32_t ECEF_Y; // cm ECEF Y coordinate |
int32_t ECEF_Z; // cm ECEF Z coordinate |
uint32_t PAcc; // cm 3D Position Accuracy Estimate |
int32_t ECEFVX; // cm/s ECEF X velocity |
int32_t ECEFVY; // cm/s ECEF Y velocity |
int32_t ECEFVZ; // cm/s ECEF Z velocity |
uint32_t SAcc; // cm/s Speed Accuracy Estimate |
uint16_t PDOP; // 0.01 Position DOP |
uint8_t res1; // reserved |
uint8_t numSV; // Number of SVs used in navigation solution |
uint32_t res2; // reserved |
Status_t Status; |
} UBX_SOL_t; |
typedef struct { |
uint32_t ITOW; // ms GPS Millisecond Time of Week |
int32_t LON; // 1e-07 deg Longitude |
int32_t LAT; // 1e-07 deg Latitude |
int32_t HEIGHT; // mm Height above Ellipsoid |
int32_t HMSL; // mm Height above mean sea level |
uint32_t Hacc; // mm Horizontal Accuracy Estimate |
uint32_t Vacc; // mm Vertical Accuracy Estimate |
Status_t Status; |
} UBX_POSLLH_t; |
typedef struct { |
uint32_t ITOW; // ms GPS Millisecond Time of Week |
int32_t VEL_N; // cm/s NED north velocity |
int32_t VEL_E; // cm/s NED east velocity |
int32_t VEL_D; // cm/s NED down velocity |
uint32_t Speed; // cm/s Speed (3-D) |
uint32_t GSpeed; // cm/s Ground Speed (2-D) |
int32_t Heading; // 1e-05 deg Heading 2-D |
uint32_t SAcc; // cm/s Speed Accuracy Estimate |
uint32_t CAcc; // deg Course / Heading Accuracy Estimate |
Status_t Status; |
} UBX_VELNED_t; |
UBX_SOL_t UbxSol = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, INVALID}; |
UBX_POSLLH_t UbxPosLlh = {0,0,0,0,0,0,0, INVALID}; |
UBX_VELNED_t UbxVelNed = {0,0,0,0,0,0,0,0,0, INVALID}; |
GPS_INFO_t GPSInfo = {0,0,0,0,0,0,0,0,0,0, INVALID}; |
volatile uint8_t GPSTimeout = 0; |
void UpdateGPSInfo (void) |
{ |
if ((UbxSol.Status == NEWDATA) && (UbxPosLlh.Status == NEWDATA) && (UbxVelNed.Status == NEWDATA)) |
{ |
if(GPSInfo.status != NEWDATA) |
{ |
GPSInfo.status = INVALID; |
// NAV SOL |
GPSInfo.flags = UbxSol.Flags; |
GPSInfo.satfix = UbxSol.GPSfix; |
GPSInfo.satnum = UbxSol.numSV; |
GPSInfo.PAcc = UbxSol.PAcc; |
GPSInfo.VAcc = UbxSol.SAcc; |
// NAV POSLLH |
GPSInfo.longitude = UbxPosLlh.LON; |
GPSInfo.latitude = UbxPosLlh.LAT; |
GPSInfo.altitude = UbxPosLlh.HEIGHT; |
GPSInfo.veleast = UbxVelNed.VEL_E; |
GPSInfo.velnorth = UbxVelNed.VEL_N; |
GPSInfo.veltop = -UbxVelNed.VEL_D; |
GPSInfo.velground = UbxVelNed.GSpeed; |
GPSInfo.status = NEWDATA; |
} |
// set state to collect new data |
UbxSol.Status = PROCESSED; // never update old data |
UbxPosLlh.Status = PROCESSED; // never update old data |
UbxVelNed.Status = PROCESSED; // never update old data |
} |
} |
// this function should be called within the UART RX ISR |
void ubx_parser(uint8_t c) |
{ |
static uint8_t ubxstate = UBXSTATE_IDLE; |
static uint8_t cka, ckb; |
static uint16_t msglen; |
static int8_t *ubxP, *ubxEp, *ubxSp; // pointers to data currently transfered |
switch(ubxstate) |
{ |
case UBXSTATE_IDLE: // check 1st sync byte |
if (c == UBX_SYNC1_CHAR) ubxstate = UBXSTATE_SYNC1; |
else ubxstate = UBXSTATE_IDLE; // out of synchronization |
break; |
case UBXSTATE_SYNC1: // check 2nd sync byte |
if (c == UBX_SYNC2_CHAR) ubxstate = UBXSTATE_SYNC2; |
else ubxstate = UBXSTATE_IDLE; // out of synchronization |
break; |
case UBXSTATE_SYNC2: // check msg class to be NAV |
if (c == UBX_CLASS_NAV) ubxstate = UBXSTATE_CLASS; |
else ubxstate = UBXSTATE_IDLE; // unsupported message class |
break; |
case UBXSTATE_CLASS: // check message identifier |
switch(c) |
{ |
case UBX_ID_POSLLH: // geodetic position |
ubxP = (int8_t *)&UbxPosLlh; // data start pointer |
ubxEp = (int8_t *)(&UbxPosLlh + 1); // data end pointer |
ubxSp = (int8_t *)&UbxPosLlh.Status; // status pointer |
break; |
case UBX_ID_SOL: // navigation solution |
ubxP = (int8_t *)&UbxSol; // data start pointer |
ubxEp = (int8_t *)(&UbxSol + 1); // data end pointer |
ubxSp = (int8_t *)&UbxSol.Status; // status pointer |
break; |
case UBX_ID_VELNED: // velocity vector in tangent plane |
ubxP = (int8_t *)&UbxVelNed; // data start pointer |
ubxEp = (int8_t *)(&UbxVelNed + 1); // data end pointer |
ubxSp = (int8_t *)&UbxVelNed.Status; // status pointer |
break; |
default: // unsupported identifier |
ubxstate = UBXSTATE_IDLE; |
break; |
} |
if (ubxstate != UBXSTATE_IDLE) |
{ |
ubxstate = UBXSTATE_LEN1; |
cka = UBX_CLASS_NAV + c; |
ckb = UBX_CLASS_NAV + cka; |
} |
break; |
case UBXSTATE_LEN1: // 1st message length byte |
msglen = c; |
cka += c; |
ckb += cka; |
ubxstate = UBXSTATE_LEN2; |
break; |
case UBXSTATE_LEN2: // 2nd message length byte |
msglen += ((uint16_t)c)<<8; |
cka += c; |
ckb += cka; |
// if the old data are not processed so far then break parsing now |
// to avoid writing new data in ISR during reading by another function |
if ( *ubxSp == NEWDATA ) |
{ |
UpdateGPSInfo(); //update GPS info respectively |
ubxstate = UBXSTATE_IDLE; |
} |
else // data invalid or allready processd |
{ |
*ubxSp = INVALID; |
ubxstate = UBXSTATE_DATA; |
} |
break; |
case UBXSTATE_DATA: |
if (ubxP < ubxEp) *ubxP++ = c; // copy curent data byte if any space is left |
cka += c; |
ckb += cka; |
if (--msglen == 0) ubxstate = UBXSTATE_CKA; // switch to next state if all data was read |
break; |
case UBXSTATE_CKA: |
if (c == cka) ubxstate = UBXSTATE_CKB; |
else |
{ |
*ubxSp = INVALID; |
ubxstate = UBXSTATE_IDLE; |
} |
break; |
case UBXSTATE_CKB: |
if (c == ckb) |
{ |
*ubxSp = NEWDATA; // new data are valid |
UpdateGPSInfo(); //update GPS info respectively |
GPSTimeout = 255; |
} |
else |
{ // if checksum not fit then set data invalid |
*ubxSp = INVALID; |
} |
ubxstate = UBXSTATE_IDLE; // ready to parse new data |
break; |
default: // unknown ubx state |
ubxstate = UBXSTATE_IDLE; |
break; |
} |
} |
/FollowMe/ubx.h |
---|
0,0 → 1,59 |
#ifndef _UBX_H |
#define _UBX_H |
#include <inttypes.h> |
typedef enum |
{ |
INVALID, |
NEWDATA, |
PROCESSED |
} Status_t; |
// Satfix types for GPSData.satfix |
#define SATFIX_NONE 0x00 |
#define SATFIX_DEADRECKOING 0x01 |
#define SATFIX_2D 0x02 |
#define SATFIX_3D 0x03 |
#define SATFIX_GPS_DEADRECKOING 0x04 |
#define SATFIX_TIMEONLY 0x05 |
// Flags for interpretation of the GPSData.flags |
#define FLAG_GPSFIXOK 0x01 // (i.e. within DOP & ACC Masks) |
#define FLAG_DIFFSOLN 0x02 // (is DGPS used) |
#define FLAG_WKNSET 0x04 // (is Week Number valid) |
#define FLAG_TOWSET 0x08 // (is Time of Week valid) |
/* enable the UBX protocol at the gps receiver with the following messages enabled |
01-02 NAV - POSLLH |
01-06 Nav - SOL |
01-12 NAV - VELNED */ |
typedef struct |
{ |
uint8_t flags; // flags |
uint8_t satnum; // number of satelites |
uint8_t satfix; // type of satfix |
int32_t longitude; // in 1e-07 deg |
int32_t latitude; // in 1e-07 deg |
int32_t altitude; // in mm |
uint32_t PAcc; // in cm 3d position accuracy |
int32_t velnorth; // in cm/s |
int32_t veleast; // in cm/s |
int32_t veltop; // in cm/s |
uint32_t velground; // 2D ground speed in cm/s |
uint32_t VAcc; // in cm/s 3d velocity accuracy |
Status_t status; // status of data: invalid | valid |
} GPS_INFO_t; |
//here you will find the current gps info |
extern GPS_INFO_t GPSInfo; // measured position (last gps record) |
// this variable should be decremted by the application |
extern volatile uint8_t GPSTimeout; // is reset to 255 if a new UBX msg was received |
// this function should be called within the UART RX ISR |
extern void ubx_parser(uint8_t c); |
#endif //_UBX_H |