Subversion Repositories Projects

Compare Revisions

Ignore whitespace Rev 425 → Rev 426

/FollowMe/trunk/FollowMe.pnproj
0,0 → 1,0
<Project name="FollowMe"><Folder name="Sources"><File path="ubx.c"></File><File path="analog.c"></File><File path="button.c"></File><File path="crc16.c"></File><File path="fat16.c"></File><File path="led.c"></File><File path="main.c"></File><File path="menu.c"></File><File path="printf_P.c"></File><File path="sdc.c"></File><File path="ssc.c"></File><File path="timer0.c"></File><File path="uart0.c"></File><File path="uart1.c"></File><File path="gps.c"></File><File path="logging.c"></File><File path="settings.c"></File><File path="gpx.c"></File><File path="kml.c"></File></Folder><Folder name="Header"><File path="ubx.h"></File><File path="analog.h"></File><File path="button.h"></File><File path="crc16.h"></File><File path="fat16.h"></File><File path="led.h"></File><File path="main.h"></File><File path="menu.h"></File><File path="printf_P.h"></File><File path="sdc.h"></File><File path="ssc.h"></File><File path="timer0.h"></File><File path="uart0.h"></File><File path="uart1.h"></File><File path="gps.h"></File><File path="settings.h"></File><File path="gpx.h"></File><File path="gpx_header.h"></File><File path="kml.h"></File><File path="kml_header.h"></File><File path="logging.h"></File></Folder></Project>
/FollowMe/trunk/FollowMe.pnps
0,0 → 1,0
<pd><ViewState><e p="FollowMe" x="true"></e><e p="FollowMe\Header" x="true"></e><e p="FollowMe\Sources" x="true"></e></ViewState></pd>
/FollowMe/trunk/FollowMe.ppg
0,0 → 1,0
<Workspace name="New Project Group"><Project path="d:\hobby\bl-UFO\Mikrocopter\01_Flight-Ctrl\my_Flight-Ctrl_V0_72o\flight.pnproj"></Project><Project path="FollowMe.pnproj"></Project></Workspace>
/FollowMe/trunk/analog.c
0,0 → 1,109
 
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
 
#include "analog.h"
 
volatile uint16_t Adc0, Adc1, Adc2, Adc3, Adc4, Adc5, Adc6, Adc7;
volatile uint8_t ADReady = 1;
 
/*****************************************************/
/* Initialize Analog Digital Converter */
/*****************************************************/
void ADC_Init(void)
{
uint8_t sreg = SREG;
// disable all interrupts before reconfiguration
cli();
//ADC0 ... ADC7 is connected to PortA pin 0 ... 7
DDRA = 0x00;
PORTA = 0x00;
// Digital Input Disable Register 0
// Disable digital input buffer for analog adc_channel pins
DIDR0 = 0xFF;
// external reference AREF, adjust data to the right
ADMUX &= ~((1 << REFS1)|(1 << REFS0)|(1 << ADLAR));
// set muxer to ADC adc_channel 0 (0 to 7 is a valid choice)
ADMUX = (ADMUX & 0xE0) | 0x00;
//Set ADC Control and Status Register A
//Auto Trigger Enable, Prescaler Select Bits to Division Factor 128, i.e. ADC clock = SYSCKL/128 = 156.25 kHz
ADCSRA = (0<<ADEN)|(0<<ADSC)|(0<<ADATE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(0<<ADIE);
//Set ADC Control and Status Register B
//Trigger Source to Free Running Mode
ADCSRB &= ~((1 << ADTS2)|(1 << ADTS1)|(1 << ADTS0));
// Start AD conversion
ADC_Enable();
// restore global interrupt flags
SREG = sreg;
}
 
/*****************************************************/
/* Interrupt Service Routine for ADC */
/*****************************************************/
// runs at 312.5 kHz or 3.2 µs
// if after (60.8µs) all 19 states are processed the interrupt is disabled
// and the update of further ads is stopped
 
 
#define ADC0 0
#define ADC1 1
#define ADC2 2
#define ADC3 3
#define ADC4 4
#define ADC5 5
#define ADC6 6
#define ADC7 7
 
ISR(ADC_vect)
{
static uint8_t ad_channel = ADC0, state = 0;
 
// state machine
switch(state++)
{
case 0:
Adc0 = ADC;
ad_channel = ADC1;
break;
case 1:
Adc1 = ADC;
ad_channel = ADC2;
break;
case 2:
Adc2 = ADC;
ad_channel = ADC3;
break;
case 3:
Adc3 = ADC;
ad_channel = ADC4;
break;
case 4:
Adc4 = ADC;
ad_channel = ADC5;
break;
case 5:
Adc5 = ADC;
ad_channel = ADC6;
break;
case 6:
Adc6 = ADC;
ad_channel = ADC7;
break;
case 7:
Adc7 = ADC;
ad_channel = ADC0;
state = 0;
ADReady = 1;
break;
default:
ad_channel = ADC0;
state = 0;
ADReady = 1;
break;
}
// set adc muxer to next ad_channel
ADMUX = (ADMUX & 0xE0) | ad_channel;
// after full cycle stop further interrupts
if(state != 0) ADC_Enable();
}
/FollowMe/trunk/analog.h
0,0 → 1,20
#ifndef _ANALOG_H
#define _ANALOG_H
 
#include <inttypes.h>
 
extern volatile uint16_t Adc0, Adc1, Adc2, Adc3, Adc4, Adc5, Adc6, Adc7;
extern volatile uint8_t ADReady;
 
void ADC_Init(void);
 
 
// clear ADC enable & ADC Start Conversion & ADC Interrupt Enable bit
#define ADC_Disable() (ADCSRA &= ~((1<<ADEN)|(1<<ADSC)|(1<<ADIE)))
// set ADC enable & ADC Start Conversion & ADC Interrupt Enable bit
#define ADC_Enable() (ADCSRA |= (1<<ADEN)|(1<<ADSC)|(1<<ADIE))
 
 
#endif //_ANALOG_H
 
 
/FollowMe/trunk/button.c
0,0 → 1,50
#include "timer0.h"
#include "button.h"
 
 
#ifdef USE_FOLLOWME
#define BUTTON !(PINC & (1<<PINC6))
#endif
#ifdef USE_SDLOGGER
#define BUTTON !(PINC & (1<<PINC3))
#endif
 
#define CNT_KEY 10 // at least 3
#define KEY_DELAY_MS 50
 
uint16_t ButtonTimer = 0;
 
void Button_Init(void)
{
 
// set port pin as input pullup
#ifdef USE_FOLLOWME
PORTC |= (1 << PORTC6);
DDRC &= ~(1 << DDC6);
#endif
 
#ifdef USE_SDLOGGER
PORTC |= (1 << PORTC3);
DDRC &= ~(1 << DDC3);
#endif
ButtonTimer = SetDelay(KEY_DELAY_MS);
}
 
uint8_t GetButton(void)
{
static uint8_t button = 0;
uint8_t ret = 0;
 
if(CheckDelay(ButtonTimer))
{
if(BUTTON)
{
if(button++ == 0 || button == CNT_KEY) ret = 1;
if(button == CNT_KEY) button = CNT_KEY - CNT_KEY / 3;
}
else button = 0;
ButtonTimer = SetDelay(KEY_DELAY_MS);
}
return(ret);
}
 
/FollowMe/trunk/button.h
0,0 → 1,11
#ifndef _BUTTON_H
#define _BUTTON_H
 
#include <avr/io.h>
#include <inttypes.h>
 
extern void Button_Init(void);
extern uint8_t GetButton(void);
 
 
#endif //_BUTTON_H
/FollowMe/trunk/crc16.c
0,0 → 1,48
#include "crc16.h"
#include <avr/pgmspace.h>
 
const uint16_t crc16tab[256] PROGMEM =
{
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
};
 
uint16_t CRC16(const uint8_t *pBuffer, uint32_t len)
{
uint32_t counter;
uint16_t crc = 0;
for( counter = 0; counter < len; counter++)
crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *pBuffer++)&0x00FF];
return crc;
}
 
/FollowMe/trunk/crc16.h
0,0 → 1,8
#ifndef _CRC16_H
#define _CRC16_H
 
#include <inttypes.h>
 
extern uint16_t CRC16(const uint8_t * pBuffer, uint32_t len);
 
#endif // _CRC16_H
/FollowMe/trunk/fat16.c
0,0 → 1,1741
#include <string.h>
#include "printf_P.h"
#include "timer0.h"
#include "fat16.h"
#include "sdc.h"
#include "uart1.h"
 
 
/*
FAT16 Drive Layout:
Description Offset
Volume Boot Sector Start of Partition
Fat Tables Start + # of Reserved Sectors
Root Directory Entry Start + # of Reserved + (# of Sectors Per FAT * 2)
Data Area (Starts with Cluster #2) Start + # of Reserved + (# of Sectors Per FAT * 2) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
*/
 
 
/*
________________________________________________________________________________________________________________________________________
 
Structure of an partition entry
________________________________________________________________________________________________________________________________________
 
Partition Entry is 16 bytes long
*/
typedef struct
{
uint8_t PartitionState; // Current State of Partition (00h=Inactive, 80h=Active)
uint8_t BeginningHead; // Beginning of Partition - Head
uint16_t BeginningCylSec; // Beginning of Partition - Cylinder/Sector (See Below)
uint8_t Type; // Type of Partition (See List Below)
uint8_t EndHead; // End of Partition - Head
uint16_t EndCylSec; // End of Partition - Cylinder/Sector
uint32_t NoSectorsBeforePartition; // Number of Sectors between the MBR and the First Sector in the Partition
uint32_t NoSectorsPartition ; // Number of Sectors in the Partition
} __attribute__((packed)) PartitionEntry_t;
 
/*
Coding of Cylinder/Sector words
 
Cylinder is 10 bits: [7:0] at [15:8] and [9:8] at [7:6]
Sector is 5 bits: [5:0] at [5:0]
*/
 
// Partition Types:
#define PART_TYPE_UNKNOWN 0x00
#define PART_TYPE_FAT12 0x01
#define PART_TYPE_XENIX 0x02
#define PART_TYPE_FAT16_ST_32_MB 0x04
#define PART_TYPE_EXTDOS 0x05
#define PART_TYPE_FAT16_LT_32_MB 0x06
#define PART_TYPE_NTFS 0x07
#define PART_TYPE_FAT32 0x0B
#define PART_TYPE_FAT32LBA 0x0C
#define PART_TYPE_FAT16LBA 0x0E
#define PART_TYPE_EXTDOSLBA 0x0F
#define PART_TYPE_EISA 0x12
#define PART_TYPE_ONTRACK 0x33
#define PART_TYPE_NOVELL 0x40
#define PART_TYPE_DYNAMIC 0x42
#define PART_TYPE_PCIX 0x4B
#define PART_TYPE_LINUX_SWAP 0x82
#define PART_TYPE_LINUX_NATIVE 0x83
#define PART_TYPE_LINUX_LVM 0x8E
#define PART_TYPE_PHOENIXSAVE 0xA0
#define PART_TYPE_FREEBSD 0xA5
#define PART_TYPE_OPENBSD 0xA6
#define PART_TYPE_NETNBSD 0xA9
#define PART_TYPE_CPM 0xDB
#define PART_TYPE_DBFS 0xE0
#define PART_TYPE_BBT 0xFF
 
 
/*
________________________________________________________________________________________________________________________________________
 
Structure of the MasterBootRecord
________________________________________________________________________________________________________________________________________
 
Master Boot Record is 512 bytes long
The Master Boot Record is the same for pretty much all Operating Systems.
It is located on the first Sector of the Hard Drive, at Cylinder 0, Head 0, Sector 1
*/
typedef struct
{
uint8_t ExecutableCode[446]; // 446 bytes for machine start code
PartitionEntry_t PartitionEntry1; // 16 bytes for partition entry 1
PartitionEntry_t PartitionEntry2; // 16 bytes for partition entry 2
PartitionEntry_t PartitionEntry3; // 16 bytes for partition entry 3
PartitionEntry_t PartitionEntry4; // 16 bytes for partition entry 4
uint16_t ExecutableMarker; // BIOS-Signature (0x55 0xAA)
} __attribute__((packed)) MBR_Entry_t;
 
 
/*
________________________________________________________________________________________________________________________________________
 
Structure of the VolumeBootRecord
________________________________________________________________________________________________________________________________________
 
The Volume Boot Record is 512 bytes long
This information is located in the first sector of every partition.
*/
typedef struct
{
uint8_t JumpCode[3]; // Jump Code + NOP
int8_t OEMName[8]; // OEM Name
uint16_t BytesPerSector; // Bytes Per Sector
uint8_t SectorsPerCluster; // Sectors Per Cluster
uint16_t ReservedSectors; // Reserved Sectors
uint8_t NoFATCopies; // Number of Copies of FAT
uint16_t MaxRootEntries; // Maximum Root Directory Entries
uint16_t NoSectorsInPartSml32MB; // Number of Sectors in Partition Smaller than 32 MB
uint8_t MediaDescriptor; // Media Descriptor (0xF8 for Hard Disks)
uint16_t SectorsPerFAT; // Sectors Per FAT
uint16_t SectorsPerTrack; // Sectors Per Track
uint16_t NoHeads; // Number of Heads
uint32_t NoHiddenSectors; // Number of Hidden Sectors in Partition
uint32_t NoSectors; // Number of Sectors in Partition
uint16_t DriveNo; // Logical Drive Number of Partition
uint8_t ExtendedSig; // Extended Signature (0x29)
uint32_t SerialNo; // Serial Number of the Partition
int8_t VolumeName[11]; // Volume Name of the Partititon
int8_t FATName[8]; // FAT Name (FAT16)
uint8_t ExecutableCode[446]; // 446 bytes for machine start code
uint16_t ExecutableMarker; // Executable Marker (0x55 0xAA)
} __attribute__((packed)) VBR_Entry_t;
 
 
 
/*
________________________________________________________________________________________________________________________________________
 
Structure of an directory entry
________________________________________________________________________________________________________________________________________
 
Directory entry is 32 bytes.
*/
typedef struct
{
int8_t Name[8]; // 8 bytes name, padded with spaces.
uint8_t Extension[3]; // 3 bytes extension, padded with spaces.
uint8_t Attribute; // attribute of the directory entry (unused,archive,read-only,system,directory,volume)
uint8_t Reserved[10]; // reserved bytes within the directory entry.
uint32_t DateTime; // date and time of last write access to the file or directory.
uint16_t StartCluster; // first cluster of the file or directory.
uint32_t Size; // size of the file or directory in bytes.
} __attribute__((packed)) DirEntry_t;
 
#define SLOT_EMPTY 0x00 // slot has never been used
#define SLOT_E5 0x05 // the real value is 0xe5
#define SLOT_DELETED 0xE5 // file in this slot deleted
 
#define ATTR_NONE 0x00 // normal file
#define ATTR_READONLY 0x01 // file is readonly
#define ATTR_HIDDEN 0x02 // file is hidden
#define ATTR_SYSTEM 0x04 // file is a system file
#define ATTR_VOLUMELABEL 0x08 // entry is a volume label
#define ATTR_LONG_FILENAME 0x0F // this is a long filename entry
#define ATTR_SUBDIRECTORY 0x10 // entry is a directory name
#define ATTR_ARCHIVE 0x20 // file is new or modified
 
 
/*
________________________________________________________________________________________________________________________________________
 
Structure of an entry within the fileallocationtable.
________________________________________________________________________________________________________________________________________
*/
typedef struct
{
uint16_t NextCluster; // the next cluster of the file.
} __attribute__((packed)) Fat16Entry_t;
 
// secial fat entries
#define FAT16_CLUSTER_FREE 0x0000
#define FAT16_CLUSTER_RESERVED 0x0001
#define FAT16_CLUSTER_USED_MIN 0x0002
#define FAT16_CLUSTER_USED_MAX 0xFFEF
#define FAT16_CLUSTER_ROOTDIR_MIN 0xFFF0
#define FAT16_CLUSTER_ROOTDIR_MAX 0xFFF6
#define FAT16_CLUSTER_BAD 0xFFF7
#define FAT16_CLUSTER_LAST_MIN 0xFFF8
#define FAT16_CLUSTER_LAST_MAX 0xFFFF
 
/*****************************************************************************************************************************************/
/* */
/* Global variables needed for read- or write-acces to the FAT16- filesystem. */
/* */
/*****************************************************************************************************************************************/
 
#define MBR_SECTOR 0x00 // the masterboot record is located in sector 0.
#define DIRENTRY_SIZE 32 //bytes
#define DIRENTRIES_PER_SECTOR BYTES_PER_SECTOR/DIRENTRY_SIZE
#define FAT16_BYTES 2
#define FAT16_ENTRIES_PER_SECTOR BYTES_PER_SECTOR/FAT16_BYTES
 
#define FSTATE_UNUSED 0
#define FSTATE_USED 1
 
typedef struct
{
uint8_t IsValid; // 0 means invalid, else valid
uint8_t SectorsPerCluster; // how many sectors does a cluster contain?
uint8_t FatCopies; // Numbers of copies of the FAT
uint16_t MaxRootEntries; // Possible number of entries in the root directory.
uint16_t SectorsPerFat; // how many sectors does a fat16 contain?
uint32_t FirstFatSector; // sector of the start of the fat
uint32_t FirstRootDirSector; // sector of the rootdirectory
uint32_t FirstDataSector; // sector of the first cluster containing data (cluster2).
uint32_t LastDataSector; // the last data sector of the partition
} Partition_t;
 
Partition_t Partition; // Structure holds partition information
 
File_t FilePointer[FILE_MAX_OPEN]; // Allocate Memmoryspace for each filepointer used.
 
 
/****************************************************************************************************************************************/
/* Function: FileDateTime(DateTime_t *); */
/* */
/* Description: This function calculates the DOS date time from a pointer to a time structure. */
/* */
/* Returnvalue: Returns the DOS date time. */
/****************************************************************************************************************************************/
 
uint32_t FileDateTime(DateTime_t * pTimeStruct)
{
uint32_t datetime = 0;
if((pTimeStruct == 0) || !(pTimeStruct->Valid)) return datetime;
 
datetime |= (0x0000007FL & (uint32_t)(pTimeStruct->Year - 1980))<<25; // set year
datetime |= (0x0000000FL & (uint32_t)(pTimeStruct->Month))<<21; // set month
datetime |= (0x0000001FL & (uint32_t)(pTimeStruct->Day))<<16;
datetime |= (0x0000001FL & (uint32_t)(pTimeStruct->Hour))<<11;
datetime |= (0x0000003FL & (uint32_t)(pTimeStruct->Min))<<5;
datetime |= (0x0000001FL & (uint32_t)(pTimeStruct->Sec/2));
return datetime;
}
 
 
/****************************************************************************************************************************************/
/* Function: LockFilePointer(); */
/* */
/* Description: This function trys to lock a free file pointer. */
/* */
/* Returnvalue: Returns the Filepointer on success or 0. */
/****************************************************************************************************************************************/
File_t * LockFilePointer(void)
{
uint8_t i;
File_t * File = 0;
for(i = 0; i < FILE_MAX_OPEN; i++)
{
if(FilePointer[i].State == FSTATE_UNUSED) // found an unused one
{
File = &FilePointer[i]; // set pointer to that entry
FilePointer[i].State = FSTATE_USED; // mark it as used
break;
}
}
return(File);
}
 
/****************************************************************************************************************************************/
/* Function: UnlockFilePointer(file_t *); */
/* */
/* Description: This function trys to unlock a file pointer. */
/* */
/* Returnvalue: Returns 1 if file pointer was freed else 0. */
/****************************************************************************************************************************************/
uint8_t UnlockFilePointer(File_t * file)
{
uint8_t cnt;
if(file == NULL) return(0);
for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
{
if(&FilePointer[cnt] == file) // filepointer to be freed found?
{
file->State = FSTATE_UNUSED;
file->FirstSectorOfFirstCluster = 0; // Sectorpointer to the first sector of the first datacluster of the file.
file->FirstSectorOfCurrCluster = 0;
file->SectorOfCurrCluster = 0; // Pointer to the cluster which is edited at the moment.
file->SectorOfCurrCluster = 0; // The sector which is edited at the moment (cluster_pointer + sector_index).
file->ByteOfCurrSector = 0; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
file->Mode = 0; // mode of fileoperation (read,write)
file->Size = 0; // the size of the opend file in bytes.
file->Position = 0; // pointer to a character within the file 0 < fileposition < filesize
file->SectorInCache = 0; // the last sector read, wich is still in the sectorbuffer.
file->DirectorySector = 0; // the sectorposition where the directoryentry has been made.
file->DirectoryIndex = 0; // the index to the directoryentry within the specified sector.
file->Attribute = 0; // the attribute of the file opened.
file = NULL;
return(1);
}
}
return(0);
}
 
/****************************************************************************************************************************************/
/* Function: SeperateDirName(int8_t*, int8_t*); */
/* */
/* Description: This function seperates the first dirname from filepath and brings them */
/* into the needed format ('test.txt' -> 'TEST TXT') */
/* The subpath is the pointer to the remaining substring if the filepath */
/* */
/* Returnvalue: Return NULL on error or pointer to subpath */
/****************************************************************************************************************************************/
int8_t* SeperateDirName(const int8_t *filepath, int8_t *dirname)
{
int8_t* subpath = NULL;
uint8_t readpointer = 0;
uint8_t writepointer = 0;
 
// search subpath from beginning of filepath
subpath = NULL;
readpointer = 0;
if(filepath[0] == '/') readpointer = 1; // ignore first '/'
while(subpath == NULL) // search the filepath until a subpath was found.
{
if(((filepath[readpointer] == 0) || (filepath[readpointer] == '/'))) // if '/' found or end of filepath reached
{
subpath = (int8_t*)&filepath[readpointer]; // store the position of the first "/" found after the beginning of the filenpath
}
readpointer++;
}
 
// clear dirname with spaces
dirname[11] = 0; // terminate dirname
for(writepointer = 0; writepointer < 11; writepointer++) dirname[writepointer] = ' ';
writepointer = 0;
// start seperating the dirname from the filepath.
readpointer = 0;
if(filepath[0] == '/') readpointer = 1; // ignore first '/'
while( &filepath[readpointer] < subpath)
{
if(writepointer >= 11) return(NULL); // dirname to long
if(filepath[readpointer] == '.') // seperating dirname and extension.
{
if(writepointer <= 8)
{
readpointer++; // next character in filename
writepointer = 8; // jump to start of extension
}
else return(NULL); // dirbasename to long
}
else
{
if((0x60 < filepath[readpointer]) && (filepath[readpointer] < 0x7B))
{
dirname[writepointer] = (filepath[readpointer] - 0x20); // all characters must be upper case.
}
else
{
dirname[writepointer] = filepath[readpointer];
}
readpointer++;
writepointer++;
}
}
return(subpath);
}
 
 
/**************************************************************************************************************************************+*/
/* Function: Fat16ClusterToSector( uint16_t cluster); */
/* */
/* Description: This function converts a cluster number given by the fat to the corresponding */
/* sector that points to the start of the data area that is represented by the cluster number. */
/* */
/* Returnvalue: The sector number with the data area of the given cluster */
/****************************************************************************************************************************************/
uint32_t Fat16ClusterToSector(uint16_t cluster)
{
if(!Partition.IsValid) return 0;
if (cluster < 2) cluster = 2; // the 0. and 1. cluster in the fat are used for the media descriptor
return ( (cluster - 2) * Partition.SectorsPerCluster) + Partition.FirstDataSector; // the first data sector is represented by the 2nd cluster
}
 
/****************************************************************************************************************************************/
/* Function: SectorToFat16Cluster( uint32_t sector); */
/* */
/* Description: This function converts a given sector number given to the corresponding */
/* cluster number in the fat that represents this data area. */
/* */
/* Returnvalue: The cluster number representing the data area of the sector. */
/****************************************************************************************************************************************/
uint16_t SectorToFat16Cluster(uint32_t sector)
{
if(!Partition.IsValid) return 0;
return ((uint16_t)((sector - Partition.FirstDataSector) / Partition.SectorsPerCluster) + 2);
}
 
 
/****************************************************************************************************************************************/
/* Function: Fat16_Deinit(void); */
/* */
/* Description: This function uninitializes the fat 16 api */
/* */
/* Returnvalue: The function returns "0" on success */
/****************************************************************************************************************************************/
uint8_t Fat16_Deinit(void)
{
int16_t returnvalue = 0;
uint8_t cnt;
// declare the filepointers as unused.
for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
{
if(FilePointer[cnt].State == FSTATE_USED)
{
returnvalue += fclose_(&FilePointer[cnt]); // try to close open file pointers
}
 
}
SDC_Deinit(); // uninitialize interface to sd-card
Partition.IsValid = 0; // mark data in partition structure as invalid
return(returnvalue);
}
 
/****************************************************************************************************************************************/
/* Function: Fat16_Init(void); */
/* */
/* Description: This function reads the Masterbootrecord and finds the position of the Volumebootrecord, the FAT and the Rootdir */
/* and stores the information in global variables. */
/* */
/* Returnvalue: The function returns "0" if the filesystem is initialized. */
/****************************************************************************************************************************************/
uint8_t Fat16_Init(void)
{
uint8_t cnt = 0;
uint32_t partitionfirstsector;
VBR_Entry_t *VBR;
MBR_Entry_t *MBR;
File_t *file;
uint8_t result = 0;
 
printf("\r\n FAT16 init...");
Partition.IsValid = 0;
 
// declare the filepointers as unused.
for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
{
FilePointer[cnt].State = FSTATE_UNUSED;
}
// set current file pinter to first position in list
file = &FilePointer[0];
 
// try to initialise the sd-card.
if(SD_SUCCESS != SDC_Init())
{
printf("SD-Card could not be initialized.");
result = 1;
goto end;
}
 
// SD-Card is initialized successfully
if(SD_SUCCESS != SDC_GetSector((uint32_t)MBR_SECTOR,file->Cache)) // Read the MasterBootRecord
{
printf("Error reading the MBR.");
result = 2;
goto end;
}
MBR = (MBR_Entry_t *)file->Cache; // Enter the MBR using the structure MBR_Entry_t.
if((MBR->PartitionEntry1.Type == PART_TYPE_FAT16_ST_32_MB) ||
(MBR->PartitionEntry1.Type == PART_TYPE_FAT16_LT_32_MB) ||
(MBR->PartitionEntry1.Type == PART_TYPE_FAT16LBA))
{
// get sector offset 1st partition
partitionfirstsector = MBR->PartitionEntry1.NoSectorsBeforePartition;
// Start of Partition is the Volume Boot Sector
if(SD_SUCCESS != SDC_GetSector(partitionfirstsector,file->Cache)) // Read the volume boot record
{
printf("Error reading the VBR.");
result = 3;
goto end;
}
}
else // maybe the medium has no partition assuming sector 0 is the vbr
{
partitionfirstsector = 0;
}
 
VBR = (VBR_Entry_t *) file->Cache; // Enter the VBR using the structure VBR_Entry_t.
if(VBR->BytesPerSector != BYTES_PER_SECTOR)
{
printf("VBR: Sector size not supported.");
result = 4;
goto end;
}
Partition.SectorsPerCluster = VBR->SectorsPerCluster; // Number of sectors per cluster. Depends on the memorysize of the sd-card.
Partition.FatCopies = VBR->NoFATCopies; // Number of fatcopies.
Partition.MaxRootEntries = VBR->MaxRootEntries; // How many Entries are possible in the rootdirectory (FAT16 allows max. 512 entries).
Partition.SectorsPerFat = VBR->SectorsPerFAT; // The number of sectors per FAT.
 
/* Calculate the sectorpositon of the FAT, the Rootdirectory and the first Datacluster. */
// Calculate the position of the FileAllocationTable:
// Start + # of Reserved Sectors
Partition.FirstFatSector = (uint32_t)(partitionfirstsector + (uint32_t)(VBR->ReservedSectors));
// Calculate the position of the Rootdirectory:
// Start + # of Reserved Sectors + (# of Sectors Per FAT * # of FAT Copies)
Partition.FirstRootDirSector = Partition.FirstFatSector + (uint32_t)((uint32_t)Partition.SectorsPerFat*(uint32_t)Partition.FatCopies);
// Calculate the position of the first datacluster:
// Start + # of Reserved + (# of Sectors Per FAT * # of FAT Copies) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
Partition.FirstDataSector = Partition.FirstRootDirSector + (uint32_t)(Partition.MaxRootEntries>>4); // assuming 512 Byte Per Sector
// Calculate the last data sector
if(VBR->NoSectors == 0)
{
printf("VBR: Bad number of sectors.");
result = 5;
goto end;
}
Partition.LastDataSector = Partition.FirstDataSector + VBR->NoSectors - 1;
// check for FAT16 in VBR of first partition
if(!((VBR->FATName[0]=='F') && (VBR->FATName[1]=='A') && (VBR->FATName[2]=='T') && (VBR->FATName[3]=='1')&&(VBR->FATName[4]=='6')))
{
printf("VBR: Partition ist not FAT16 type.");
result = 6;
goto end;
}
Partition.IsValid = 1; // mark data in partition structure as valid
result = 0;
end:
if(result != 0) Fat16_Deinit();
else printf(" ...ok");
return(result);
}
 
/****************************************************************************************************************************************/
/* Function: Fat16_IsValid(void); */
/* */
/* Description: This function return the Fat 15 filesystem state */
/* */
/* Returnvalue: The function returns "1" on success */
/****************************************************************************************************************************************/
uint8_t Fat16_IsValid(void)
{
return(Partition.IsValid);
}
 
/****************************************************************************************************************************************/
/* Function: ClearCurrCluster(File_t*); */
/* */
/* Description: This function fills the current cluster with 0. */
/* */
/* Returnvalue: The function returns 1 on success else 0. */
/****************************************************************************************************************************************/
uint8_t ClearCurrCluster(File_t * file)
{
uint8_t retvalue = 1;
uint32_t i;
 
if((!Partition.IsValid) || (file == NULL)) return(0);
 
for(i = 0; i < BYTES_PER_SECTOR; i++) file->Cache[i] = 0; // clear file cache
for(i = 0; i < Partition.SectorsPerCluster; i++)
{
file->SectorInCache = file->FirstSectorOfCurrCluster + i;
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
{
Fat16_Deinit();
retvalue = 0;
}
}
return(retvalue);
}
 
/*****************************************************************************************************************************************/
/* Function: GetNextCluster(File_t* ); */
/* */
/* Description: This function finds the next datacluster of the file specified with File *File. */
/* */
/* Returnvalue: The function returns the next cluster or 0 if the last cluster has already reached. */
/*****************************************************************************************************************************************/
uint16_t GetNextCluster(File_t * file)
{
uint16_t cluster = 0;
uint32_t fat_byte_offset, sector, byte;
Fat16Entry_t * fat;
 
if((!Partition.IsValid) || (file == NULL)) return(cluster);
// if sector is within the data area
if((Partition.FirstDataSector <= file->FirstSectorOfCurrCluster)&& (file->FirstSectorOfCurrCluster <= Partition.LastDataSector))
{
// determine current file cluster
cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster);
// calculate byte offset in the fat for corresponding entry
fat_byte_offset = ((uint32_t)cluster)<<1; // two FAT bytes (16 bits) for every cluster
// calculate the sector that contains the current cluster within the fat
sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
// calculate byte offset of the current cluster within that fat sector
byte = fat_byte_offset % BYTES_PER_SECTOR;
// read this sector to the file cache
if(file->SectorInCache != sector)
{
file->SectorInCache = sector; // update sector stored in buffer
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache)) // read sector from sd-card
{
Fat16_Deinit();
return (cluster);
}
}
// read the next cluster from cache
fat = (Fat16Entry_t *)(&(file->Cache[byte]));
cluster = fat->NextCluster;
// if last cluster fat entry
if(FAT16_CLUSTER_LAST_MIN <= cluster)
{
cluster = 0;
}
else
{
file->FirstSectorOfCurrCluster = Fat16ClusterToSector(cluster);
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
}
}
return(cluster);
}
 
 
/****************************************************************************************************************************************/
/* Function: FindNextFreeCluster(File_t *); */
/* */
/* Description: This function looks in the fat to find the next free cluster */
/* */
/* Returnvalue: The function returns the cluster number of the next free cluster found within the fat. */
/****************************************************************************************************************************************/
uint16_t FindNextFreeCluster(File_t *file)
{
uint32_t fat_sector; // current sector within the fat relative to the first sector of the fat.
uint32_t curr_sector; // current sector
uint16_t fat_entry; // index to an fatentry within the actual sector (256 fatentries are possible within one sector).
uint16_t free_cluster = 0; // next free cluster number.
Fat16Entry_t * fat;
 
if((!Partition.IsValid) || (file == NULL)) return(0);
 
// start searching for an empty cluster at the beginning of the fat.
fat_sector = 0;
do
{
curr_sector = Partition.FirstFatSector + fat_sector; // calculate sector to read
file->SectorInCache = curr_sector; // upate the sector number of file cache.
if( SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache)) // read sector of fat from sd-card.
{
Fat16_Deinit();
return(free_cluster);
}
 
fat = (Fat16Entry_t *)file->Cache; // set fat pointer to file cache
 
for(fat_entry = 0; fat_entry < FAT16_ENTRIES_PER_SECTOR; fat_entry++) // look for an free cluster at all entries in this sector of the fat.
{
if(fat[fat_entry].NextCluster == FAT16_CLUSTER_FREE) // empty cluster found!!
{
fat[fat_entry].NextCluster = FAT16_CLUSTER_LAST_MAX; // mark this fat-entry as used
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) // and save the sector at the sd-card.
{
Fat16_Deinit();
return(free_cluster);
}
free_cluster = (uint16_t)(fat_sector * FAT16_ENTRIES_PER_SECTOR + (uint32_t)fat_entry);
fat_entry = FAT16_ENTRIES_PER_SECTOR; // terminate the search for a free cluster in this sector.
}
}
fat_sector++; // continue the search in next fat sector
// repeat until the end of the fat is reached and no free cluster has been found so far
}while((fat_sector < Partition.SectorsPerFat) && (!free_cluster));
return(free_cluster);
}
 
 
/****************************************************************************************************************************************************/
/* Function: int16_t fseek_(File_t *, int32_t *, uint8_t) */
/* */
/* Description: This function sets the pointer of the stream relative to the position */
/* specified by origin (SEEK_SET, SEEK_CUR, SEEK_END) */
/* Returnvalue: Is 1 if seek was successful */
/****************************************************************************************************************************************************/
int16_t fseek_(File_t * const file, int32_t offset, int16_t origin)
{
int32_t fposition = 0;
int16_t retvalue = 1;
 
if((!Partition.IsValid) || (file == NULL)) return(0);
switch(origin)
{
case SEEK_SET: // Fileposition relative to the beginning of the file.
fposition = 0;
break;
case SEEK_END: // Fileposition relative to the end of the file.
fposition = (int32_t)file->Size;
break;
case SEEK_CUR: // Fileposition relative to the current position of the file.
default:
fposition = file->Position;
break;
}
 
fposition += offset;
 
if((fposition >= 0) && (fposition <= (int32_t)file->Size)) // is the pointer still within the file?
{
// reset file position to start of the file
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
file->Position = 0;
 
while(file->Position < fposition) // repeat until the current position is less than target
{
file->Position++; // increment file position
file->ByteOfCurrSector++; // next byte in current sector
if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)
{
file->ByteOfCurrSector = 0; // reading at the beginning of new sector.
file->SectorOfCurrCluster++; // continue reading in next sector
if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster) // if end of cluster is reached, the next datacluster has to be searched in the FAT.
{
if(GetNextCluster(file)) // Sets the clusterpointer of the file to the next datacluster.
{
file->SectorOfCurrCluster = 0;
}
else // the last cluster was allready reached
{
file->SectorOfCurrCluster--; // jump back to the ast sector in the last cluster
file->ByteOfCurrSector = BYTES_PER_SECTOR; // set ByteOfCurrSector one byte over sector end
}
}
}
}
}
if(file->Position == fposition) retvalue = 0;
return(retvalue);
}
 
 
/****************************************************************************************************************************************/
/* Function: uint16_t DeleteClusterChain(File *file); */
/* */
/* Description: This function trances along a cluster chain in the fat and frees all clusters visited. */
/* */
/****************************************************************************************************************************************/
uint8_t DeleteClusterChain(uint16_t StartCluster)
{
uint16_t cluster;
uint32_t fat_byte_offset, sector, byte;
Fat16Entry_t * fat;
uint8_t buffer[BYTES_PER_SECTOR];
uint32_t sector_in_buffer = 0;
uint8_t repeat = 0;
 
if(!Partition.IsValid) return 0;
 
cluster = StartCluster; // init chain trace
// calculate byte offset in the fat for corresponding entry
fat_byte_offset = ((uint32_t)cluster)<<1; // two FAT bytes (16 bits) for every cluster
// calculate the sector that contains the current cluster within the fat
sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
// calculate byte offset of the current cluster within that fat sector
byte = fat_byte_offset % BYTES_PER_SECTOR;
do
{
if(sector != sector_in_buffer)
{
// read this sector to buffer
sector_in_buffer = sector;
if(SD_SUCCESS != SDC_GetSector(sector_in_buffer, buffer)) return 0; // read sector from sd-card
}
// read the next cluster from cache
fat = (Fat16Entry_t *)(&(buffer[byte]));
cluster = fat->NextCluster;
if((FAT16_CLUSTER_USED_MIN <= cluster) && (cluster <= FAT16_CLUSTER_USED_MAX) ) repeat = 1;
else repeat = 0;
 
fat->NextCluster = FAT16_CLUSTER_FREE; // mark current cluster as free
// calculate byte offset in the fat for corresponding entry
fat_byte_offset = ((uint32_t)cluster)<<1; // two FAT bytes (16 bits) for every cluster
// calculate the sector that contains the current cluster within the fat
sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
// calculate byte offset of the current cluster within that fat sector
byte = fat_byte_offset % BYTES_PER_SECTOR;
// if new sector is not the sector in buffer or the last cluster in the chain was traced
if((sector != sector_in_buffer) || !repeat)
{ // write sector in buffer
if(SD_SUCCESS != SDC_PutSector(sector_in_buffer,buffer)) return 0;
}
}
while(repeat);
 
return 1;
}
 
 
/****************************************************************************************************************************************/
/* Function: uint16_t AppendCluster(File *file); */
/* */
/* Description: This function looks in the fat to find the next free cluster and appends it to the file. */
/* */
/* Returnvalue: The function returns the appened cluster number or 0 of no cluster was appended. */
/****************************************************************************************************************************************/
uint16_t AppendCluster(File_t *file)
{
uint16_t last_cluster, new_cluster = 0;
uint32_t fat_byte_offset, sector, byte;
Fat16Entry_t * fat;
 
if((!Partition.IsValid) || (file == NULL)) return(new_cluster);
 
new_cluster = FindNextFreeCluster(file); // the next free cluster found on the disk.
if(new_cluster)
{ // A free cluster was found and can be added to the end of the file.
fseek_(file, 0, SEEK_END); // jump to the end of the file
last_cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster); // determine current file cluster
fat_byte_offset = ((uint32_t)last_cluster)<<1;
sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
byte = fat_byte_offset % BYTES_PER_SECTOR;
 
if(file->SectorInCache != sector)
{
file->SectorInCache = sector; // update sector stored in buffer
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache)) // read sector from sd-card
{
Fat16_Deinit();
return(0);
}
}
fat = (Fat16Entry_t *)(&(file->Cache[byte]));
fat->NextCluster = new_cluster; // append the free cluster to the end of the file in the FAT.
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) // save the modified sector to the FAT.
{
Fat16_Deinit();
return(0);
}
file->FirstSectorOfCurrCluster = Fat16ClusterToSector(new_cluster);
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
}
return(new_cluster);
}
 
/****************************************************************************************************************************************************/
/* Function: DirectoryEntryExist(int8_t *, uint8_t, uint8_t, File_t *) */
/* */
/* Description: This function searches all possible dir entries until the file or directory is found or the end of the directory is reached */
/* */
/* Returnvalue: This function returns 1 if the directory entry specified was found. */
/****************************************************************************************************************************************************/
uint8_t DirectoryEntryExist(int8_t *dirname, uint8_t attribfilter, uint8_t attribmask, File_t *file)
{
uint32_t dir_sector, max_dir_sector, curr_sector;
uint16_t dir_entry = 0;
 
uint16_t end_of_directory_not_reached = 0;
uint8_t i = 0;
uint8_t direntry_exist = 0;
DirEntry_t * dir;
 
// if incomming pointers are useless return immediatly
if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return(direntry_exist);
 
// dir entries can be searched only in filesclusters that have
// a corresponding dir entry with adir-flag set in its attribute
// or direct within the root directory area
 
file->FirstSectorOfFirstCluster = 0;
// no current directory exist therefore assume searching in the root
if(file->DirectorySector == 0)
{
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
}
// within the root directory area we can read sectors sequentially until the end of this area
else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
{
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
}
// within the data clusters we can read sectors sequentially only within the cluster
else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
{
max_dir_sector = Partition.SectorsPerCluster; // limit max secters before next cluster
}
else return (direntry_exist); // bad sector range for directory sector of the file
// if search area is not defined yet
if(file->FirstSectorOfFirstCluster == 0)
{
// check if the directory entry of current file is existent and has the dir-flag set
file->SectorInCache = file->DirectorySector; // update the sector number of file cache.
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(direntry_exist);
}
dir = (DirEntry_t *)file->Cache; // set pointer to directory
switch((uint8_t)dir[file->DirectoryIndex].Name[0]) // check if current directory exist
{
case SLOT_EMPTY:
case SLOT_DELETED:
// the directrory pointer of this file points to a deleted or not existen directory
// therefore no file or subdirectory can be created
return (direntry_exist);
break;
default: // and is a real directory
if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
{ // current file is not a directory therefore no file or subdirectory can be created here
return (direntry_exist);
}
break;
}
file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[file->DirectoryIndex].StartCluster);
}
 
// update current file data area position to start of first cluster
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
 
do // loop over all data clusters of the current directory entry
{
dir_sector = 0; // reset sector counter within a new cluster
do // loop over all sectors of a cluster or all sectors of the root directory
{
curr_sector = file->FirstSectorOfCurrCluster + dir_sector; // calculate sector number
file->SectorInCache = curr_sector; // upate the sector number of file cache.
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
{
Fat16_Deinit();
return(direntry_exist);
}
dir = (DirEntry_t *)file->Cache; // set pointer to directory
// search all directory entries within that sector
for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
{ // check for existing dir entry
switch((uint8_t)dir[dir_entry].Name[0])
{
case SLOT_EMPTY:
case SLOT_DELETED:
// ignore empty or deleted dir entries
break;
default:
// if existing check attributes before names are compared will safe performance
if ((dir[dir_entry].Attribute & attribmask) != attribfilter) break; // attribute must match
// then compare the name to the giveb dirname (first 11 characters include 8 chars of basename and 3 chars extension.)
i = 0;
while((i < 11) && (dir[dir_entry].Name[i] == dirname[i])) i++;
if (i < 10) break; // names does not match
// if dirname and attribute have matched
file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
file->DirectorySector = curr_sector; // current sector
file->DirectoryIndex = dir_entry; // current direntry in current sector
file->Size = dir[dir_entry].Size;
direntry_exist = 1; // mark as found
dir_entry = DIRENTRIES_PER_SECTOR; // stop for-loop
} // end of first byte of name check
}
dir_sector++; // search next sector
// stop if we reached the end of the cluster or the end of the root dir
}while((dir_sector < max_dir_sector) && (!direntry_exist));
 
// if we are seaching in the data area and the file not found in this cluster so take next cluster.
if(!direntry_exist && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
{
end_of_directory_not_reached = GetNextCluster(file); // updates File->FirstSectorOfCurrCluster
}
}while((end_of_directory_not_reached) && (!direntry_exist)); // repeat until a next cluster exist an no
return(direntry_exist);
}
 
 
/****************************************************************************************************************************************/
/* Function: CreateDirectoryEntry(int8_t *, uint16_t, File_t *) */
/* */
/* Description: This function looks for the next free position in the directory and creates an entry. */
/* The type of an directory entry is specified by the file attribute. */
/* */
/* Returnvalue: Return 0 on error */
/****************************************************************************************************************************************/
uint8_t CreateDirectoryEntry(int8_t *dirname, uint8_t attrib, File_t *file)
{
uint32_t dir_sector, max_dir_sector, curr_sector;
uint16_t dir_entry = 0;
uint16_t subdircluster, dircluster = 0;
uint16_t end_of_directory_not_reached = 0;
uint8_t i = 0;
uint8_t retvalue = 0;
DirEntry_t* dir;
 
if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return (retvalue);
// It is not checked here that the dir entry that should be created is already existent!
 
// Dir entries can be created only in file-clusters that have
// the dir-flag set in its attribute or within the root directory
 
file->FirstSectorOfFirstCluster = 0;
// no current directory exist therefore assume creating in the root
if(file->DirectorySector == 0)
{
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
dircluster = 0;
file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
}
// within the root directory area we can read sectors sequentially until the end of this area
else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
{
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
}
// within the data clusters we can read sectors sequentially only within the cluster
else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
{
max_dir_sector = Partition.SectorsPerCluster;
}
else return (retvalue); // bad sector range for directory sector of the file
// if search area is not defined yet
if(file->FirstSectorOfFirstCluster == 0)
{
// check if the directory entry of current file is existent and has the dir-flag set
file->SectorInCache = file->DirectorySector; // update the sector number of file cache.
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(retvalue);
}
dir = (DirEntry_t *)file->Cache; // set pointer to directory
switch((uint8_t)dir[file->DirectoryIndex].Name[0]) // check if current directory exist
{
case SLOT_EMPTY:
case SLOT_DELETED:
return (retvalue);
break;
default: // and is a real directory
if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
{ // current file is not a directory therefore no file or subdirectory can be created here
return (retvalue);
}
break;
}
dircluster = dir[file->DirectoryIndex].StartCluster;
file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dircluster);
}
 
subdircluster = FindNextFreeCluster(file); // get the next free cluster on the disk and mark it as used.
if(subdircluster)
{
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
file->SectorOfCurrCluster = 0;
do // loop over all clusters of current directory
{
dir_sector = 0; // reset sector counter within a new cluster
do // loop over all sectors of a cluster or all sectors of the root directory
{
curr_sector = file->FirstSectorOfCurrCluster + dir_sector; // calculate sector number
file->SectorInCache = curr_sector; // upate the sector number of file cache.
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(retvalue);
}
dir = (DirEntry_t *)file->Cache; // set pointer to directory
// search all directory entries of a sector
for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
{ // check if current direntry is available
if(((uint8_t)dir[dir_entry].Name[0] == SLOT_EMPTY) || ((uint8_t)dir[dir_entry].Name[0] == SLOT_DELETED))
{ // a free direntry was found
for(i = 0; i < 11; i++) dir[dir_entry].Name[i] = dirname[i]; // Set dir name
dir[dir_entry].Attribute = attrib; // Set the attribute of the new directoryentry.
dir[dir_entry].StartCluster = subdircluster; // copy the location of the first datacluster to the directoryentry.
dir[dir_entry].DateTime = FileDateTime(&SystemTime); // set date/time
dir[dir_entry].Size = 0; // the new createted file has no content yet.
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) // write back to card
{
Fat16_Deinit();
return(retvalue);
}
file->FirstSectorOfFirstCluster = Fat16ClusterToSector(subdircluster); // Calculate absolute sectorposition of first datacluster.
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster; // Start reading the file with the first sector of the first datacluster.
file->SectorOfCurrCluster = 0; // reset sector of cureen cluster
file->ByteOfCurrSector = 0; // reset the byte location within the current sector
file->Attribute = attrib; // set file attribute to dir attribute
file->Size = 0; // new file has no size
file->DirectorySector = curr_sector;
file->DirectoryIndex = dir_entry;
if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY) // if a new directory was created then initilize the data area
{
ClearCurrCluster(file); // fill cluster with zeros
file->SectorInCache = file->FirstSectorOfFirstCluster;
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(retvalue);
}
dir = (DirEntry_t *)file->Cache;
// create direntry "." to current dir
dir[0].Name[0] = 0x2E;
for(i = 1; i < 11; i++) dir[0].Name[i] = ' ';
dir[0].Attribute = ATTR_SUBDIRECTORY;
dir[0].StartCluster = subdircluster;
dir[0].DateTime = 0;
dir[0].Size = 0;
// create direntry ".." to the upper dir
dir[1].Name[0] = 0x2E;
dir[1].Name[1] = 0x2E;
for(i = 2; i < 11; i++) dir[1].Name[i] = ' ';
dir[1].Attribute = ATTR_SUBDIRECTORY;
dir[1].StartCluster = dircluster;
dir[1].DateTime = 0;
dir[1].Size = 0;
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// read in the sector.
{
Fat16_Deinit();
return(retvalue);
}
}
retvalue = 1;
dir_entry = DIRENTRIES_PER_SECTOR; // stop for-loop
}
}
dir_sector++; // search next sector
// stop if we reached the end of the cluster or the end of the root dir
}while((dir_sector < max_dir_sector) && (!retvalue));
 
// if we are seaching in the data area and the file not found in this cluster so take next cluster.
if(!retvalue && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
{
end_of_directory_not_reached = GetNextCluster(file); // updates File->FirstSectorOfCurrCluster
}
}while((end_of_directory_not_reached) && (!retvalue));
// Perhaps we are at the end of the last cluster of a directory file an have no free direntry found.
// Then we would need to add a cluster to that file and create the new direntry there.
// This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are
// within a subdirectory of root.
}
return(retvalue); // return 1 if file has been created otherwise return 0.
}
 
/********************************************************************************************************************************************/
/* Function: FileExist(const int8_t* filename, uint8_t attribfilter, uint8_t attribmask, File_t *file); */
/* */
/* Description: This function looks for the specified file including its subdirectories beginning */
/* in the rootdirectory of the drive. If the file is found the Filepointer properties are */
/* updated. */
/* */
/* Returnvalue: 1 if file is found else 0. */
/********************************************************************************************************************************************/
uint8_t FileExist(const int8_t* filename, const uint8_t attribfilter, const uint8_t attribmask, File_t *file)
{
int8_t* path = 0;
int8_t* subpath = 0;
uint8_t af, am, file_exist = 0;
int8_t dirname[12]; // 8+3 + temination character
 
// if incomming pointers are useless return immediatly
if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
 
// trace along the filepath
path = (int8_t*)filename; // start a the beginning of the filename string
file->DirectorySector = 0; // start at RootDirectory with file search
file->DirectoryIndex = 0;
// as long as the file was not found and the remaining path is not empty
while((*path != 0) && !file_exist)
{ // separate dirname and subpath from filepath string
subpath = SeperateDirName(path, dirname);
if(subpath != NULL)
{
if(*subpath == 0)
{ // empty subpath indicates last element of dir chain
af = attribfilter;
am = attribmask;
}
else // it must be a subdirectory and no volume label
{
af = ATTR_SUBDIRECTORY;
am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
}
if(!DirectoryEntryExist(dirname, af, am, file))
{
return (file_exist); // subdirectory does not exist
}
else
{
if (*subpath == 0)
{
file_exist = 1; // last element of path chain was found with the given attribute filter
}
}
}
else // error seperating the subpath
{
return file_exist; // bad subdir format
}
path = subpath;
subpath = 0;
}
return (file_exist);
}
 
 
/********************************************************************************************************************************************/
/* Function: FileCreate(const s8* filename, u8 attrib, File_t *file); */
/* */
/* Description: This function looks for the specified file including its subdirectories beginning */
/* in the rootdirectory of the partition. If the file is found the Filepointer properties are */
/* updated. If file or its subdirectories are not found they will be created */
/* */
/* Returnvalue: 1 if file was created else 0. */
/********************************************************************************************************************************************/
uint8_t FileCreate(const int8_t* filename, const uint8_t attrib, File_t *file)
{
int8_t *path = 0;
int8_t *subpath = 0;
uint8_t af, am, file_created = 0;
int8_t dirname[12];
 
// if incomming pointers are useless return immediatly
if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
 
// trace along the filepath
path = (int8_t*)filename; // start a the beginning of the filename string
file->DirectorySector = 0; // start at RootDirectory with file search
file->DirectoryIndex = 0;
// as long as the file was not created and the remaining file path is not empty
while((*path != 0) && !file_created)
{ // separate dirname and subpath from filepath string
subpath = SeperateDirName(path, dirname);
if(subpath != NULL)
{
if(*subpath == 0)
{ // empty subpath indicates last element of dir chain
af = ATTR_NONE;
am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL; // any file that is no subdir or volume label
}
else // it must be a subdirectory and no volume label
{
af = ATTR_SUBDIRECTORY;
am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
}
if(!DirectoryEntryExist(dirname, af, am, file)) // if subdir or file is not existent
{ // try to create subdir or file
if(*subpath == 0) af = attrib; // if last element in dir chain take the given attribute
if(!CreateDirectoryEntry(dirname, af, file))
{ // could not be created
return(file_created);
}
else if (*subpath == 0) file_created = 1; // last element of path chain was created
}
}
else // error seperating the subpath
{
return file_created; // bad subdir format
}
path = subpath;
subpath = 0;
}
return (file_created);
}
 
 
/********************************************************************************************************************************************/
/* Function: File_t * fopen_(int8_t* filename, int8_t mode); */
/* */
/* Description: This function looks for the specified file in the rootdirectory of the drive. If the file is found the number of the */
/* corrosponding filepointer is returned. Only modes 'r' (reading) and 'a' append are implemented yet. */
/* */
/* Returnvalue: The filepointer to the file or 0 if faild. */
/********************************************************************************************************************************************/
File_t * fopen_(int8_t * const filename, const int8_t mode)
{
File_t *file = 0;
 
if((!Partition.IsValid) || (filename == 0)) return(file);
 
// Look for an unused filepointer in the file pointer list?
file = LockFilePointer();
// if no unused file pointer was found return 0
if(file == NULL) return(file);
 
// now we have found a free filepointer and claimed it
// so let initiate its property values
file->FirstSectorOfFirstCluster = 0; // Sectorpointer to the first sector of the first datacluster of the file.
file->FirstSectorOfCurrCluster = 0; // Pointer to the cluster which is edited at the moment.
file->SectorOfCurrCluster = 0; // The sector which is edited at the moment (cluster_pointer + sector_index).
file->ByteOfCurrSector = 0; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
file->Mode = mode; // mode of fileoperation (read,write)
file->Size = 0; // the size of the opened file in bytes.
file->Position = 0; // pointer to a byte within the file 0 < fileposition < filesize
file->SectorInCache = 0; // the last sector read, wich is still in the sectorbuffer.
file->DirectorySector = 0; // the sectorposition where the directoryentry has been made.
file->DirectoryIndex = 0; // the index to the directoryentry within the specified sector.
file->Attribute = 0; // the attribute of the file opened.
 
// check if a real file (no directory) to the given filename exist
if(FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file))
{ // file exist
switch(mode) // check mode
{
case 'a': // if mode is: append to file
if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
{ // file is marked as readonly --> do not open this file
fclose_(file);
file = NULL;
}
else
{ // file is not marked as read only --> goto end of file
fseek_(file, 0, SEEK_END); // point to the end of the file
}
break;
case 'w': // if mode is: write to file
if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
{ // file is marked as readonly --> do not open this file
fclose_(file);
file = NULL;
}
else
{ // file is not marked as read only --> goto start of file
// free all clusters of that file
DeleteClusterChain(SectorToFat16Cluster(file->FirstSectorOfFirstCluster));
// mar an empy cluster as the last one and store the corresponding sector
file->FirstSectorOfFirstCluster = Fat16ClusterToSector(FindNextFreeCluster(file));
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
file->SectorOfCurrCluster = 0;
file->ByteOfCurrSector = 0;
file->Size = 0;
file->Position = 0;
fseek_(file, 0, SEEK_SET);
}
break;
case 'r': // if mode is: read from file
// goto end of file
fseek_(file, 0, SEEK_SET);
break;
default: // other modes are not supported
fclose_(file);
file = NULL;
break;
}
return(file);
}
else // file does not exist
{
switch(mode) // check mode
{
case 'a':
case 'w': // if mode is write or append
// try to create the file
if(!FileCreate(filename, ATTR_ARCHIVE, file))
{ // if it could not be created
fclose_(file);
file = NULL;
}
break;
case 'r': // else opened for 'r'
default: // of unsupported mode
fclose_(file);
file = NULL;
break;
}
return(file);
}
// we should never come to this point
fclose_(file);
file = NULL;
return(file);
}
 
/****************************************************************************************************************************************************/
/* Function: fflush_(File *); */
/* */
/* Description: This function writes the data already in the buffer but not yet written to the file. */
/* */
/* Returnvalue: 0 on success EOF on error */
/****************************************************************************************************************************************************/
int16_t fflush_(File_t * const file)
{
DirEntry_t *dir;
 
if((file == NULL) || (!Partition.IsValid)) return (EOF);
 
switch(file->Mode)
{
case 'a':
case 'w':
if(file->ByteOfCurrSector > 0) // has data been added to the file?
{
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// save the data still in the buffer
{
Fat16_Deinit();
return(EOF);
}
}
file->SectorInCache = file->DirectorySector;
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache)) // read the directory entry for this file.
{
Fat16_Deinit();
return(EOF);
}
 
dir = (DirEntry_t *)file->Cache;
dir[file->DirectoryIndex].Size = file->Size; // update file size
dir[file->DirectoryIndex].DateTime = FileDateTime(&SystemTime); // update date time
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) // write back to sd-card
{
Fat16_Deinit();
return(EOF);
}
break;
case 'r':
default:
return(EOF);
break;
 
}
return(0);
}
 
/****************************************************************************************************************************************/
/* Function: 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. */
/* */
/* Returnvalue: 0 on success EOF on error */
/****************************************************************************************************************************************/
int16_t fclose_(File_t *file)
{
int16_t returnvalue = EOF;
 
if(file == NULL) return(returnvalue);
returnvalue = fflush_(file);
UnlockFilePointer(file);
return(returnvalue);
}
 
/********************************************************************************************************************************************/
/* Function: fgetc_(File *file); */
/* */
/* Description: This function reads and returns one character from the specified file. Is the end of the actual sector reached the */
/* next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT. */
/* */
/* Returnvalue: The function returns the character read from the specified memorylocation as u8 casted to s16 or EOF. */
/********************************************************************************************************************************************/
int16_t fgetc_(File_t * const file)
{
int16_t c = EOF;
uint32_t curr_sector;
 
if( (!Partition.IsValid) || (file == NULL)) return(c);
// if the end of the file is not reached, get the next character.
if((0 < file->Size) && ((file->Position+1) < file->Size) )
{
curr_sector = file->FirstSectorOfCurrCluster; // calculate the sector of the next character to be read.
curr_sector += file->SectorOfCurrCluster;
 
if(file->SectorInCache != curr_sector)
{
file->SectorInCache = curr_sector;
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache,file->Cache))
{
Fat16_Deinit();
return(c);
}
}
c = (int16_t) file->Cache[file->ByteOfCurrSector];
file->Position++; // increment file position
file->ByteOfCurrSector++; // goto next byte in sector
if(file->ByteOfCurrSector >= BYTES_PER_SECTOR) // if end of sector
{
file->ByteOfCurrSector = 0; // reset byte location
file->SectorOfCurrCluster++; // next sector
if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster) // if end of cluster is reached, the next datacluster has to be searched in the FAT.
{
 
if(GetNextCluster(file)) // Sets the clusterpointer of the file to the next datacluster.
{
file->SectorOfCurrCluster = 0; // start reading new cluster at first sector of the cluster.
}
else // the last cluster was allready reached
{
file->SectorOfCurrCluster--; // jump back to the last sector in the last cluster
file->ByteOfCurrSector = BYTES_PER_SECTOR; // set ByteOfCurrSector one byte over sector end
}
}
}
}
return(c);
}
 
/********************************************************************************************************************************************/
/* Function: fputc_( const s8 c, File *file); */
/* */
/* Description: This function writes a byte to the specified file and takes care of writing the necessary FAT- Entries. */
/* next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT. */
/* */
/* Returnvalue: The function returns the character written to the stream or EOF on error. */
/********************************************************************************************************************************************/
int16_t fputc_(const int8_t c, File_t * const file)
{
uint32_t curr_sector = 0;
 
if((!Partition.IsValid) || (file == NULL)) return(EOF);
 
// If file position equals to file size, then the end of file has reached.
// In this chase it has to be checked that the ByteOfCurrSector is BYTES_PER_SECTOR
// and a new cluster should be appended.
if((file->Position >= file->Size) && (file->ByteOfCurrSector >= BYTES_PER_SECTOR))
{
if(!AppendCluster(file)) return(EOF);
}
 
curr_sector = file->FirstSectorOfCurrCluster;
curr_sector += file->SectorOfCurrCluster;
if(file->SectorInCache != curr_sector)
{
file->SectorInCache = curr_sector;
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))
{
Fat16_Deinit();
return(EOF);
}
}
 
file->Cache[file->ByteOfCurrSector] = (uint8_t)c; // write databyte into the buffer. The byte will be written to the device at once
if(file->Size == file->Position) file->Size++; // a character has been written to the file so the size is incremented only when the character has been added at the end of the file.
file->Position++; // the actual positon within the file.
file->ByteOfCurrSector++; // goto next byte in sector
if(file->ByteOfCurrSector >= BYTES_PER_SECTOR) // if the end of this sector is reached yet
{ // save the sector to the sd-card
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
{
Fat16_Deinit();
return(EOF);
}
file->ByteOfCurrSector = 0; // reset byte location
file->SectorOfCurrCluster++; // next sector
if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)// if end of cluster is reached, the next datacluster has to be searched in the FAT.
{
if(!GetNextCluster(file)) // Sets the clusterpointer of the file to the next datacluster.
{ // if current cluster was the last cluster of the file
if(!AppendCluster(file)) // append a new and free cluster at the end of the file.
{
file->SectorOfCurrCluster--; // jump back to last sector of last cluster
file->ByteOfCurrSector = BYTES_PER_SECTOR; // set byte location to 1 byte over sector len
return(EOF);
}
}
else // next cluster
{
file->SectorOfCurrCluster = 0; // start reading new cluster at first sector of the cluster.
}
}
}
return(0);
}
 
 
/****************************************************************************************************************************************/
/* Function: fread_(void *buffer, uint32_t size, uint32_t 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. */
/****************************************************************************************************************************************/
uint32_t fread_(void * const buffer, uint32_t size, uint32_t count, File_t * const file)
{
uint32_t object_cnt = 0; // count the number of objects read from the file.
uint32_t object_size = 0; // count the number of bytes read from the actual object.
uint8_t *pbuff = 0; // a pointer to the actual bufferposition.
uint8_t success = 1; // no error occured during read operation to the file.
int16_t c;
 
if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
 
pbuff = (uint8_t *) buffer; // cast the void pointer to an u8 *
 
while((object_cnt < count) && success)
{
object_size = size;
while((size > 0) && success)
{
c = fgetc_(file);
if(c != EOF)
{
*pbuff = (uint8_t)c; // read a byte from the buffer to the opened file.
pbuff++;
size--;
}
else // error or end of file reached
{
success = 0;
}
}
if(success) object_cnt++;
}
return(object_cnt); // return the number of objects succesfully read from the file
}
 
 
/****************************************************************************************************************************************/
/* Function: fwrite_(void *buffer, uint32_t size, uint32_t count, File *file); */
/* */
/* Description: This function writes count objects of the specified size */
/* from the buffer pointer to the actual position in the file. */
/* */
/* Returnvalue: The function returns the number of objects (not bytes) read from the file. */
/****************************************************************************************************************************************/
uint32_t fwrite_(void * const buffer, uint32_t size, uint32_t count, File_t * const file)
{
uint32_t object_cnt = 0; // count the number of objects written to the file.
uint32_t object_size = 0; // count the number of bytes written from the actual object.
uint8_t *pbuff = 0; // a pointer to the actual bufferposition.
uint8_t success = 1; // no error occured during write operation to the file.
int16_t c;
 
if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
 
pbuff = (uint8_t *) buffer; // cast the void pointer to an u8 *
 
while((object_cnt < count) && success)
{
object_size = size;
while((size > 0) && success)
{
c = fputc_(*pbuff, file); // write a byte from the buffer to the opened file.
if(c != EOF)
{
pbuff++;
size--;
}
else
{
success = 0;
}
}
if(success) object_cnt++;
}
 
return(object_cnt); // return the number of objects succesfully written to the file
}
 
 
/****************************************************************************************************************************************/
/* Function: fputs_(const int8_t *string, File_t *File); */
/* */
/* Description: This function writes a string to the specified file. */
/* */
/* Returnvalue: The function returns a no negative value or EOF on error. */
/****************************************************************************************************************************************/
int16_t fputs_(int8_t * const string, File_t * const file)
{
uint8_t i=0;
int16_t c = 0;
 
if((!Partition.IsValid) || (file == NULL) || (string == NULL)) return(0);
 
while((string[i] != 0)&& (c != EOF))
{
c = fputc_(string[i], file);
i++;
}
return(c);
}
 
/****************************************************************************************************************************************/
/* Function: fgets_(int8 *, int16_t , File_t *); */
/* */
/* Description: This function reads a string from the file to the specifies string. */
/* */
/* Returnvalue: A pointer to the string read from the file or 0 on error. */
/****************************************************************************************************************************************/
int8_t * fgets_(int8_t * const string, int16_t length, File_t * const file)
{
int8_t *pbuff;
int16_t c = 0, bytecount;
 
if((!Partition.IsValid) || (file == NULL) || (string == NULL) || (length > 1)) return (0);
pbuff = string;
bytecount = length;
while(bytecount > 1) // read the count-1 characters from the file to the string.
{
c = fgetc_(file); // read a character from the opened file.
switch(c)
{
case 0x0A:
*pbuff = 0; // set string terminator
return(string); // stop loop
break;
 
case EOF:
*pbuff = 0; // set string terminator
return(0);
default:
*pbuff++ = (int8_t)c; // copy byte to string
bytecount--;
break;
}
}
*pbuff = 0;
return(string);
}
 
/****************************************************************************************************************************************/
/* Function: fexist_(const int8_t*); */
/* */
/* Description: This function checks if a file already exist. */
/* */
/* Returnvalue: 1 if the file exist else 0. */
/****************************************************************************************************************************************/
uint8_t fexist_(int8_t* const filename)
{
uint8_t exist = 0;
File_t *file = 0;
file = LockFilePointer();
exist = FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file);
UnlockFilePointer(file);
return(exist);
}
 
/****************************************************************************************************************************************/
/* Function: feof_(File_t *File); */
/* */
/* Description: This function checks wether the end of the file has been reached. */
/* */
/* Returnvalue: 0 if the end of the file was not reached otherwise 1. */
/****************************************************************************************************************************************/
uint8_t feof_(File_t *file)
{
if(((file->Position)+1) < (file->Size))
{
return(0);
}
else
{
return(1);
}
}
 
 
/FollowMe/trunk/fat16.h
0,0 → 1,70
#ifndef _FAT16_H
#define _FAT16_H
 
 
//________________________________________________________________________________________________________________________________________
//
// Definitions
//
//________________________________________________________________________________________________________________________________________
 
//#define __USE_TIME_DATE_ATTRIBUTE
#define FILE_MAX_OPEN 3 // The number of files that can accessed simultaneously.
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define EOF (-1)
#define BYTES_PER_SECTOR 512
/*
________________________________________________________________________________________________________________________________________
 
Structure of a filepointer
________________________________________________________________________________________________________________________________________
*/
typedef struct
{
uint32_t FirstSectorOfFirstCluster; // First sector of the first cluster of the file.
uint32_t FirstSectorOfCurrCluster; // First sector of the cluster which is edited at the moment.
uint8_t SectorOfCurrCluster; // The sector within the current cluster.
uint16_t ByteOfCurrSector; // The byte location within the current sector.
uint8_t Mode; // Mode of fileoperation (read,write)
uint32_t Size; // The size of the opend file in bytes.
uint32_t Position; // Pointer to a character within the file 0 < fileposition < filesize
uint32_t DirectorySector; // the sectorposition where the directoryentry has been made.
uint16_t DirectoryIndex; // The index to the directoryentry within the specified sector.
uint8_t Attribute; // The attribute of the file opened.
uint8_t Cache[BYTES_PER_SECTOR]; // Cache for read and write operation from or to the sd-card.
uint32_t SectorInCache; // The last sector read, which is still in the sector cache.
uint8_t State; // State of the filepointer (used/unused/...)
} File_t;
 
//________________________________________________________________________________________________________________________________________
//
// API to the FAT16 filesystem
//
//________________________________________________________________________________________________________________________________________
 
extern uint8_t Fat16_Init(void);
extern uint8_t Fat16_Deinit(void);
extern uint8_t Fat16_IsValid(void);
 
extern File_t * fopen_(int8_t * const filename, const int8_t mode);
extern int16_t fclose_(File_t *file);
extern uint8_t fexist_(int8_t * const filename);
extern int16_t fflush_(File_t * const file);
extern int16_t fseek_(File_t * const file, int32_t offset, int16_t origin);
extern int16_t fgetc_(File_t * const file);
extern int16_t fputc_(const int8_t c, File_t * const file);
extern uint32_t fread_(void * const buffer, uint32_t size, uint32_t count, File_t * const file);
extern uint32_t fwrite_(void *buffer, uint32_t size, uint32_t count, File_t *file);
extern int16_t fputs_(int8_t * const string, File_t * const file);
extern int8_t * fgets_(int8_t * const string, const int16_t length, File_t * const file);
extern uint8_t feof_(File_t * const file);
 
 
 
#endif //_FAT16_H
 
 
 
 
/FollowMe/trunk/gps.c
0,0 → 1,98
#include "gps.h"
#include "uart0.h"
#include "main.h"
#include "timer0.h"
 
#define GPS_TIMEOUT 1000 // of ne new gps data arrivw within that time an error ist set
#define GPS_MINSATS 4
 
//------------------------------------------------------------
// copy GPS position from source position to target position
uint8_t GPS_CopyPosition(GPS_Pos_t * pGPSPosSrc, GPS_Pos_t* pGPSPosTgt)
{
uint8_t retval = 0;
if((pGPSPosSrc == 0) || (pGPSPosTgt == 0)) return(retval); // bad pointer
// copy only valid positions
if(pGPSPosSrc->Status != INVALID)
{
// if the source GPS position is not invalid
pGPSPosTgt->Longitude = pGPSPosSrc->Longitude;
pGPSPosTgt->Latitude = pGPSPosSrc->Latitude;
pGPSPosTgt->Altitude = pGPSPosSrc->Altitude;
pGPSPosTgt->Status = NEWDATA; // mark data in target position as new
retval = 1;
}
return(retval);
}
 
//------------------------------------------------------------
// clear position data
uint8_t GPS_ClearPosition(GPS_Pos_t * pGPSPos)
{
uint8_t retval = 0;
if(pGPSPos == 0) return(retval); // bad pointer
else
{
pGPSPos->Longitude = 0;
pGPSPos->Latitude = 0;
pGPSPos->Altitude = 0;
pGPSPos->Status = INVALID;
retval = 1;
}
return (retval);
}
 
 
//------------------------------------------------------------
// check for new GPS data
void GPS_Update(void)
{
static uint16_t GPS_Timeout = 0;
static uint16_t beep_rythm = 0;
 
switch(GPSData.Status)
{
case INVALID:
Error |= ERROR_GPS_RX_TIMEOUT;
GPS_ClearPosition(&(FollowMe.Position)); // clear followme position
break;
 
case PROCESSED:
// wait for timeout
if(CheckDelay(GPS_Timeout))
{
GPSData.Status = INVALID;
}
break;
 
case NEWDATA:
GPS_Timeout = SetDelay(GPS_TIMEOUT); // reset gps timeout
Error &= ~ERROR_GPS_RX_TIMEOUT; // clear possible error
beep_rythm++;
 
// update data in the follow me message
if((GPSData.SatFix & SATFIX_3D) && (GPSData.NumOfSats >= GPS_MINSATS))
{
GPS_CopyPosition(&(GPSData.Position),&(FollowMe.Position));
}
else
{
GPS_ClearPosition(&(FollowMe.Position)); // clear followme position
}
 
// NC like sound on bad gps signals
if(SysState == STATE_SEND_FOLLOWME)
{
if(!(GPSData.Flags & FLAG_GPSFIXOK) && !(beep_rythm % 5)) BeepTime = 100;
else if ((GPSData.NumOfSats < GPS_MINSATS) && !(beep_rythm % 5)) BeepTime = 10;
}
 
GPSData.Status = PROCESSED; // set to processed unlocks the buffer for new data
break;
 
default:
GPSData.Status = INVALID;
break;
}
}
 
/FollowMe/trunk/gps.h
0,0 → 1,7
#ifndef _GPS_H
#define _GPS_H
 
#include "ubx.h"
extern void GPS_Update(void);
 
#endif //_GPS_H
/FollowMe/trunk/gpx.c
0,0 → 1,380
/*#######################################################################################*/
/* !!! THIS IS NOT FREE SOFTWARE !!! */
/*#######################################################################################*/
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Copyright (c) 2008 Ingo Busker, Holger Buss
// + Nur für den privaten Gebrauch
// + FOR NON COMMERCIAL USE ONLY
// + 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 (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 sonstigen Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
// + eindeutig als Ursprung verlinkt 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 permitted
// + 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 this software (or part of it) 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "gpx.h"
#include "gpx_header.h"
#include "timer0.h"
//#include "spi_slave.h"
#include "main.h"
#include "uart1.h"
#include "ubx.h"
 
//________________________________________________________________________________________________________________________________________
// Function: GPX_DocumentInit(GPX_Document_t *)
//
// Description: This function initializes the gpx-document for further use.
//
//
// Returnvalue: '1' if document was initialized
//________________________________________________________________________________________________________________________________________
 
uint8_t GPX_DocumentInit(GPX_Document_t *doc)
{
if(doc->state != GPX_DOC_CLOSED) GPX_DocumentClose(doc); // close file if it was opened before
doc->state = GPX_DOC_CLOSED; // init state of the gpx-document
doc->file = NULL;
return(1);
}
 
//________________________________________________________________________________________________________________________________________
// Function: GPX_Document_Open(s8 *name, GPX_Document_t *doc);
//
// Description: This function opens a new gpx-document with the specified name and creates the document header within the file.
//
//
// Returnvalue: '1' if the gpx-file could be created.
//________________________________________________________________________________________________________________________________________
 
uint8_t GPX_DocumentOpen(int8_t *name, GPX_Document_t *doc)
{
 
uint8_t retvalue = 0;
 
if(doc == NULL) return(0);
GPX_DocumentInit(doc); // intialize the document with resetvalues
doc->file = fopen_(name,'a'); // open a new file with the specified filename on the memorycard.
 
if(doc->file != NULL) // could the file be opened?
{
retvalue = 1; // the document could be created on the drive.
doc->state = GPX_DOC_OPENED; // change document state to opened. At next a placemark has to be opened.
fwrite_((void*)GPX_DOCUMENT_HEADER, sizeof(GPX_DOCUMENT_HEADER)-1,1,doc->file);// write the gpx-header to the document.
}
 
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: DocumentClose(GPX_Document_t *doc);
//
// Description: This function closes the document specified by doc.
//
//
// Returnvalue: '1' if the gpx-file could be closed.
//________________________________________________________________________________________________________________________________________
 
uint8_t GPX_DocumentClose(GPX_Document_t *doc)
{
 
uint8_t retvalue = 1;
 
if(doc == NULL) return(0);
 
while(doc->state != GPX_DOC_CLOSED) // close linestring, placemark and document before closing the file on the memorycard
{
switch(doc->state)
{
case GPX_DOC_TRACKSEGMENT_OPENED:
GPX_TrackSegmentEnd(doc); // write terminating tag to end tracksegment.
break;
 
case GPX_DOC_TRACK_OPENED: // write terminating tag to close track.
GPX_TrackEnd(doc);
break;
 
case GPX_DOC_OPENED: // close the file on the memorycard
if(doc->file != NULL)
{
fwrite_((void*)GPX_DOCUMENT_FOOTER, sizeof(GPX_DOCUMENT_FOOTER)-1,1,doc->file); // write the gpx-footer to the document.
fclose_(doc->file);
retvalue = 1;
}
doc->state = GPX_DOC_CLOSED;
break;
 
default:
doc->state = GPX_DOC_CLOSED;
break;
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: u8 GPX_TrackBegin(GPX_Document_t);
//
// Description: This function adds a track to the document.
//
//
// Returnvalue: '1' if the track could be opened
//________________________________________________________________________________________________________________________________________
 
uint8_t GPX_TrackBegin(GPX_Document_t *doc)
{
 
uint8_t retvalue = 0;
if(doc->state == GPX_DOC_OPENED)
{
if(doc->file != NULL)
{
doc->state = GPX_DOC_TRACK_OPENED;
retvalue = 1;
fwrite_((void*)GPX_TRACK_HEADER, sizeof(GPX_TRACK_HEADER)-1,1,doc->file);
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: u8 GPX_TrackEnd(KML_Document_t *doc)
//
// Description: This function ends the track opened before.
//
//
// Returnvalue: 1' if the track could be closed
//________________________________________________________________________________________________________________________________________
 
uint8_t GPX_TrackEnd(GPX_Document_t *doc)
{
 
uint8_t retvalue = 0;
 
if(doc->state == GPX_DOC_TRACK_OPENED)
{
if(doc->file != NULL)
{
doc->state = GPX_DOC_OPENED;
fwrite_((void*)GPX_TRACK_FOOTER, sizeof(GPX_TRACK_FOOTER)-1,1,doc->file);
retvalue = 1;
}
}
 
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: u8 GPX_TrackSegmentBegin(GPX_Document_t *doc);
//
// Description: This function starts a track segment.
//
//
// Returnvalue: '1' if the track segement could be started
//________________________________________________________________________________________________________________________________________
 
uint8_t GPX_TrackSegmentBegin(GPX_Document_t *doc)
{
 
uint8_t retvalue = 0;
 
if(doc->state == GPX_DOC_TRACK_OPENED)
{
if(doc->file != NULL)
{
doc->state = GPX_DOC_TRACKSEGMENT_OPENED;
fwrite_((void*)GPX_TRACKSEGMENT_HEADER, sizeof(GPX_TRACKSEGMENT_HEADER)-1,1,doc->file);
retvalue = 1;
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: u8 GPX_TrackSegmentEnd(GPX_Document_t *doc);
//
// Description: This function ends the tracksegment opened before.
//
//
// Returnvalue: '1' if the track segment could be terminated
//________________________________________________________________________________________________________________________________________
 
uint8_t GPX_TrackSegmentEnd(GPX_Document_t *doc)
{
 
uint8_t retvalue = 0;
if(doc->state == GPX_DOC_TRACKSEGMENT_OPENED)
{
if(doc->file != NULL)
{
doc->state = GPX_DOC_TRACK_OPENED;
fwrite_((void*)GPX_TRACKSEGMENT_FOOTER, sizeof(GPX_TRACKSEGMENT_FOOTER)-1,1,doc->file);
retvalue = 1;
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: u8 GPX_TrackSegementAddPoint(GPS_Pos_t * pGPS_Position ,GPX_Document_t *doc);
//
// Description: This function adds a pointof a track segement to the specified document.
//
//
// Returnvalue: '1' if a point was added
//________________________________________________________________________________________________________________________________________
 
uint8_t GPX_TrackSegementAddPoint(GPX_Document_t *doc)
{
 
uint8_t retvalue = 0;
int8_t string[100];
 
if(doc == NULL) return(0);
 
if(GPSData.Position.Status != INVALID)
{
if(doc->state == GPX_DOC_TRACKSEGMENT_OPENED)
{
if(doc->file != NULL)
{
int16_t i16_1, i16_2, i16_3;
uint8_t u8_1, u8_2;
// write <trkpt> tag
if(GPSData.Position.Latitude < 0) u8_1 = '-';
else u8_1 = '+';
i16_1 = abs((int16_t)(GPSData.Position.Latitude/10000000L));
i16_2 = abs((int16_t)((GPSData.Position.Latitude%10000000L)/10000L));
i16_3 = abs((int16_t)(((GPSData.Position.Latitude%10000000L)%10000L)/10L));
sprintf(string, "<trkpt lat=\"%c%d.%.3d%.3d\" ",u8_1, i16_1, i16_2, i16_3);
fputs_(string, doc->file);
 
if(GPSData.Position.Longitude < 0) u8_1 = '-';
else u8_1 = '+';
i16_1 = abs((int16_t)(GPSData.Position.Longitude/10000000L));
i16_2 = abs((int16_t)((GPSData.Position.Longitude%10000000L)/10000L));
i16_3 = abs((int16_t)(((GPSData.Position.Longitude%10000000L)%10000L)/10L));
sprintf(string, "<lon=\"%c%d.%.3d%.3d\" ",u8_1, i16_1, i16_2, i16_3);
fputs_(string, doc->file);
 
// write <time> tag only at a resolution of one second
sprintf(string, "<time>%04d-%02d-%02dT%02d:%02d:%02dZ</time>\r\n",SystemTime.Year, SystemTime.Month, SystemTime.Day, SystemTime.Hour, SystemTime.Min, SystemTime.Sec);
fputs_(string, doc->file);
// write <sat> tag
sprintf(string, "<sat>%d</sat>\r\n", GPSData.NumOfSats);
fputs_(string, doc->file);
// todo: add <extensions> tag with additional data to be logged
sprintf(string, "<extensions>\r\n");
fputs_(string, doc->file);
// Course in deg
i16_1 = (int16_t)(GPSData.Heading/100000L);
sprintf(string, "<Course>%03d</Course>\r\n", i16_1);
fputs_(string, doc->file);
// Ground Speed in cm/s
sprintf(string, "<GroundSpeed>%d</GroundSpeed>\r\n", (uint16_t)GPSData.Speed_Ground);
fputs_(string, doc->file);
// Ubat
u8_1 = UBat / 10;
u8_2 = UBat % 10;
sprintf(string, "<Voltage>%d.%01d</Voltage>\r\n", u8_1, u8_2);
fputs_(string, doc->file);
 
// eof extensions
sprintf(string, "</extensions>\r\n");
fputs_(string, doc->file);
sprintf(string, "</trkpt>\r\n");
fputs_(string, doc->file);
retvalue = 1;
}
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: u8 KML_LoggGPSCoordinates(gps_data_t *, KML_Document_t *)
//
// Description: This function opens and adds gpscoordinates to an GPX-Document. The document will be opened, if not already done
//
//
// Returnvalue: '1' if an gps coordinate was logged
//________________________________________________________________________________________________________________________________________
 
uint8_t GPX_LoggGPSCoordinates(GPX_Document_t *doc)
{
uint8_t retval = 0;
while(doc->state != GPX_DOC_TRACKSEGMENT_OPENED) // automatic create document with default filename on the card.
{
switch(doc->state)
{
case GPX_DOC_CLOSED: // document hasn't been opened yet therefore it will be initialized automatically
retval = GPX_DocumentOpen("default.gpx",doc); // open the gpx-document with a standardname.
break;
 
case GPX_DOC_OPENED: // if a document has been opened before but no track exists:
retval = GPX_TrackBegin(doc);
break;
 
case GPX_DOC_TRACK_OPENED: // add tracksegement to the track
retval = GPX_TrackSegmentBegin(doc);
break;
 
default:
retval = 0;
break;
 
}
if(retval != 1) return(retval); // stop on error
}
 
if(doc->state == GPX_DOC_TRACKSEGMENT_OPENED) // if the document was opened add coordinates to the document.
{
retval = GPX_TrackSegementAddPoint(doc); // add a track segment point
}
return(retval);
}
 
/FollowMe/trunk/gpx.h
0,0 → 1,36
#ifndef _GPX_H
#define _GPX_H
 
#include "fat16.h"
#include "gps.h"
 
 
// possible state of a gpx-document
typedef enum
{
GPX_DOC_CLOSED,
GPX_DOC_OPENED,
GPX_DOC_TRACK_OPENED,
GPX_DOC_TRACKSEGMENT_OPENED,
GPX_DOC_END
}GPX_DocState_t;
 
 
// structure of an gpx-document
typedef struct gpx_doc
{
GPX_DocState_t state; // state of the gpx-document
File_t *file; // filepointer to the file where the data should be saved.
} GPX_Document_t;
 
uint8_t GPX_LoggGPSCoordinates(GPX_Document_t *); // intializes the gpx-document with standard filename and adds points to the file
uint8_t GPX_DocumentInit(GPX_Document_t *); // Init the new gpx-document
uint8_t GPX_DocumentOpen(int8_t *, GPX_Document_t *); // opens a new gpx-document. a new file is created on the sd-memorycard
uint8_t GPX_DocumentClose(GPX_Document_t *doc); // closes the specified document saving remaining data to the file.
uint8_t GPX_TrackBegin(GPX_Document_t *doc); // opens a new track within the open gpx-document
uint8_t GPX_TrackEnd(GPX_Document_t *doc); // ends the actual track
uint8_t GPX_TrackSegmentBegin(GPX_Document_t *doc); // begins a new tracksegment within the actual track
uint8_t GPX_TrackSegmentEnd(GPX_Document_t *doc); // ends the actual track segment within the actual track
uint8_t GPX_TrackSegmentAddPoint(GPX_Document_t *); // adds a point to the tracksegment
 
#endif //_GPX_H
/FollowMe/trunk/gpx_header.h
0,0 → 1,72
//________________________________________________________________________________________________________________________________________
//
// Definition of gpx-header and footer elements for documents
//
//________________________________________________________________________________________________________________________________________
 
 
const int8_t GPX_DOCUMENT_HEADER[] =
{
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\r\n"
"<gpx creator=\"NC\" version=\"1.0\" >\r\n"
"\r\n"
"<metadata>\r\n"
"<link href=\"http://www.mikrokopter.de\">\r\n"
"<text>MikroKopter</text>\r\n"
"</link>\r\n"
"</metadata>\r\n"
"\r\n"
};
 
//________________________________________________________________________________________________________________________________________
//
// footer of an gpx-file.
//
//________________________________________________________________________________________________________________________________________
const int8_t GPX_DOCUMENT_FOOTER[] =
{
"</gpx>\r\n"
};
 
//________________________________________________________________________________________________________________________________________
//
// Header of a track
//
//________________________________________________________________________________________________________________________________________
 
const int8_t GPX_TRACK_HEADER[] =
{
"<trk>\r\n"
"<name>Flight</name>\r\n"
};
 
//________________________________________________________________________________________________________________________________________
//
// Footer of a track
//
//________________________________________________________________________________________________________________________________________
const int8_t GPX_TRACK_FOOTER[] =
{
"</trk>\r\n"
};
 
//________________________________________________________________________________________________________________________________________
//
// Header of a track segment
//
//________________________________________________________________________________________________________________________________________
const int8_t GPX_TRACKSEGMENT_HEADER[] =
{
"<trkseg>\r\n"
};
 
//________________________________________________________________________________________________________________________________________
//
// Footer of a track segment
//
//________________________________________________________________________________________________________________________________________
const int8_t GPX_TRACKSEGMENT_FOOTER[] =
{
"</trkseg>\r\n"
};
 
/FollowMe/trunk/kml.c
0,0 → 1,380
/*#######################################################################################*/
/* !!! THIS IS NOT FREE SOFTWARE !!! */
/*#######################################################################################*/
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Copyright (c) 2008 Ingo Busker, Holger Buss
// + Nur für den privaten Gebrauch
// + FOR NON COMMERCIAL USE ONLY
// + 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 (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 sonstigen Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
// + eindeutig als Ursprung verlinkt 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 permitted
// + 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 this software (or part of it) 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 <stdlib.h>
#include <stdio.h>
#include "kml.h"
#include "kml_header.h"
 
 
//________________________________________________________________________________________________________________________________________
// Module name: kml.c
// Compiler used: avr-gcc 3.4.5
// Last Modifikation: 22.03.2009
// Version: 1.03
// Authors: Stephan Busker, Gregor Stobrawa
// Description: Source files to write gps-coordinates to a file in the kml (keyhole markup language) fileformat
// Copyright (C) 2007 Stephan Busker
//........................................................................................................................................
// Functions: extern u8 KML_LoggGPSCoordinates(struct str_gps_nav_data , KML_Document_t *); // intializes the kml-document with standard filename and adds points to the file
// extern u8 KML_DocumentInit(KML_Document_t *doc) // initializes the kml-document to resetvalues.
// extern u8 KML_DocumentOpen(s8 *, KML_Document_t *); // opens a new kml document. A filename can be specified.
// extern u8 KML_DocumentClose(KML_Document_t *doc); // closes an open document
// extern u8 KML_PlaceMarkOpen(KML_Document_t *); // opens a new placemark within the specified document
// extern u8 KML_PlaceMarkClose(KML_Document_t *); // Closes the placemark
// extern u8 KML_LineStringBegin(KML_Document_t *); // begins a new line within the actual placemark
// extern u8 KML_LineStringEnd(KML_Document_t *doc); // ends the actual linestring
// extern u8 KML_LineStringAddPoint(struct str_gps_nav_data, KML_Document_t *); // adds a new point (gps-coordinates) to the actual linestring
//........................................................................................................................................
// ext. functions:
//
//........................................................................................................................................
//
// URL: www.Mikro-Control.de
// mailto: stephan.busker@mikro-control.de
//________________________________________________________________________________________________________________________________________
 
 
 
//________________________________________________________________________________________________________________________________________
// Function: KML_DocumentInit(KML_Document_t *)
//
// Description: This function initializes the kml-document for further use.
//
//
// Returnvalue: '1' if document was initialized
//________________________________________________________________________________________________________________________________________
 
uint8_t KML_DocumentInit(KML_Document_t *doc)
{
doc->state = KML_DOC_CLOSED; // state of the kml-document
doc->file = NULL;
return(1);
}
 
//________________________________________________________________________________________________________________________________________
// Function: KML_Document_Open(void);
//
// Description: This function opens a new KML- document with the specified name and creates the document header within the file.
//
//
// Returnvalue: '1' if the KML- file could be created.
//________________________________________________________________________________________________________________________________________
 
uint8_t KML_DocumentOpen(int8_t *name, KML_Document_t *doc)
{
 
uint8_t retvalue = 0;
 
if(doc == NULL) return(0);
 
KML_DocumentInit(doc); // intialize the document with resetvalues
doc->file = fopen_(name,'a'); // open a new file with the specified filename on the memorycard.
 
if(doc->file != NULL) // could the file be opened?
{
retvalue = 1; // the document could be created on the drive.
doc->state = KML_DOC_OPENED; // change document state to opened. At next a placemark has to be opened.
fwrite_((void*)KML_DOCUMENT_HEADER, sizeof(KML_DOCUMENT_HEADER)-1,1,doc->file);// write the KML-header to the document.
}
 
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: DocumentClose(KML_Document_t *doc);
//
// Description: This function closes the document specified by doc.
//
//
// Returnvalue: '1' if the KML- file could be closed.
//________________________________________________________________________________________________________________________________________
 
uint8_t KML_DocumentClose(KML_Document_t *doc)
{
 
uint8_t retvalue = 1;
 
if(doc == NULL) return(0);
 
while(doc->state != KML_DOC_CLOSED) // close linestring, placemark and document before closing the file on the memorycard
{
switch(doc->state)
{
case KML_DOC_LINESTRING_OPENED:
KML_LineStringEnd(doc); // write terminating tag to end linestring.
break;
 
case KML_DOC_PLACEMARK_OPENED: // write terminating tag to close placemark.
KML_PlaceMarkClose(doc);
break;
 
case KML_DOC_OPENED: // close the file on the memorycard
if(doc->file != NULL)
{
fwrite_((void*)KML_DOCUMENT_FOOTER, sizeof(KML_DOCUMENT_FOOTER)-1,1,doc->file); // write the KML- footer to the document.
fclose_(doc->file);
retvalue = 1;
}
doc->state = KML_DOC_CLOSED;
break;
 
default:
doc->state = KML_DOC_CLOSED;
break;
 
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: u8 KML_PlaceMarkOpen(KML_Document_t *doc);
//
// Description: This function adds a placemark to the document.
//
//
// Returnvalue: '1' if the PlaceMark could be opened
//________________________________________________________________________________________________________________________________________
 
uint8_t KML_PlaceMarkOpen(KML_Document_t *doc)
{
uint8_t retvalue = 0;
if(doc->state == KML_DOC_OPENED)
{
if(doc->file != NULL)
{
doc->state = KML_DOC_PLACEMARK_OPENED;
retvalue = 1;
fwrite_((void*)KML_PLACEMARK_HEADER, sizeof(KML_PLACEMARK_HEADER)-1,1,doc->file);
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: u8 PlaceMarkClose(KML_PlaceMark_t *place, File *file);
//
// Description: This function ends the placemark opened before.
//
//
// Returnvalue: 1' if the PlaceMark could be closed
//________________________________________________________________________________________________________________________________________
 
uint8_t KML_PlaceMarkClose(KML_Document_t *doc)
{
 
uint8_t retvalue = 0; // close the Placemark-tag of the corosponding document.
 
if(doc->state == KML_DOC_PLACEMARK_OPENED)
{
if(doc->file != NULL)
{
doc->state = KML_DOC_OPENED;
fwrite_((void*)KML_PLACEMARK_FOOTER, sizeof(KML_PLACEMARK_FOOTER)-1,1,doc->file);
retvalue = 1;
}
}
 
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: u8 LineStringBegin(KML_Document_t *doc);
//
// Description: This function ends the placemark opened before.
//
//
// Returnvalue: '1' if the LineString could be started
//________________________________________________________________________________________________________________________________________
 
uint8_t KML_LineStringBegin(KML_Document_t *doc)
{
 
uint8_t retvalue = 0;
 
if(doc->state == KML_DOC_PLACEMARK_OPENED)
{
if(doc->file != NULL)
{
doc->state = KML_DOC_LINESTRING_OPENED;
fwrite_((void*)KML_LINESTRING_HEADER, sizeof(KML_LINESTRING_HEADER)-1,1,doc->file);
retvalue = 1;
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: u8 KML_LineStringEnd(KML_Document_t *doc)
//
// Description: This function ends the placemark opened before.
//
//
// Returnvalue: '1' if the LineString could be terminated
//________________________________________________________________________________________________________________________________________
 
uint8_t KML_LineStringEnd(KML_Document_t *doc)
{
 
uint8_t retvalue = 0;
 
if(doc->state == KML_DOC_LINESTRING_OPENED)
{
if(doc->file != NULL)
{
doc->state = KML_DOC_PLACEMARK_OPENED;
fwrite_((void*)KML_LINESTRING_FOOTER, sizeof(KML_LINESTRING_FOOTER)-1,1,doc->file);
retvalue = 1;
}
}
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: u8 LineStringAddPoint(gps_data_t, KML_Document_t *doc)
//
// Description: This function adds a point to the specified document.
//
//
// Returnvalue: '1' if a ppoint was added could be started
//________________________________________________________________________________________________________________________________________
 
uint8_t KML_LineStringAddPoint(KML_Document_t *doc)
{
 
uint8_t retvalue = 0;
int8_t string[50];
// int32_t rel_altitude = 0;
 
if(doc == NULL) return(0);
 
if(GPSData.Position.Status != INVALID)
{
if(doc->state == KML_DOC_LINESTRING_OPENED)
{
if(doc->file != NULL)
{
int16_t i1, i2, i3;
uint8_t sign;
if(GPSData.Position.Longitude < 0) sign = '-';
else sign = '+';
i1 = abs((int16_t)(GPSData.Position.Longitude/10000000L));
i2 = abs((int16_t)((GPSData.Position.Longitude%10000000L)/10000L));
i3 = abs((int16_t)(((GPSData.Position.Longitude%10000000L)%10000L)/10L));
sprintf(string,"\r\n%c%d.%.3d%.3d,",sign, i1, i2, i3);
fputs_(string, doc->file);
if(GPSData.Position.Latitude < 0) sign = '-';
else sign = '+';
i1 = abs((int16_t)(GPSData.Position.Latitude/10000000L));
i2 = abs((int16_t)((GPSData.Position.Latitude%10000000L)/10000L));
i3 = abs((int16_t)(((GPSData.Position.Latitude%10000000L)%10000L)/10L));
sprintf(string,"%c%d.%.3d%.3d,",sign, i1, i2, i3);
fputs_(string, doc->file);
sign = '+';
sprintf(string,"%c%d.%.3d",sign, 0, 0);
fputs_(string, doc->file);
retvalue = 1;
}
}
}
 
return(retvalue);
}
 
//________________________________________________________________________________________________________________________________________
// Function: u8 KML_LoggGPSCoordinates(gps_data_t *, KML_Document_t *)
//
// Description: This function opens adds gpscoordinates to an KML-Document. The document will be opened, if not already done
//
//
// Returnvalue: '1' if an gps coordinate was logged
//________________________________________________________________________________________________________________________________________
 
uint8_t KML_LoggGPSCoordinates(KML_Document_t *doc)
{
uint8_t retval = 0;
while(doc->state != KML_DOC_LINESTRING_OPENED) // automatic create document with default filename on the card.
{
switch(doc->state)
{
case KML_DOC_CLOSED: // document hasn't been opened yet therefore it will be initialized automatically
retval = KML_DocumentOpen("default.kml",doc); // open the kml-document with a standardname.
break;
 
case KML_DOC_OPENED: // if a document has been opened before but no placemark exists:
retval = KML_PlaceMarkOpen(doc);
break;
 
case KML_DOC_PLACEMARK_OPENED: // add linestring to the placemark
retval = KML_LineStringBegin(doc);
break;
 
default:
retval = 0;
break;
 
}
if(retval != 1) return(retval); // stop on error
}
 
if(doc->state == KML_DOC_LINESTRING_OPENED) // if the document was opened add coordinates to the document.
{
retval = KML_LineStringAddPoint(doc);
}
return(retval);
}
 
/FollowMe/trunk/kml.h
0,0 → 1,37
#ifndef _KML_H
#define _KML_H
 
#include "fat16.h"
#include "gps.h"
 
 
// possible state of an kml-document
typedef enum
{
KML_DOC_CLOSED,
KML_DOC_OPENED,
KML_DOC_PLACEMARK_OPENED,
KML_DOC_LINESTRING_OPENED,
KML_DOC_END
}KML_DocState_t;
 
 
// structure of an kml-document
typedef struct kml_doc
{
KML_DocState_t state; // state of the kml-document
File_t *file; // filepointer to the file where the data should be saved.
} KML_Document_t;
 
 
uint8_t KML_LoggGPSCoordinates(KML_Document_t *); // intializes the kml-document with standard filename and adds points to the file
uint8_t KML_DocumentInit(KML_Document_t *); // Init the new kml-document
uint8_t KML_DocumentOpen(int8_t *, KML_Document_t *); // opens a new kml-document. a new file is created on the sd-memorycard
uint8_t KML_DocumentClose(KML_Document_t *doc); // closes the specified document saving remaining data to the file.
uint8_t KML_PlaceMarkOpen(KML_Document_t *doc); // opens a new placemark within the open kml-document
uint8_t KML_PlaceMarkClose(KML_Document_t *doc); // closes the actual placemark
uint8_t KML_LineStringBegin(KML_Document_t *doc); // begins a new linestring within the actual placemark
uint8_t KML_LineStringEnd(KML_Document_t *doc); // close the actual linestring within the actual placemark
uint8_t KML_LineStringAddPoint(KML_Document_t *); // adds a point from the gps (longitude, altitude, height) to the linestring
 
#endif //_KML_H
/FollowMe/trunk/kml_header.h
0,0 → 1,78
//________________________________________________________________________________________________________________________________________
//
// Definition of KML header and footer elements for documents, placemarks and linestrings
//
//________________________________________________________________________________________________________________________________________
const int8_t KML_DOCUMENT_HEADER[] =
{
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
"<kml xmlns=\"http://earth.google.com/kml/2.2\">\r\n"
"<Document>\r\n"
"<name>Mikrokopter GPS logging</name>\r\n"
"\r\n"
"<Style id=\"MK_gps-style\">\r\n"
"<LineStyle>\r\n"
"<color>ff0000ff</color>\r\n"
"<width>2</width>\r\n"
"</LineStyle>\r\n"
"</Style>\r\n"
};
 
//________________________________________________________________________________________________________________________________________
//
// footer of an KML- file.
//
//________________________________________________________________________________________________________________________________________
const int8_t KML_DOCUMENT_FOOTER[] =
{
"</Document>\r\n"
"</kml>\r\n"
};
 
//________________________________________________________________________________________________________________________________________
//
// Header of an placemark
//
//________________________________________________________________________________________________________________________________________
const int8_t KML_PLACEMARK_HEADER[] =
{
"<Placemark>\r\n"
"<name>Flight</name>\r\n"
"<styleUrl>#MK_gps-style</styleUrl>\r\n"
};
 
//________________________________________________________________________________________________________________________________________
//
// Footer of an placemark
//
//________________________________________________________________________________________________________________________________________
const int8_t KML_PLACEMARK_FOOTER[] =
{
"</Placemark>\r\n"
};
 
 
//________________________________________________________________________________________________________________________________________
//
// Header of an linestring
//
//________________________________________________________________________________________________________________________________________
const int8_t KML_LINESTRING_HEADER[] =
{
"<LineString>\r\n"
"<tessellate>1</tessellate>\r\n"
"<altitudeMode>relativeToGround</altitudeMode>\r\n" // also possible "absolute"
"<coordinates>\r\n"
};
 
//________________________________________________________________________________________________________________________________________
//
// Footer of an linestring
//
//________________________________________________________________________________________________________________________________________
const int8_t KML_LINESTRING_FOOTER[] =
{
"\r\n</coordinates>"
"\r\n</LineString>\r\n"
};
 
/FollowMe/trunk/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 green LED)
DDRB |= (1<<DDB0);
LEDGRN_OFF;
// set PB1 as output (control of red LED)
DDRB |= (1<<DDB1);
LEDRED_OFF;
#endif
 
}
/FollowMe/trunk/led.h
0,0 → 1,29
#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)
 
#define LEDGRN_OFF
#define LEDGRN_ON
#define LEDGRN_TOGGLE
#endif
 
#ifdef USE_FOLLOWME
#define LEDGRN_OFF PORTB |= (1<<PORTB1)
#define LEDGRN_ON PORTB &= ~(1<<PORTB1)
#define LEDGRN_TOGGLE PORTB ^= (1<<PORTB1)
 
#define LEDRED_OFF PORTB |= (1<<PORTB0)
#define LEDRED_ON PORTB &= ~(1<<PORTB0)
#define LEDRED_TOGGLE PORTB ^= (1<<PORTB0)
#endif
 
void LED_Init(void);
 
#endif //_LED_H
 
/FollowMe/trunk/logging.c
0,0 → 1,436
/*#######################################################################################*/
/* !!! THIS IS NOT FREE SOFTWARE !!! */
/*#######################################################################################*/
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Copyright (c) 2008 Ingo Busker, Holger Buss
// + Nur für den privaten Gebrauch
// + FOR NON COMMERCIAL USE ONLY
// + 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 (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 sonstigen Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
// + eindeutig als Ursprung verlinkt 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 permitted
// + 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 this software (or part of it) 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 <stdio.h>
#include "main.h"
#include "timer0.h"
#include "uart1.h"
#include "kml.h"
//#include "gpx.h"
#include "ssc.h"
#include "settings.h"
#include "printf_P.h"
 
 
#define LOG_FLUSH_INTERVAL 20000 // 20s
 
typedef enum
{
LOGFILE_IDLE,
LOGFILE_START,
LOGFILE_CLOSED,
LOGFILE_OPENED,
LOGFILE_ERROR
} logfilestate_t;
 
// logger handler prototypes
logfilestate_t Logging_KML(uint16_t LogDelay);
//logfilestate_t Logging_GPX(uint16_t LogDelay);
 
typedef struct
{
uint16_t KML_Interval; // the kml-log interval (0 = off)
uint16_t GPX_Interval; // the gpx-log interval (0 = off)
} LogCfg_t;
 
LogCfg_t LogCfg = {500 , 1000};
 
 
//----------------------------------------------------------------------------------------------------
int8_t* GenerateKMLLogFileName(void)
{
static uint16_t filenum = 0; // file name counter
static int8_t filename[35];
static DateTime_t LastTime = {0,0,0,0,0,0,0,0};
 
if(SystemTime.Valid)
{
// if the day has been changed
if((LastTime.Year != SystemTime.Year) || (LastTime.Month != SystemTime.Month) || (LastTime.Day != SystemTime.Day))
{
LastTime.Year = SystemTime.Year;
LastTime.Month = SystemTime.Month;
LastTime.Day = SystemTime.Day;
LastTime.Valid = 1;
filenum = 0; // reset file counter
}
sprintf(filename, "LOG/%04i%02i%02i/KML/GPS%05i.KML", SystemTime.Year, SystemTime.Month, SystemTime.Day, filenum);
filenum++;
return filename;
}
else return NULL;
}
 
//----------------------------------------------------------------------------------------------------
/*int8_t* GenerateGPXLogFileName(void)
{
static uint16_t filenum = 0; // file name counter
static int8_t filename[35];
static DateTime_t LastTime = {0,0,0,0,0,0,0,0};
 
if(SystemTime.Valid)
{
// if the day has been changed
if((LastTime.Year != SystemTime.Year) || (LastTime.Month != SystemTime.Month) || (LastTime.Day != SystemTime.Day))
{
LastTime.Year = SystemTime.Year;
LastTime.Month = SystemTime.Month;
LastTime.Day = SystemTime.Day;
LastTime.Valid = 1;
filenum = 0; // reset file counter
}
sprintf(filename, "LOG/%04i%02i%02i/GPX/GPS%05i.GPX", SystemTime.Year, SystemTime.Month, SystemTime.Day, filenum);
filenum++;
return filename;
}
else return NULL;
}*/
 
 
//----------------------------------------------------------------------------------------------------
// logs the current gps position to a kml file
logfilestate_t Logging_KML(uint16_t LogDelay)
{
static logfilestate_t logfilestate = LOGFILE_IDLE; // the current logfilestate
static int8_t* logfilename = NULL; // the pointer to the logfilename
static uint16_t logtimer = 0, flushtimer = 0; // the log update timer
static KML_Document_t logfile; // the logfilehandle
 
// initialize if LogDelay os zero
if(!LogDelay)
{
switch(logfilestate)
{
case LOGFILE_OPENED:
KML_DocumentClose(&logfile); // try to close it
break;
default:
break;
}
logfilestate = LOGFILE_IDLE;
logfilename = NULL;
KML_DocumentInit(&logfile);
logtimer = SetDelay(0); // set logtimer to now
return logfilestate;
}
// no init
if(CheckDelay(logtimer))
{
logtimer = SetDelay(LogDelay); // standard interval
 
if(SysState == STATE_SEND_FOLLOWME)
{
switch(logfilestate)
{
case LOGFILE_IDLE:
case LOGFILE_CLOSED:
if((GPSData.Status != INVALID) && (GPSData.Flags & FLAG_GPSFIXOK) && (GPSData.SatFix == SATFIX_3D))
{
logfilestate = LOGFILE_START;
}
break;
case LOGFILE_START:
// find unused logfile name
do
{ // try to generate a new logfile name
logfilename = GenerateKMLLogFileName();
}while((logfilename != NULL) && fexist_(logfilename));
// if logfilename exist
if(logfilename != NULL)
{
// try to create the log file
if(KML_DocumentOpen(logfilename, &logfile))
{
flushtimer = SetDelay(LOG_FLUSH_INTERVAL);
logfilestate = LOGFILE_OPENED; // goto next step
printf("\r\nOpening kml-file: %s\r\n",logfilename);
}
else // could not be openend
{
logfilestate = LOGFILE_ERROR;
printf("\r\nError opening kml-file: %s\r\n", logfilename);
logtimer = SetDelay(10); // try again in open logfile in 10 mili sec
}
}
else
{
logfilestate = LOGFILE_ERROR;
printf("\r\nError getting free kml-file name\r\n");
}
// else retry in next loop
break;
case LOGFILE_OPENED:
// append new gps log data
if((GPSData.Status != INVALID) && (GPSData.Flags & FLAG_GPSFIXOK) && (GPSData.SatFix == SATFIX_3D))
{
if(!KML_LoggGPSCoordinates(&logfile))
{ // error logging data
printf("\r\nError logging to kml-file\r\n");
KML_DocumentClose(&logfile);
logfilestate = LOGFILE_ERROR;
}
else // sucessfully logged
{
if(CheckDelay(flushtimer))
{
flushtimer = SetDelay(LOG_FLUSH_INTERVAL);
fflush_(logfile.file);
}
}
 
}
break;
 
case LOGFILE_ERROR:
break;
 
default:
logfilestate = LOGFILE_IDLE;
break;
}
} // EOF follow me on
else // follow me off
{ // close log file if opened
if(logfilestate == LOGFILE_OPENED)
{
if(KML_DocumentClose(&logfile))
{
printf("\r\nClosing kml-file\r\n");
logfilestate = LOGFILE_CLOSED;
}
else // could not be closed
{
printf("\r\nError closing kml-file\r\n");
logfilestate = LOGFILE_ERROR;
}
}
} //EOF follow me off
 
} // EOF Check LogTimer
 
return logfilestate;
}
 
//----------------------------------------------------------------------------------------------------
/*
// logs gps and state info to a gpx file
logfilestate_t Logging_GPX(uint16_t LogDelay)
{
static logfilestate_t logfilestate = LOGFILE_IDLE; // the current logfilestate
static int8_t* logfilename = NULL; // the pointer to the logfilename
static uint16_t logtimer = 0, flushtimer = 0; // the log update timer
static GPX_Document_t logfile; // the logfilehandle
 
// initialize if LogDelay os zero
if(!LogDelay)
{
switch(logfilestate)
{
case LOGFILE_OPENED:
GPX_DocumentClose(&logfile); // try to close it
break;
default:
break;
}
logfilestate = LOGFILE_IDLE;
logfilename = NULL;
GPX_DocumentInit(&logfile);
logtimer = SetDelay(0); // set logtimer to now
return logfilestate;
}
// no init
if(CheckDelay(logtimer))
{
logtimer = SetDelay(LogDelay); // standard interval
 
if(SysState == STATE_SEND_FOLLOWME)
{
switch(logfilestate)
{
case LOGFILE_IDLE:
case LOGFILE_CLOSED:
//if((GPSData.Status != INVALID) && (GPSData.Flags & FLAG_GPSFIXOK) && (GPSData.SatFix == SATFIX_3D) )
{
logfilestate = LOGFILE_START;
}
break;
case LOGFILE_START:
// find unused logfile name
do
{ // try to generate a new logfile name
logfilename = GenerateGPXLogFileName();
}while((logfilename != NULL) && fexist_(logfilename));
// if logfilename exist
if(logfilename != NULL)
{
// try to create the log file
if(GPX_DocumentOpen(logfilename, &logfile))
{
flushtimer = SetDelay(LOG_FLUSH_INTERVAL);
logfilestate = LOGFILE_OPENED; // goto next step
printf("\r\nOpening gpx-file: %s\r\n", logfilename);
}
else // could not be openend
{
logfilestate = LOGFILE_ERROR;
printf("\r\nError opening gpx-file: %s\r\n", logfilename);
logtimer = SetDelay(10); // try again in open logfile in 10 mili sec
}
}
else
{
logfilestate = LOGFILE_ERROR;
printf("\r\nError getting free gpx-file name\r\n");
}
// else retry in next loop
break;
case LOGFILE_OPENED:
// append new gps log data
if((GPSData.Status != INVALID) && (GPSData.Flags & FLAG_GPSFIXOK) && (GPSData.SatFix == SATFIX_3D))
{
if(!GPX_LoggGPSCoordinates(&logfile))
{ // error logging data
printf("\r\nError logging to gpx-file\r\n");
GPX_DocumentClose(&logfile);
logfilestate = LOGFILE_ERROR;
}
else // successful log
{
if(CheckDelay(flushtimer))
{
flushtimer = SetDelay(LOG_FLUSH_INTERVAL);
fflush_(logfile.file);
}
}
}
break;
 
case LOGFILE_ERROR:
break;
 
default:
logfilestate = LOGFILE_IDLE;
break;
}
} // EOF follow me on
else // follow me off
{ // close log file if opened
if(logfilestate == LOGFILE_OPENED)
{
if(GPX_DocumentClose(&logfile))
{
printf("\r\nClosing gpx-file\r\n");
logfilestate = LOGFILE_CLOSED;
}
else // could not be closed
{
printf("\r\nError closing gpx-file\r\n");
logfilestate = LOGFILE_ERROR;
}
}
} //EOF follow me off
} // EOF Check LogTimer
 
return logfilestate;
}
*/
 
//----------------------------------------------------------------------------------------------------
// initialize logging
void Logging_Init(void)
{
LogCfg.KML_Interval = 500; //default
Settings_GetParamValue(PID_KML_LOGGING, (uint16_t*)&LogCfg.KML_Interval); // overwrite by settings value
Logging_KML(0); // initialize
//LogCfg.GPX_Interval = 1000; //default
//Settings_GetParamValue(PID_GPX_LOGGING, (uint16_t*)&LogCfg.GPX_Interval); // overwrite by settings value
//Logging_GPX(0); // initialize
}
 
//----------------------------------------------------------------------------------------------------
// gobal logging handler
void Logging_Update(void)
{
static uint16_t logtimer = 0;
static logfilestate_t logstate = LOGFILE_IDLE;
 
 
if(SD_SWITCH) // a card is in slot
{
if(CheckDelay(logtimer))
{
logtimer = SetDelay(10); // faster makes no sense
// call the logger handlers if no error has occured
if(logstate != LOGFILE_ERROR) logstate = Logging_KML(LogCfg.KML_Interval);
//if(logstate != LOGFILE_ERROR) logstate = Logging_GPX(LogCfg.GPX_Interval);
 
// a logging error has occured
if(logstate == LOGFILE_ERROR)
{
if(Fat16_IsValid()) // wait for reinizialization of fat16 from outside
{
Logging_Init(); // initialize the logs
logstate = LOGFILE_IDLE;
logtimer = SetDelay(10); // try next log in 10 mili sec
}
else
{ // retry in 5 seconds
logtimer = SetDelay(5000); // try again in 5 sec
}
} //EOF logfile error
} // EOF CheckDelay
}// EOF Card in Slot
}
/FollowMe/trunk/logging.h
0,0 → 1,7
#ifndef _LOGGING_H
#define _LOGGING_H
 
void Logging_Init(void);
void Logging_Update(void); // logs the current gps position to a kml file
 
#endif //_LOGGING_H
/FollowMe/trunk/main.c
0,0 → 1,227
#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"
#include "analog.h"
#include "gps.h"
#include "button.h"
#include "logging.h"
#include "settings.h"
 
#define FOLLOWME_INTERVAL 1000 // 1 second update
#define CELLUNDERVOLTAGE 32 // lowest allowed voltage/cell; 32 = 3.2V
 
#ifdef USE_FOLLOWME
int16_t UBat = 120;
int16_t Zellenzahl = 0;
int16_t PowerOn = 0;
int16_t i = 0;
int16_t delay = 0;
#endif
 
uint16_t Error = 0;
SysState_t SysState = STATE_UNDEFINED;
 
int main (void)
{
static uint16_t FollowMe_Timer = 0;
 
// disable interrupts global
cli();
 
// disable watchdog
MCUSR &=~(1<<WDRF);
WDTCSR |= (1<<WDCE)|(1<<WDE);
WDTCSR = 0;
 
// initalize modules
LED_Init();
LEDRED_ON;
TIMER0_Init();
USART0_Init();
UBX_Init();
USART1_Init();
ADC_Init();
Button_Init();
// enable interrupts global
sei();
 
LEDRED_OFF;
LEDGRN_ON;
 
// try to initialize the FAT 16 filesystem on the SD-Card
Fat16_Init();
 
// initialize the settings
Settings_Init();
// initialize logging (needs settings)
Logging_Init();
 
#ifdef USE_SDLOGGER
printf("\r\n\r\nHW: SD-Logger");
#endif
#ifdef USE_FOLLOWME
printf("\r\n\r\nHW: Follow-Me");
#endif
printf("\r\nFollow Me\n\rSoftware:V%d.%d%c ",VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH + 'a');
printf("\r\n------------------------------");
printf("\r\n");
 
 
//BeepTime = 2000;
 
LCD_Clear();
 
FollowMe_Timer = SetDelay(FOLLOWME_INTERVAL);
 
while (1)
{
// get gps data to update the follow me position
GPS_Update();
 
// update logging
Logging_Update();
 
// check for button action and change state resectively
if(GetButton())
{
BeepTime = 200;
 
switch(SysState)
{
case STATE_IDLE:
if(!Error) SysState = STATE_SEND_FOLLOWME; // activate followme only of no error has occured
break;
 
case STATE_SEND_FOLLOWME:
SysState = STATE_IDLE;
break;
 
default:
SysState = STATE_IDLE;
break;
}
 
}
 
// state machine
switch(SysState)
{
case STATE_SEND_FOLLOWME:
if(CheckDelay(FollowMe_Timer)) // time for next message?
{
if(FollowMe.Position.Status == NEWDATA) // if new
{ // update remaining data
FollowMe_Timer = SetDelay(FOLLOWME_INTERVAL); // reset timer
FollowMe.Heading = -1; // invalid heading
FollowMe.ToleranceRadius = 1; // 1 meter
FollowMe.HoldTime = 60; // go home after 60s without any update
FollowMe.Event_Flag = 0; // no event
FollowMe.reserve[0] = 0; // reserve
FollowMe.reserve[1] = 0; // reserve
FollowMe.reserve[2] = 0; // reserve
FollowMe.reserve[3] = 0; // reserve
Request_SendFollowMe = 1; // triggers serial tranmission
 
}
else // now new position avalable (maybe bad gps signal condition)
{
FollowMe_Timer = SetDelay(FOLLOWME_INTERVAL/4); // reset timer on higer frequency
}
LEDGRN_TOGGLE; // indication of active follow me
}
break;
 
case STATE_IDLE:
// do nothing
LEDGRN_ON;
break;
 
default:
// triger to idle state
SysState = STATE_IDLE;
break;
 
}
 
 
// restart ADConversion if ready
if(ADReady)
{
DebugOut.Analog[0] = Adc0;
DebugOut.Analog[1] = Adc1;
DebugOut.Analog[2] = Adc2;
DebugOut.Analog[3] = Adc3;
DebugOut.Analog[4] = Adc4;
DebugOut.Analog[5] = Adc5;
DebugOut.Analog[6] = Adc6;
DebugOut.Analog[7] = Adc7;
 
#ifdef USE_FOLLOWME
// AVcc = 5V --> 5V = 1024 counts
// the voltage at the voltage divider reference point is 0.8V less that the UBat
// because of the silicon diode inbetween.
// voltage divider R2=10K, R3=3K9
// UAdc4 = R3/(R3+R2)*UBat= 3.9/(3.9+10)*UBat = UBat/3.564
UBat = (3 * UBat + (64 * Adc4) / 368) / 4;
DebugOut.Analog[8] = UBat;
 
// check for zellenzahl
if(PowerOn < 100)
{
if(UBat<=84) Zellenzahl = 2;
else Zellenzahl = 3;
PowerOn++;
}
DebugOut.Analog[16] = Zellenzahl;
DebugOut.Analog[17] = PowerOn;
 
//show recognised Zellenzahl to user
if(i < Zellenzahl && PowerOn >= 100 && BeepTime == 0 && delay > 1000)
{
BeepTime = 100;
i++;
delay = 0;
}
if(delay < 1500) delay++;
 
// monitor battery undervoltage [...||(UBat<74) as temporary workaround to protect 2s lipo packs]
if(((UBat < Zellenzahl * CELLUNDERVOLTAGE)||(UBat < 74)) && (PowerOn >= 100))
{ // sound for low battery
BeepModulation = 0x0300;
if(!BeepTime)
{
//BeepTime = 6000; // 0.6 seconds
}
Error |= ERROR_LOW_BAT;
}
else
{
Error &= ~ERROR_LOW_BAT;
}
#endif
ADReady = 0;
ADC_Enable(); // restart ad conversion sequence
}
 
// serial communication
USART0_ProcessRxData();
USART0_TransmitTxData();
 
// indicate error, blinking code tbd.
if(Error) LEDRED_ON;
else LEDRED_OFF;
 
}
return (1);
}
 
/FollowMe/trunk/main.h
0,0 → 1,29
#ifndef _MAIN_H
#define _MAIN_H
 
#include <avr/io.h>
#define SYSCLK F_CPU
 
 
typedef enum
{
STATE_UNDEFINED,
STATE_IDLE,
STATE_SEND_FOLLOWME
} SysState_t;
 
#define ERROR_GPS_RX_TIMEOUT 0x0001
#define ERROR_LOW_BAT 0x0002
 
extern uint16_t Error;
extern int16_t UBat;
extern SysState_t SysState;
 
#endif //_MAIN_H
 
 
 
 
 
 
 
/FollowMe/trunk/makefile
0,0 → 1,429
#--------------------------------------------------------------------
# MCU name
MCU = atmega644p
F_CPU = 20000000
#-------------------------------------------------------------------
VERSION_MAJOR = 0
VERSION_MINOR = 1
VERSION_PATCH = 2
 
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 = 2
 
##########################################################################################################
# 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 analog.c button.c crc16.c ssc.c sdc.c fat16.c gps.c settings.c logging.c kml.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/trunk/menu.c
0,0 → 1,184
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + 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 "uart0.h"
#include "printf_P.h"
#include "ubx.h"
#include "timer0.h"
 
uint8_t MaxMenuItem = 3;
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)
{
int16_t i1,i2,i3;
uint8_t sign;
 
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:
if (GPSData.Status == INVALID)
{
LCD_printfxy(0,0,"No GPS data");
LCD_printfxy(0,1,"Lon: ");
LCD_printfxy(0,2,"Lat: ");
LCD_printfxy(0,3,"Alt: ");
}
else // newdata or processed
{
switch (GPSData.SatFix)
{
case SATFIX_NONE:
LCD_printfxy(0,0,"Sats:%02d Fix:None", GPSData.NumOfSats);
break;
case SATFIX_2D:
LCD_printfxy(0,0,"Sats:%02d Fix:2D ", GPSData.NumOfSats);
break;
case SATFIX_3D:
LCD_printfxy(0,0,"Sats:%02d Fix:3D ", GPSData.NumOfSats);
break;
default:
LCD_printfxy(0,0,"Sats:%02d Fix:?? ", GPSData.NumOfSats);
break;
}
if(GPSData.Position.Longitude < 0) sign = '-';
else sign = '+';
i1 = abs((int16_t)(GPSData.Position.Longitude/10000000L));
i2 = abs((int16_t)((GPSData.Position.Longitude%10000000L)/10000L));
i3 = abs((int16_t)(((GPSData.Position.Longitude%10000000L)%10000L)/10L));
LCD_printfxy(0,1,"Lon: %c%d.%.3d%.3d deg",sign, i1, i2, i3);
if(GPSData.Position.Latitude < 0) sign = '-';
else sign = '+';
i1 = abs((int16_t)(GPSData.Position.Latitude/10000000L));
i2 = abs((int16_t)((GPSData.Position.Latitude%10000000L)/10000L));
i3 = abs((int16_t)(((GPSData.Position.Latitude%10000000L)%10000L)/10L));
LCD_printfxy(0,2,"Lat: %c%d.%.3d%.3d deg",sign, i1, i2, i3);
if(GPSData.Position.Altitude < 0) sign = '-';
else sign = '+';
i1 = abs((int16_t)(GPSData.Position.Altitude/1000L));
i2 = abs((int16_t)(GPSData.Position.Altitude%1000L));
LCD_printfxy(0,3,"Alt: %c%04d.%.03d m",sign, i1, i2);
}
break;
case 2:
if (GPSData.Status == INVALID)
{
LCD_printfxy(0,0,"No GPS data");
LCD_printfxy(0,1,"Speed N: ");
LCD_printfxy(0,2,"Speed E: ");
LCD_printfxy(0,3,"Speed T: ");
}
else // newdata or processed
{
switch (GPSData.SatFix)
{
case SATFIX_NONE:
LCD_printfxy(0,0,"Sats:%02d Fix:None", GPSData.NumOfSats);
break;
case SATFIX_2D:
LCD_printfxy(0,0,"Sats:%02d Fix:2D ", GPSData.NumOfSats);
break;
case SATFIX_3D:
LCD_printfxy(0,0,"Sats:%02d Fix:3D ", GPSData.NumOfSats);
break;
default:
LCD_printfxy(0,0,"Sats:%02d Fix:?? ", GPSData.NumOfSats);
break;
}
LCD_printfxy(0,1,"Speed N: %+4d cm/s",(int16_t)GPSData.Speed_North);
LCD_printfxy(0,2,"Speed E: %+4d cm/s",(int16_t)GPSData.Speed_East);
LCD_printfxy(0,3,"Speed T: %+4d cm/s",(int16_t)GPSData.Speed_Top);
}
break;
case 3:
LCD_printfxy(0,0,"GPS UTC Time");
if (!SystemTime.Valid)
{
LCD_printfxy(0,1," ");
LCD_printfxy(0,2," No time data! ");
LCD_printfxy(0,3," ");
}
else // newdata or processed
{
LCD_printfxy(0,1," ");
LCD_printfxy(0,2,"Date: %02i/%02i/%04i",SystemTime.Month, SystemTime.Day, SystemTime.Year);
LCD_printfxy(0,3,"Time: %02i:%02i:%02i.%03i", SystemTime.Hour, SystemTime.Min, SystemTime.Sec, SystemTime.mSec);
}
break;
 
default: MaxMenuItem = MenuItem - 1;
MenuItem = 0;
break;
}
RemoteKeys = 0;
}
/FollowMe/trunk/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/trunk/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/trunk/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/trunk/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/trunk/sdc.c
0,0 → 1,688
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include "sdc.h"
#include "ssc.h"
#include "timer0.h"
#include "printf_P.h"
#include "crc16.h"
 
//#define _SD_DEBUG
 
#define CMD_GO_IDLE_STATE 0x00 /* CMD00: response R1 */
#define CMD_SEND_OP_COND 0x01 /* CMD01: response R1 */
#define CMD_SEND_IF_COND 0x08 /* CMD08: response R7 */
#define CMD_SEND_CSD 0x09 /* CMD09: response R1 */
#define CMD_SEND_CID 0x0A /* CMD10: response R1 */
#define CMD_SEND_STATUS 0x0D /* CMD13: response R2 */
#define CMD_SET_BLOCKLEN 0x10 /* CMD16: arg0[31:0]: block length, response R1*/
#define CMD_READ_SINGLE_BLOCK 0x11 /* CMD17: arg0[31:0]: data address, response R1 */
#define CMD_WRITE_SINGLE_BLOCK 0x18 /* CMD24: arg0[31:0]: data address, response R1 */
#define CMD_APP_CMD 0x37 /* CMD55: response R1 */
#define CMD_READ_OCR 0x3A /* CMD58: response R3 */
#define CMD_CRC_ON_OFF 0x3B /* CMD59: arg0[31:1]: stuff bits, arg0[0:0]: crc option, response R1 */
#define ACMD_SEND_OP_COND 0x29 /* ACMD41: arg0[31]: stuff bits, arg0[30]: HCS, arg0[29:0] stuff bits*, response R1 */
 
#define R1_NO_ERR 0x00
#define R1_IDLE_STATE 0x01
#define R1_ERASE_RESET 0x02
#define R1_ILLEGAL_CMD 0x04
#define R1_COM_CRC_ERR 0x08
#define R1_ERASE_SEQUENCE_ERR 0x10
#define R1_ADDRESS_ERR 0x20
#define R1_PARAMETER_ERR 0x40
#define R1_BAD_RESPONSE 0x80
 
#define R2_NO_ERR 0x00
#define R2_CARD_LOCKED 0x01
#define R2_ERASE_WRITE_PROT_ERR 0x02
#define R2_UNKOWN_ERR 0x04
#define R2_CARD_CTRL_ERR 0x08
#define R2_CARD_ECC_ERR 0x10
#define R2_WRITE_PROT_ERR 0x20
#define R2_ERASE_PARAM_ERR 0x40
#define R2_OUT_OF_RANGE_ERR 0x80
 
#define DATA_START_TOKEN 0xFE
#define DATA_RESPONSE_MASK 0x1F
#define DATA_RESPONSE_OK 0x05
#define DATA_RESPONSE_CRC_ERR 0x0B
#define DATA_RESPONSE_WRITE_ERR 0x1D
 
typedef enum
{
VER_UNKNOWN,
VER_1X,
VER_20
} SDVersion_t;
 
typedef struct
{
uint8_t Valid;
SDVersion_t Version; // HW-Version
uint32_t Capacity; // Memory capacity in bytes
uint8_t CID[16]; // CID register
uint8_t CSD[16]; // CSD register
} __attribute__((packed)) SDCardInfo_t;
 
 
volatile SDCardInfo_t SDCardInfo;
 
//________________________________________________________________________________________________________________________________________
// Function: CRC7(uint8_t* cmd, uint32_t len);
//
// Description: This function calculated the CRC7 checksum used in the last byte of a spi command frame.
//
//
// Returnvalue: the function returns the crc7 including bit 0 set to 1
//________________________________________________________________________________________________________________________________________
 
uint8_t CRC7(uint8_t *cmd, uint32_t len)
{
uint8_t i, a;
uint8_t crc, Data;
 
crc = 0; // init CRC buffer
for (a = 0; a < len ;a++) // for every byte in the msg
{
Data = cmd[a];
for (i=0;i<8;i++) // for every bit in the byte
{
crc <<= 1; // shift crc
if ((Data & 0x80)^(crc & 0x80)) crc ^=0x09; //xor
Data <<= 1; // shift data for next bit
}
}
crc = (crc<<1)|1; // set terminating bit to 1
return(crc);
}
 
 
uint8_t SDC_WaitForBusy(uint16_t timeout)
{
uint8_t rsp = 0;
uint16_t timestamp = 0;
 
SSC_Enable(); // enable chipselect.
timestamp = SetDelay(timeout);
do
{
rsp = SSC_GetChar();
if(CheckDelay(timestamp)) break;
}while(rsp != 0xFF); // wait while card is busy (data out low)
return(rsp);
}
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_SendCMDR1(uint8_t CmdNo, uint32_t arg);
//
// Description: This function send a command frame to the SD-Card in spi-mode.
//
//
// Returnvalue: The function returns the first response byte like for R1 commands
//________________________________________________________________________________________________________________________________________
uint8_t SDC_SendCMDR1(uint8_t CmdNo, uint32_t arg)
{
uint8_t r1;
uint16_t timeout = 0;
uint16_t a;
uint8_t cmd[6];
 
cmd[0] = 0x40|CmdNo; // set command index
cmd[1] = (arg & 0xFF000000)>>24;
cmd[2] = (arg & 0x00FF0000)>>16;
cmd[3] = (arg & 0x0000FF00)>>8;
cmd[4] = (arg & 0x000000FF);
cmd[5] = CRC7(cmd, 5); // update checksum
#ifdef _SD_DEBUG
printf("\r\nCmd=%02X, arg=%04X%04X", CmdNo, (uint16_t)(arg>>16), (uint16_t)(0xFFFF & arg));
#endif
SSC_Disable(); // disable chipselect.
SSC_PutChar(0xFF); // dummy to sync
SSC_Enable(); // enable chipselect.
 
SDC_WaitForBusy(500); // wait 500ms until card is busy
 
for (a = 0;a < 6; a++) // send the command sequence to the sdcard (6 bytes)
{
SSC_PutChar(cmd[a]);
_delay_loop_2(10);
}
// get response byte
do
{
r1 = SSC_GetChar(); // get byte from sd-card
if (timeout++ > 500) break;
}while(r1 == 0xFF); // wait for the response byte from sd-card.
#ifdef _SD_DEBUG
printf("-->R1=%02X", r1);
#endif
return(r1);
}
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_SendACMDR1(uint8_t CmdNo, uint32_t arg);
//
// Description: This function send a application command frame to the SD-Card in spi-mode.
//
//
// Returnvalue: The function returns the first response byte like for R1 commands
//________________________________________________________________________________________________________________________________________
uint8_t SDC_SendACMDR1(uint8_t CmdNo, uint32_t arg)
{
uint8_t r1 = 0xFF;
r1 = SDC_SendCMDR1(CMD_APP_CMD, 0UL);
if(r1 & R1_BAD_RESPONSE) return(r1);
r1 = SDC_SendCMDR1(CmdNo, arg);
return(r1);
}
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_GetData(uint8_t * cmd ,u8 *Buffer, u32 len);
//
// Description: This function sneds cmd an reads a datablock of len from the sd-card
//
//
// Returnvalue: SD_Result_t
//________________________________________________________________________________________________________________________________________
 
SD_Result_t SDC_GetData(uint8_t CmdNo, uint32_t addr, uint8_t *Buffer, uint32_t len)
{
uint8_t rsp;
uint16_t a, crc16;
SD_Result_t result = SD_ERROR_UNKNOWN;
 
// send the command
rsp = SDC_SendCMDR1(CmdNo, addr);
if (rsp != R1_NO_ERR)
{
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
 
do
{
rsp = SSC_GetChar();
if((rsp & 0xF0) == 0x00) // data error token
{
result = SD_ERROR_READ_DATA;
goto end;
}
}while(rsp != DATA_START_TOKEN);
// data start token received
for (a = 0; a < len; a++) // read the block from the SSC
{
Buffer[a] = SSC_GetChar();
}
// Read two bytes CRC16-Data checksum
crc16 = SSC_GetChar(); // highbyte first
crc16 = (crc16<<8)|SSC_GetChar(); // lowbyte last
/* if(crc16 != CRC16(Buffer, len)) result = SD_ERROR_CRC_DATA;
else */result = SD_SUCCESS;
 
end:
if(result != SD_SUCCESS)
{
printf("Error %02X reading data from sd card (R1=%02X).\r\n", result, rsp);
}
return(result);
}
 
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_PrintCID(u8 * pCID);
//
// Description: This function prints the CIS register in a human readable format.
//
//
// Returnvalue: the function returns nothing
//________________________________________________________________________________________________________________________________________
 
void SDC_PrintCID(uint8_t * pCID)
{
uint8_t pn[6];
uint16_t temp1, temp2;
 
printf("\r\n Manufacturer ID: %i\r\n", pCID[0]);
memcpy(pn, &pCID[1], 2);
pn[2] = '\0'; // terminate string
printf(" Application ID: %s\r\n",pn);
memcpy(pn, &pCID[3], 5);
pn[5] = '\0'; // terminate string
printf(" Product Name: %s\r\n",pn);
printf(" Product Rev.: %i.%i\r\n",pCID[8]>>4, pCID[8]&0xF);
printf(" Serial No.: ");
for(temp1 = 0; temp1<4; temp1++)
{
printf("%02X", pCID[9+temp1]);
}
printf("\r\n");
temp1 = pCID[14] & 0x0F; // month
temp2 = ((pCID[14]>>4)|(pCID[13]<<4)) + 2000; // year
printf(" Manufac. Date: %i/%i\r\n\r\n",temp1, temp2);
}
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_GetCID(uint8_t * pCID);
//
// Description: This function reads the CIS register form the sd card in spi mode.
//
//
// Returnvalue: the function returns error state
//________________________________________________________________________________________________________________________________________
 
SD_Result_t SDC_GetCID(uint8_t * pCID)
{
return SDC_GetData(CMD_SEND_CID, 0UL, pCID, 16);
}
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_GetCSD(uint8_t * pCSD);
//
// Description: This function reads the CSD register form the sd card in spi mode.
//
//
// Returnvalue: the function returns error state
//________________________________________________________________________________________________________________________________________
 
SD_Result_t SDC_GetCSD(uint8_t * pCSD)
{
return SDC_GetData(CMD_SEND_CSD, 0UL, pCSD, 16);
}
 
 
//________________________________________________________________________________________________________________________________________
// Function: 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.
//________________________________________________________________________________________________________________________________________
 
SD_Result_t SDC_Init(void)
{
uint16_t timeout = 0;
uint8_t rsp[6]; // SD-SPI response buffer
SD_Result_t result = SD_ERROR_UNKNOWN;
 
if(SD_SWITCH) // init only if the SD-Switch is indicating a card in the slot
{
printf("\r\n SSC init...");
SSC_Init();
printf("ok");
 
//_delay_loop_2(1050);
 
printf("\r\n SDC init...");
SDCardInfo.Valid = 0;
/* The host shall supply power to the card so that the voltage is reached to Vdd_min within 250ms and
start to supply at least 74 SD clocks to the SD card with keeping cmd line to high. In case of SPI
mode, CS shall be held to high during 74 clock cycles. */
SSC_Disable(); // set SD_CS high
for (timeout = 0; timeout < 15; timeout++) // 15*8 = 120 cycles
{
SSC_PutChar(0xFF);
}
 
// switch to idle state
#ifdef _SD_DEBUG
printf("\r\nGoing idle state..");
#endif
timeout = 0;
do
{
rsp[0] = SDC_SendCMDR1(CMD_GO_IDLE_STATE, 0UL);
if (timeout++ > 500)
{
printf("reset timeout");
result = SD_ERROR_RESET;
goto end;
}
}while(rsp[0] != R1_IDLE_STATE);
// enable crc feature
/* if(SDC_SendCMDR1(CMD_CRC_ON_OFF, 1UL) != R1_IDLE_STATE)
{
printf("Bad cmd59 R1=%02X.", rsp[0]);
result = SD_ERROR_BAD_RESPONSE;
goto end;
}*/
// check for card hw version
// 2.7-3.6V Range = 0x01, check pattern 0xAA
rsp[0] = SDC_SendCMDR1(CMD_SEND_IF_COND, 0x000001AA);
// answer to cmd58 is an R7 response (R1+ 4Byte IFCond)
if(rsp[0] & R1_BAD_RESPONSE)
{
printf("Bad cmd8 R1=%02X.", rsp[0]);
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
if(rsp[0] & R1_ILLEGAL_CMD)
{
//Ver1.X SD Memory Card or not a SD Memory Card
SDCardInfo.Version = VER_1X;
}
else
{
// Ver2.00 or later SD Memory Card
// reading the remaining bytes of the R7 response
SDCardInfo.Version = VER_20;
for(timeout = 1; timeout < 5; timeout++)
{
rsp[timeout] = SSC_GetChar();
}
//check pattern
if(rsp[4]!= 0xAA)
{
printf("Bad cmd8 R7 check pattern.\r\n");
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
if ( (rsp[3] & 0x0F)!= 0x01 ) // voltage range is not 2.7-3.6V
{
 
printf("Card is incompatible to 3.3V.\r\n");
result = SD_ERROR_BAD_VOLTAGE_RANGE;
goto end;
}
}
 
rsp[0] = SDC_SendCMDR1(CMD_READ_OCR, 0UL);
// answer to cmd58 is an R3 response (R1 + 4Byte OCR)
if(rsp[0] & R1_BAD_RESPONSE)
{
printf("Bad cmd58 R1 %02x.", rsp[0]);
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
if(rsp[0] & R1_ILLEGAL_CMD)
{
printf("Not an SD-CARD.");
result = SD_ERROR_NO_SDCARD;
goto end;
}
// read 4 bytes of OCR register
for(timeout = 1; timeout < 5; timeout++)
{
rsp[timeout] = SSC_GetChar();
}
// FollowMe & SD-Logger uses 3.3 V, therefore check for bit 20 & 21
if((rsp[2] & 0x30) != 0x30)
{
// supply voltage is not supported by sd-card
printf("Card is incompatible to 3.3V.");
result = SD_ERROR_BAD_VOLTAGE_RANGE;
goto end;
}
 
// Initialize the sd-card sending continously ACMD_SEND_OP_COND (only supported by SD cards)
timeout = SetDelay(2000); // set timeout to 2000 ms (large cards tend to longer)
do
{
rsp[0] = SDC_SendACMDR1(ACMD_SEND_OP_COND, 0UL);
if(rsp[0] & R1_BAD_RESPONSE)
{
printf("Bad Acmd41 R1=%02X.", rsp[0]);
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
if(CheckDelay(timeout))
{
printf("Init timeout.");
result = SD_ERROR_INITIALIZE;
goto end;
}
} while(rsp[0] & R1_IDLE_STATE); // loop until idle state
 
if(rsp[0] != R1_NO_ERR)
{
printf("Init error.");
result = SD_ERROR_INITIALIZE;
goto end;
}
/* set block size to 512 bytes */
if(SDC_SendCMDR1(CMD_SET_BLOCKLEN, 512UL) != R1_NO_ERR)
{
printf("Error setting block length to 512.");
result = SD_ERROR_SET_BLOCKLEN;
goto end;
}
 
//SSC_Disable(); // set SD_CS high
// here is the right place to inrease the SPI baud rate to maximum
//SSC_Enable(); // set SD_CS high
 
// read CID register
result = SDC_GetCID((uint8_t *)&SDCardInfo.CID);
if(result != SD_SUCCESS)
{
printf("Error reading CID.\r\n");
goto end;
}
 
// read CSD register
result = SDC_GetCSD((uint8_t *)&SDCardInfo.CSD);
if(result != SD_SUCCESS)
{
printf("Error reading CSD.");
goto end;
}
 
printf("ok\r\n");
 
uint8_t c_size_mult, read_bl_len;
uint32_t c_size;
 
switch(SDCardInfo.CSD[0]>>6) // check CSD Version
{
case 0x00: // if CSD is V1.0 structure (2GB limit)
 
/*
memory capacity = BLOCKNR * BLOCK_LEN
BLOCKNR = (C_SIZE+1) * MULT
MULT = 2^(C_SIZE_MULT+2)
BLOCK_LEN = 2^READ_BL_LEN
 
C_SIZE is 12 bits [73:62] in CSD register
C_SIZE_MULT is 3 bits [49:47] in CSD register
READ_BL_LEN is 4 bits [83:80] in CSD register
*/
 
read_bl_len = (SDCardInfo.CSD[5] & 0x0F); //CSD[05] -> [87:80]
c_size = ((uint32_t)(SDCardInfo.CSD[6] & 0x03))<<10; //CSD[06] -> [79:72]
c_size |= ((uint32_t)SDCardInfo.CSD[7])<<2; //CSD[07] -> [71:64]
c_size |= (uint32_t)(SDCardInfo.CSD[8]>>6); //CSD[08] -> [63:56]
c_size_mult = (SDCardInfo.CSD[9] & 0x03)<<1; //CSD[09] -> [55:48]
c_size_mult |=(SDCardInfo.CSD[10] & 0x80)>>7; //CSD[10] -> [47:40]
SDCardInfo.Capacity = (uint32_t)(c_size+1)*(1L<<(c_size_mult+2))*(1L<<read_bl_len);
break;
 
case 0x01: // if CSD is V2.0 structure (HC SD-Card > 2GB)
 
/*
memory capacity = (C_SIZE+1) * 512K byte
C_SIZE is 22 bits [69:48] in CSR register
*/
 
c_size = ((uint32_t)(SDCardInfo.CSD[7] & 0x3F))<<16; //CSD[07] -> [71:64]
c_size |= ((uint32_t)SDCardInfo.CSD[8])<<8; //CSD[08] -> [63:56]
c_size |= (uint32_t)SDCardInfo.CSD[9]; //CSD[09] -> [55:48];
SDCardInfo.Capacity = (c_size + 1)* 512L * 1024L;
break;
 
default: //unknown CSD Version
SDCardInfo.Capacity = 0;
break;
}
 
switch(SDCardInfo.Version)
{
case VER_1X:
printf("\r\n SD-CARD V1.x");
break;
case VER_20:
printf("\r\n SD-CARD V2.0 or later");
default:
break;
}
uint16_t mb_size = (uint16_t)(SDCardInfo.Capacity/(1024L*1024L));
printf("\r\n Capacity = %i MB", mb_size);
 
SDC_PrintCID((uint8_t *)&SDCardInfo.CID);
SDCardInfo.Valid = 1;
// jump point for error condition before
end:
SSC_Disable();
}
else
{
SSC_Deinit();
SDCardInfo.Valid = 0;
result = SD_ERROR_NOCARD;
printf("No Card in Slot.");
}
return(result);
}
 
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_Deinit(void);
//
// Description: This function deinitialises the SDCard interface.
//
//
// Returnvalue: the function returns 0 if the initialisation was successfull otherwise the function returns an errorcode.
//________________________________________________________________________________________________________________________________________
 
SD_Result_t SDC_Deinit(void)
{
printf("\r\n SDC deinit...");
SSC_Deinit();
 
SDCardInfo.Valid = 0;
SDCardInfo.Capacity = 0;
SDCardInfo.Version = VER_UNKNOWN;
 
printf("ok");
return(SD_SUCCESS);
}
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_PutSector(uint32_t addr, const uint8_t *Buffer)
//
// Description: This function writes one sector of data to the SSC
//
//
// Returnvalue: SD_Result_t
//________________________________________________________________________________________________________________________________________
 
SD_Result_t SDC_PutSector(uint32_t addr, const uint8_t *Buffer)
{
uint8_t rsp;
uint16_t a, crc16;
uint16_t timeout = 0;
SD_Result_t result = SD_ERROR_UNKNOWN;
 
addr = addr << 9; // convert sectoradress to byteadress
rsp = SDC_SendCMDR1(CMD_WRITE_SINGLE_BLOCK, addr);
if (rsp != R1_NO_ERR)
{
result = SD_ERROR_BAD_RESPONSE;
goto end;
}
 
for (a=0;a<20;a++) // at least one byte
{
SSC_GetChar();
}
crc16 = CRC16(Buffer, 512); // calc checksum for data block
SSC_PutChar(DATA_START_TOKEN); // send data start of header to the SSC
 
for (a=0;a<512;a++) // transmit one sector (normaly 512bytes) of data to the sdcard.
{
SSC_PutChar(Buffer[a]);
}
// write two bytes of crc16 to the sdcard
SSC_PutChar((uint8_t)(crc16>>8)); // write high byte first
SSC_PutChar((uint8_t)(0x00FF&crc16)); // lowbyte last
 
do // wait for data response token
{
rsp = SSC_GetChar();
if(timeout++ > 500)
{
result = SD_ERROR_TIMEOUT;
goto end;
}
}while((rsp & 0x11) != 0x01 );
// analyse data response token
switch(rsp & DATA_RESPONSE_MASK)
{
case DATA_RESPONSE_OK:
result = SD_SUCCESS;
break;
case DATA_RESPONSE_CRC_ERR:
result = SD_ERROR_CRC_DATA;
goto end;
break;
case DATA_RESPONSE_WRITE_ERR:
result = SD_ERROR_WRITE_DATA;
goto end;
break;
default:
result = SD_ERROR_UNKNOWN;
goto end;
break;
 
}
// wait 2 seconds until the sdcard is busy.
rsp = SDC_WaitForBusy(2000);
if(rsp != 0xFF)
{
result = SD_ERROR_TIMEOUT;
goto end;
}
 
// check card status
rsp = SDC_SendCMDR1(CMD_SEND_STATUS, 0);
// first byte of R2 response is like R1 response
if(rsp != R1_NO_ERR)
{
result = SD_ERROR_BAD_RESPONSE;
SSC_GetChar(); // read out 2nd byte
goto end;
}
// 2nd byte of r2 response
rsp = SSC_GetChar();
if(rsp != R2_NO_ERR)
{
result = SD_ERROR_WRITE_DATA;
SSC_GetChar();
goto end;
}
end:
if(result != SD_SUCCESS)
{
printf("Error %02X writing data to sd card (R=%02X).\r\n", result, rsp);
}
return(result);
}
 
 
 
 
//________________________________________________________________________________________________________________________________________
// Function: SDC_GetSector(uint32_t addr,uint8_t *Buffer);
//
// Description: This function reads one sector of data from the SSC
//
//
// Returnvalue: SD_Result_t
//________________________________________________________________________________________________________________________________________
 
SD_Result_t SDC_GetSector(uint32_t addr,uint8_t *Buffer)
{
addr = addr << 9; // convert sectoradress to byteadress
return SDC_GetData(CMD_READ_SINGLE_BLOCK, addr, Buffer, 512);
}
 
/FollowMe/trunk/sdc.h
0,0 → 1,30
#ifndef _SDC_H_
#define _SDC_H_
 
#include <inttypes.h>
 
typedef enum
{
SD_SUCCESS = 0,
SD_ERROR_NOCARD,
SD_ERROR_RESET,
SD_ERROR_INITIALIZE,
SD_ERROR_BAD_RESPONSE,
SD_ERROR_BAD_VOLTAGE_RANGE,
SD_ERROR_NO_SDCARD,
SD_ERROR_TIMEOUT,
SD_ERROR_CRC_DATA,
SD_ERROR_WRITE_DATA,
SD_ERROR_READ_DATA,
SD_ERROR_SET_BLOCKLEN,
SD_ERROR_UNKNOWN
} SD_Result_t;
 
extern SD_Result_t SDC_Init(void);
extern SD_Result_t SDC_GetSector (uint32_t Addr, uint8_t *pBuffer);
extern SD_Result_t SDC_PutSector (uint32_t Addr, const uint8_t *pBuffer);
extern SD_Result_t SDC_Deinit(void);
 
#endif
 
 
/FollowMe/trunk/settings.c
0,0 → 1,225
/*#######################################################################################*/
/* !!! THIS IS NOT FREE SOFTWARE !!! */
/*#######################################################################################*/
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Copyright (c) 2008 Ingo Busker, Holger Buss
// + Nur für den privaten Gebrauch
// + FOR NON COMMERCIAL USE ONLY
// + 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 (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 sonstigen Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
// + eindeutig als Ursprung verlinkt 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 permitted
// + 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 this software (or part of it) 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "printf_P.h"
#include "fat16.h"
#include "settings.h"
#include "uart0.h"
 
typedef struct
{
ParamId_t ParamId;
int8_t Name[17]; // 0 terminator is the last byte
uint8_t Group; // 0 = reserved 1,2,3,4
uint16_t Value;
uint16_t Default;
uint16_t Min;
uint16_t Max;
} __attribute__((packed)) Parameter_t;
 
Parameter_t CFG_Parameter[] =
{
//{PID , "1234567890123456" , Group, Value, Default, Min, Max },
{PID_KML_LOGGING , "KMLLogging " , 1, 500, 500, 0, 60000}, // the log interval for KML logging, 0 = off
{PID_GPX_LOGGING , "GPXLogging " , 1, 1000, 1000, 0, 60000} // the log interval for GPX logging, 0 = off
};
 
 
//----------------------------------------------------------------------------------
// initialize all parameters by its default value
void Settings_SetDefaultValues(void)
{
uint8_t i;
// run thrue all parameters and set value to default
for (i = 0; i < sizeof(CFG_Parameter) / sizeof(Parameter_t); i++)
{
CFG_Parameter[i].Value = CFG_Parameter[i].Default;
}
}
 
//----------------------------------------------------------------------------------
// set parameter from string based name and value
uint8_t Settings_SetParameterFromString(int8_t *name, int8_t *value)
{
uint8_t i, retval = 0;
int8_t string[] = " \0"; // null terminated string of 16 characters
 
if((name == NULL) || (value == NULL)) return(retval);
 
i = strlen(name); // lenght of the parameter name
if (i > 16) i = 16; // cut off at 16
 
memcpy(string, name, i); // copy name to local buffer
 
// search name in parameter list
for (i = 0; i < sizeof(CFG_Parameter) / sizeof(Parameter_t); i++)
{
if(strncmp(string, CFG_Parameter[i].Name, 16) == 0) // names are matching
{
CFG_Parameter[i].Value = (uint16_t)atoi(value); // convert string to number and set value
// out of range ?
if((CFG_Parameter[i].Value < CFG_Parameter[i].Min) || (CFG_Parameter[i].Value > CFG_Parameter[i].Max))
{ // print a warning
printf("\r\n%s <-- %d is out of range [%d...%d]", string, CFG_Parameter[i].Value, CFG_Parameter[i].Min, CFG_Parameter[i].Max);
CFG_Parameter[i].Value = CFG_Parameter[i].Default; // fallback to default
}
retval = 1; // value in range
break; // end loop
}
}
if(!retval)
{
printf("\r\n%s <-- unknown parameter\r\n", string);
}
return(retval);
}
 
//----------------------------------------------------------------------------------
// read settings from file on sd-card
void Settings_Init(void)
{
#define LINE_MAX 32
File_t *fp;
int8_t settingsline[LINE_MAX];
char *name, *value;
uint8_t i;
char *tmp;
 
printf("\r\n Settings init...");
Settings_SetDefaultValues();
 
if(Fat16_IsValid())
{ // check if settings file is existing
if(fexist_("settings.ini"))
{
fp = fopen_("settings.ini", 'r'); // try to open the file
if (fp == NULL) // could not open the file
{
printf("ERROR: Opening settings file!");
return;
}
// read all lines from file
while(fgets_(settingsline, LINE_MAX, fp) != 0)
{
if ( // ignorelines starting with \r,\n,' ',';','#'
(settingsline[0] != '\n') &&
(settingsline[0] != '\r') &&
(settingsline[0] != ' ' ) &&
(settingsline[0] != ';' ) &&
(settingsline[0] != '#' )
)
{
name = strtok_r(settingsline, "=", & tmp); // get name
value = strtok_r(NULL, "=", & tmp); // get value
if ((name != NULL) && (value != NULL))
{
Settings_SetParameterFromString(name, value);
}
}
}
fclose_(fp);
printf("ok");
return;
}
else // settings file does not exist
{ // create default settings file
fp = fopen_("settings.ini", 'w'); // try to open the file
if(fp == NULL)
{
printf("ERROR: Creating default settings file!");
return;
}
// run thrue all parameters and set value to default
for (i = 0; i < sizeof(CFG_Parameter) / sizeof(Parameter_t); i++)
{
sprintf(settingsline, "%s = %d\r\n", CFG_Parameter[i].Name, CFG_Parameter[i].Default);
fputs_(settingsline, fp); // write to file
}
fputs_("\r\n", fp); // newline at the end of file
fclose_(fp);
printf("Default settings file created!");
return;
}
}
else // no acces to fat 16 filesystem
{
printf("Using default values!");
return;
}
}
 
 
//----------------------------------------------------------------------------------
// read value of a paramter identified by its id
// returns 1 on success and 0 on error
uint8_t Settings_GetParamValue(ParamId_t Pid, uint16_t * pValue)
{
uint8_t i, retval = 0;
 
for (i = 0; i < sizeof(CFG_Parameter) / sizeof(Parameter_t); i++)
{
if(CFG_Parameter[i].ParamId == Pid)
{
*pValue = CFG_Parameter[i].Value;
retval = 1;
break;
}
}
return retval;
}
/FollowMe/trunk/settings.h
0,0 → 1,16
#ifndef _SETTINGS_H
#define _SETTINGS_H
 
typedef enum
{
PID_KML_LOGGING,
PID_GPX_LOGGING
} ParamId_t;
 
void Settings_Init(void);
void Settings_SetDefaultValues(void);
uint8_t Settings_GetParamValue(ParamId_t Pid, uint16_t* pValue);
 
#endif // _SETTINGS_H
 
 
/FollowMe/trunk/ssc.c
0,0 → 1,216
#include <avr/io.h>
#include "ssc.h"
 
//-------------------------------------- Hardware specific definitions --------------------------------------
#define PORTR_SPI PINB
#define PORTW_SPI PORTB //Port to which the sd-card is connected (SPI Port)
#define PORT_MISO PORTB6 //Port Pin that is connected to the DO of the MMC/SD-card
#define PORT_MOSI PORTB5 //Port Pin that is connected to DI of the MMC/SD-card
#define PORT_SCK PORTB7 //Port Pin that is connected the CLK of the MMC/SD-card
#define PORT_SS PORTB4 //Slave Select is not used in SPI Master Mode, but must be defined
#define PORT_CS PORTB4 //Port Pin that is connected to /CS of the MMC/SD-Karte
 
 
#ifdef USE_SDLOGGER
#define __SD_INTERFACE_INVERTED // the interface between the controller and the 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 __SD_INTERFACE_INVERTED // the interface between the controller and the MMC/SD-card uses an inverting leveltranslator (transistorinverter)
#endif
 
#define DDR_SPI DDRB
#define DD_MISO DDB6 //Port Pin that is connected to the DO of the MMC/SD-card
#define DD_MOSI DDB5 //Port Pin that is connected to DI of the MMC/SD-card
#define DD_SCK DDB7 //Port Pin that is connected the CLK of the MMC/SD-card
#define DD_SS DDB4 //Slave Select is not used in SPI Master Mode, but must be defined
#define DD_CS DDB4 //Port Pin that is connected to /CS of the MMC/SD-Karte
 
// for compatibility reasons gcc3.x <-> gcc4.x
#ifndef SPCR
#define SPCR SPCR0
#endif
#ifndef SPIE
#define SPIE SPIE0
#endif
#ifndef SPE
#define SPE SPE0
#endif
#ifndef DORD
#define DORD DORD0
#endif
#ifndef MSTR
#define MSTR MSTR0
#endif
#ifndef CPOL
#define CPOL CPOL0
#endif
#ifndef CPHA
#define CPHA CPHA0
#endif
#ifndef SPR1
#define SPR1 SPR01
#endif
#ifndef SPR0
#define SPR0 SPR00
#endif
 
#ifndef SPDR
#define SPDR SPDR0
#endif
 
#ifndef SPSR
#define SPSR SPSR0
#endif
#ifndef SPIF
#define SPIF SPIF0
#endif
#ifndef WCOL
#define WCOL WCOL0
#endif
#ifndef SPI2X
#define SPI2X SPI2X0
#endif
 
 
//________________________________________________________________________________________________________________________________________
// Function: SSC_Init(void);
//
// Description: This function initialises the synchronus serial channel to the sdcard.
//
//
// Returnvalue: none
//________________________________________________________________________________________________________________________________________
 
void SSC_Init(void)
{
// Set MOSI,SCK and CS as output
DDR_SPI |= (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_CS);
// set MISO as input
DDR_SPI &= ~(1<<DD_MISO);
 
SSC_Disable();
 
// 20MHz / 32 = 625 kHz
#ifdef __SD_INTERFACE_INVERTED
SPCR = (1<<SPE)|(1<<MSTR)|(0<<DORD)|(1<<CPOL)|(0<<CPHA)|(1<<SPR1)|(0<<SPR0); // Enable SSC in mastermode, inverted clockpolarity (idle high)
#else
SPCR = (1<<SPE)|(1<<MSTR)|(0<<DORD)|(0<<CPOL)|(0<<CPHA)|(1<<SPR1)|(0<<SPR0); // Enable SSC in mastermode, noninverted clockpolarity (idle low)
#endif
SPSR |= (1<<SPI2X);
 
// set port pin as input pullup for SD-Card switch
#ifdef USE_FOLLOWME
PORTB |= (1 << PORTB2);
DDRB &= ~(1 << DDB2);
#endif
 
#ifdef USE_SDLOGGER
PORTB |= (1 << PORTB3);
DDRB &= ~(1 << DDB3);
#endif
}
 
void SSC_Deinit(void)
{
SSC_Disable();
SPCR = 0;
SPSR = 0;
}
 
//________________________________________________________________________________________________________________________________________
// Function: SSC_GetChar(void);
//
// Description: This function reads one byte from the SSC
//
//
// Returnvalue: the byte received.
//________________________________________________________________________________________________________________________________________
 
uint8_t SSC_GetChar (void)
{
uint8_t Byte = 0;
 
#ifdef __SD_INTERFACE_INVERTED
SPDR = 0x00; // send dummy byte to initiate the reading
#else
SPDR = 0xFF; // send dummy byte to initiate the reading
#endif
while(!(SPSR & (1<<SPIF)))
{
// wait until the data has been read.
}
Byte = SPDR;
 
#ifdef __SD_INTERFACE_INVERTED
Byte = ~Byte;
#endif
 
return(Byte);
}
 
 
//________________________________________________________________________________________________________________________________________
// Function: SSC_PutChar(u8 Byte);
//
// Description: This function writes one byte to the SSC
//
//
// Returnvalue: none
//________________________________________________________________________________________________________________________________________
 
void SSC_PutChar (uint8_t Byte)
{
 
#ifdef __SD_INTERFACE_INVERTED
SPDR = ~Byte; // send one byte of data to the SSC
#else
SPDR = Byte; // send one byte of data to the SSC
#endif
while(!(SPSR & (1<<SPIF)))
{
// wait until the data has been sent.
}
}
 
 
//________________________________________________________________________________________________________________________________________
// Function: SSC_Disable(void);
//
// Description: This function enables chipselect of the sdcard (active low)
//
//
// Returnvalue: none
//________________________________________________________________________________________________________________________________________
 
void SSC_Disable(void)
{
#ifdef __SD_INTERFACE_INVERTED
PORTW_SPI &= ~(1<<PORT_CS); // disable chipselect of the sdcard (active low).
#else
PORTW_SPI |= (1<<PORT_CS); // disable chipselect of the sdcard (active low).
#endif
}
 
 
 
 
//________________________________________________________________________________________________________________________________________
// Function: SSC_Enable(void);
//
// Description: This function disables chipselect of the sdcard (active low)
//
//
// Returnvalue: none
//________________________________________________________________________________________________________________________________________
 
void SSC_Enable(void)
{
#ifdef __SD_INTERFACE_INVERTED
PORTW_SPI |= (1<<PORT_CS); // enable chipselect of the sdcard (active low).
#else
PORTW_SPI &= ~(1<<PORT_CS); // enable chipselect of the sdcard (active low).
#endif
}
 
 
/FollowMe/trunk/ssc.h
0,0 → 1,20
#ifndef __SSC_H
#define __SSC_H
 
#include <inttypes.h>
 
#ifdef USE_FOLLOWME
#define SD_SWITCH !(PINB & (1<<PINB2))
#endif
#ifdef USE_SDLOGGER
#define SD_SWITCH !(PINB & (1<<PINB3))
#endif
 
extern void SSC_Init(void);
extern uint8_t SSC_GetChar(void);
extern void SSC_PutChar(uint8_t);
extern void SSC_Enable(void);
extern void SSC_Disable(void);
extern void SSC_Deinit(void);
 
#endif //__SSC_H
/FollowMe/trunk/timer0.c
0,0 → 1,138
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
 
#include "timer0.h"
 
volatile uint16_t CountMilliseconds = 0;
DateTime_t SystemTime;
 
volatile uint16_t BeepTime = 0;
volatile uint16_t BeepModulation = 0xFFFF;
 
/*****************************************************/
/* 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();
 
 
// configure speaker port as output
 
#ifdef USE_FOLLOWME
// Speaker at PC7
DDRC |= (1<<DDC7);
PORTC &= ~(1<<PORTC7);
#endif
 
// Timer/Counter 0 Control Register A
 
// Waveform Generation None (Bits WGM02 = 0, WGM01 = 0, WGM00 = 0)
TCCR0A &= ~((1<<COM0A0)|(1<<COM0B0)|(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);
 
// 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);
 
 
SystemTime.Year = 0;
SystemTime.Month = 0;
SystemTime.Day = 0;
SystemTime.Hour = 0;
SystemTime.Min = 0;
SystemTime.Sec = 0;
SystemTime.mSec = 0;
SystemTime.Valid = 0;
 
CountMilliseconds = 0;
 
 
SREG = sreg;
}
 
 
 
/*****************************************************/
/* Interrupt Routine of Timer 0 */
/*****************************************************/
ISR(TIMER0_OVF_vect) // 9.765 kHz
{
static uint8_t cnt = 0;
#ifdef USE_FOLLOWME
uint8_t Beeper_On = 0;
#endif
 
if(!cnt--) // every 10th run (9.765kHz/10 = 976Hz)
{
cnt = 9;
CountMilliseconds++; // increment millisecond counter
}
 
// beeper on if duration is not over
if(BeepTime)
{
BeepTime--; // decrement BeepTime
if(BeepTime & BeepModulation) Beeper_On = 1;
else Beeper_On = 0;
}
else // beeper off if duration is over
{
Beeper_On = 0;
BeepModulation = 0xFFFF;
}
#ifdef USE_FOLLOWME
// if beeper is on
if(Beeper_On)
{
// set speaker port to high
PORTC |= (1<<PORTC7); // Speaker at PC7
}
else // beeper is off
{
// set speaker port to low
PORTC &= ~(1<<PORTC7);// Speaker at PC7
}
#endif
}
 
 
// -----------------------------------------------------------------------
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/trunk/timer0.h
0,0 → 1,30
#ifndef _TIMER0_H
#define _TIMER0_H
 
#include <inttypes.h>
 
typedef struct{
uint16_t Year;
uint8_t Month;
uint8_t Day;
uint8_t Hour;
uint8_t Min;
uint8_t Sec;
uint16_t mSec;
uint8_t Valid;
} DateTime_t;
 
extern DateTime_t SystemTime;
 
extern volatile uint16_t CountMilliseconds;
 
extern volatile uint16_t BeepTime;
extern volatile uint16_t BeepModulation;
 
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/trunk/uart0.c
0,0 → 1,524
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + 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
 
uint8_t text[100]; // globally used text buffer
 
//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 Request_SendFollowMe = FALSE;
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
 
Waypoint_t FollowMe;
 
const uint8_t ANALOG_LABEL[32][16] =
{
//1234567890123456
"Analog_Ch0 ", //0
"Analog_Ch1 ",
"Analog_Ch2 ",
"Analog_Ch3 ",
"Analog_Ch4 ",
"Analog_Ch5 ", //5
"Analog_Ch6 ",
"Analog_Ch7 ",
"UBat ",
"Speed_North ",
"Speed_East ", //10
"Speed_Top ",
"NumOfSats ",
"Pos.Longitude ",
"Pos.Latitude ",
"Pos.Altitude ", //15
"Zellenzahl ",
"PowerOn ",
"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:
//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;
}
if(Request_SendFollowMe && txd_complete)
{
SendOutData('s', NC_ADDRESS, 1, (uint8_t *)&FollowMe, sizeof(FollowMe));
FollowMe.Position.Status = PROCESSED;
Request_SendFollowMe = FALSE;
}
}
 
/FollowMe/trunk/uart0.h
0,0 → 1,75
#ifndef _UART0_H
#define _UART0_H
 
#include "ubx.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;
 
extern uint8_t text[100]; // globally used text buffer
 
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;
 
typedef struct
{
GPS_Pos_t Position; // the gps position of the waypoint, see ubx.h for details
int16_t Heading; // orientation, future implementation
uint8_t ToleranceRadius; // in meters, if the MK is within that range around the target, then the next target is triggered
uint8_t HoldTime; // in seconds, if the was once in the tolerance area around a WP, this time defines the delay before the next WP is triggered
uint8_t Event_Flag; // future implementation
uint8_t reserve[12]; // reserve
} __attribute__((packed)) Waypoint_t;
 
extern Waypoint_t FollowMe;
extern uint8_t Request_SendFollowMe;
 
#endif //_UART0_H
/FollowMe/trunk/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/trunk/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/trunk/ubx.c
0,0 → 1,413
#include <inttypes.h>
#include "ubx.h"
#include "timer0.h"
#include "uart0.h"
 
 
// ------------------------------------------------------------------------------------------------
// defines
 
#define DAYS_FROM_JAN01YEAR0001_TO_JAN6_1980 722819 // the year 0 does not exist!
#define DAYS_PER_YEAR 365
#define DAYS_PER_LEAPYEAR 366
#define DAYS_PER_4YEARS 1461 //((3 * DAYS_PER_YEAR) + DAYS_PER_LEAPYEAR) // years dividable by 4 are leap years
#define DAYS_PER_100YEARS 36524 //((25 * DAYS_PER_4YEARS) - 1) // years dividable by 100 are no leap years
#define DAYS_PER_400YEARS 146097 //((4 * DAYS_PER_100YEARS) + 1L) // but years dividable by 400 are leap years
#define SECONDS_PER_MINUTE 60
#define MINUTES_PER_HOUR 60
#define HOURS_PER_DAY 24
#define DAYS_PER_WEEK 7
#define SECONDS_PER_HOUR 3600 //(SECONDS_PER_MINUTE * MINUTES_PER_HOUR)
#define SECONDS_PER_DAY 86400 //(SECONDS_PER_HOUR * HOURS_PER_DAY)
#define SECONDS_PER_WEEK 604800 //(SECONDS_PER_DAY * DAYS_PER_WEEK)
 
// days per month in normal and leap years
const uint32_t Leap[ 13 ] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
const uint32_t Normal[ 13 ] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
 
#define LEAP_SECONDS_FROM_1980 15 // the last one was on the Dec 31th 2008
 
// message sync bytes
#define UBX_SYNC1_CHAR 0xB5
#define UBX_SYNC2_CHAR 0x62
// protocoll identifier
#define UBX_CLASS_NAV 0x01
// message id
#define UBX_ID_POSLLH 0x02
#define UBX_ID_SOL 0x06
#define UBX_ID_VELNED 0x12
 
// ------------------------------------------------------------------------------------------------
// typedefs
 
 
// ubx parser state
typedef enum
{
UBXSTATE_IDLE,
UBXSTATE_SYNC1,
UBXSTATE_SYNC2,
UBXSTATE_CLASS,
UBXSTATE_LEN1,
UBXSTATE_LEN2,
UBXSTATE_DATA,
UBXSTATE_CKA,
UBXSTATE_CKB
} ubxState_t;
 
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
int32_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
uint8_t Status; // invalid/newdata/processed
} __attribute__((packed)) ubx_nav_sol_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
int32_t Speed; // cm/s Speed (3-D)
int32_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
uint8_t Status; // invalid/newdata/processed
} __attribute__((packed)) ubx_nav_velned_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
uint8_t Status; // invalid/newdata/processed
} __attribute__((packed)) ubx_nav_posllh_t;
 
 
 
//------------------------------------------------------------------------------------
// global variables
 
// local buffers for the incomming ubx messages
volatile ubx_nav_sol_t UbxSol = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, INVALID};
volatile ubx_nav_posllh_t UbxPosLlh = {0,0,0,0,0,0,0, INVALID};
volatile ubx_nav_velned_t UbxVelNed = {0,0,0,0,0,0,0,0,0, INVALID};
 
uint16_t CheckGPSOkay = 0;
 
// shared buffer
gps_data_t GPSData = {{0,0,0,INVALID},0,0,0,0,0,0,0, INVALID};
 
//------------------------------------------------------------------------------------
// functions
 
uint8_t IsLeapYear(uint16_t year)
{
if((year%400 == 0) || ( (year%4 == 0) && (year%100 != 0) ) ) return 1;
else return 0;
}
 
/********************************************************/
/* Calculates the UTC Time from the GPS week and tow */
/********************************************************/
void SetGPSTime(DateTime_t * pTimeStruct)
{
uint32_t Days, Seconds, Week;
uint16_t YearPart;
uint32_t * MonthDayTab = 0;
uint8_t i;
 
 
 
// if GPS data show valid time data
if((UbxSol.Status != INVALID) && (UbxSol.Flags & FLAG_WKNSET) && (UbxSol.Flags & FLAG_TOWSET) )
{
Seconds = UbxSol.itow / 1000L;
Week = (uint32_t)UbxSol.week;
// correct leap seconds since 1980
if(Seconds < LEAP_SECONDS_FROM_1980)
{
Week--;
Seconds = SECONDS_PER_WEEK - LEAP_SECONDS_FROM_1980 + Seconds;
}
else Seconds -= LEAP_SECONDS_FROM_1980;
 
Days = DAYS_FROM_JAN01YEAR0001_TO_JAN6_1980;
Days += (Week * DAYS_PER_WEEK);
Days += Seconds / SECONDS_PER_DAY; // seperate days from GPS seconds of week
 
pTimeStruct->Year = 1;
YearPart = (uint16_t)(Days / DAYS_PER_400YEARS);
pTimeStruct->Year += YearPart * 400;
Days = Days % DAYS_PER_400YEARS;
YearPart = (uint16_t)(Days / DAYS_PER_100YEARS);
pTimeStruct->Year += YearPart * 100;
Days = Days % DAYS_PER_100YEARS;
YearPart = (uint16_t)(Days / DAYS_PER_4YEARS);
pTimeStruct->Year += YearPart * 4;
Days = Days % DAYS_PER_4YEARS;
if(Days < (3* DAYS_PER_YEAR)) YearPart = (uint16_t)(Days / DAYS_PER_YEAR);
else YearPart = 3;
pTimeStruct->Year += YearPart;
// calculate remaining days of year
Days -= (uint32_t)(YearPart * DAYS_PER_YEAR);
Days += 1;
// check if current year is a leap year
if(IsLeapYear(pTimeStruct->Year)) MonthDayTab = (uint32_t*)Leap;
else MonthDayTab = (uint32_t*)Normal;
// seperate month and day from days of year
for ( i = 0; i < 12; i++ )
{
if ( (MonthDayTab[i]< Days) && (Days <= MonthDayTab[i+1]) )
{
pTimeStruct->Month = i+1;
pTimeStruct->Day = Days - MonthDayTab[i];
i = 12;
}
}
Seconds = Seconds % SECONDS_PER_DAY; // remaining seconds of current day
pTimeStruct->Hour = (uint8_t)(Seconds / SECONDS_PER_HOUR);
Seconds = Seconds % SECONDS_PER_HOUR; // remaining seconds of current hour
pTimeStruct->Min = (uint8_t)(Seconds / SECONDS_PER_MINUTE);
Seconds = Seconds % SECONDS_PER_MINUTE; // remaining seconds of current minute
pTimeStruct->Sec = (uint8_t)(Seconds);
pTimeStruct->mSec = (uint16_t)(UbxSol.itow % 1000L);
pTimeStruct->Valid = 1;
}
else
{
pTimeStruct->Valid = 0;
}
}
 
 
 
/********************************************************/
/* Initialize UBX Parser */
/********************************************************/
void UBX_Init(void)
{
// mark msg buffers invalid
UbxSol.Status = INVALID;
UbxPosLlh.Status = INVALID;
UbxVelNed.Status = INVALID;
GPSData.Status = INVALID;
}
 
/********************************************************/
/* Upate GPS data stcructure */
/********************************************************/
void Update_GPSData (void)
{
static uint16_t Ubx_Timeout = 0;
static uint8_t Msg_Count = 0;
 
// the timeout is used to detect the delay between two message sets
// and is used for synchronisation so that always a set is collected
// that belongs together
// _______NAVSOL|POSLLH|VELNED|___________________NAVSOL|POSLLH|VELNED|_____________
// | 8ms | 8ms | 184 ms | | |
// msg_count: 0 1 2 0 1 2
 
if(CheckDelay(Ubx_Timeout)) Msg_Count = 0;
else Msg_Count++;
Ubx_Timeout = SetDelay(100); // reset ubx msg timeout
 
// if a new set of ubx messages was collected
if((Msg_Count >= 2))
{ // if set is complete
if((UbxSol.Status == NEWDATA) && (UbxPosLlh.Status == NEWDATA) && (UbxVelNed.Status == NEWDATA))
{
CheckGPSOkay++;
// update GPS data only if the status is INVALID or PROCESSED and the last ubx message was received within less than 100 ms
if(GPSData.Status != NEWDATA) // if last data were processed
{ // wait for new data at all neccesary ubx messages
GPSData.Status = INVALID;
// NAV SOL
GPSData.Flags = UbxSol.Flags;
GPSData.NumOfSats = UbxSol.numSV;
GPSData.SatFix = UbxSol.GPSfix;
GPSData.Position_Accuracy = UbxSol.PAcc;
GPSData.Speed_Accuracy = UbxSol.SAcc;
SetGPSTime(&SystemTime); // update system time
// NAV POSLLH
GPSData.Position.Status = INVALID;
GPSData.Position.Longitude = UbxPosLlh.LON;
GPSData.Position.Latitude = UbxPosLlh.LAT;
GPSData.Position.Altitude = UbxPosLlh.HMSL;
GPSData.Position.Status = NEWDATA;
// NAV VELNED
GPSData.Speed_East = UbxVelNed.VEL_E;
GPSData.Speed_North = UbxVelNed.VEL_N;
GPSData.Speed_Top = -UbxVelNed.VEL_D;
GPSData.Speed_Ground = UbxVelNed.GSpeed;
GPSData.Heading = UbxVelNed.Heading;
 
GPSData.Status = NEWDATA; // new data available
} // EOF if(GPSData.Status != NEWDATA)
} // EOF all ubx messages received
// set state to collect new data
UbxSol.Status = PROCESSED; // ready for new data
UbxPosLlh.Status = PROCESSED; // ready for new data
UbxVelNed.Status = PROCESSED; // ready for new data
}
}
 
 
/********************************************************/
/* UBX Parser */
/********************************************************/
void UBX_Parser(uint8_t c)
{
static ubxState_t ubxState = UBXSTATE_IDLE;
static uint16_t msglen;
static uint8_t cka, ckb;
static uint8_t *ubxP, *ubxEp, *ubxSp; // pointers to data currently transfered
 
 
//state machine
switch (ubxState) // ubx message parser
{
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 = (uint8_t *)&UbxPosLlh; // data start pointer
ubxEp = (uint8_t *)(&UbxPosLlh + 1); // data end pointer
ubxSp = (uint8_t *)&UbxPosLlh.Status; // status pointer
break;
 
case UBX_ID_SOL: // navigation solution
ubxP = (uint8_t *)&UbxSol; // data start pointer
ubxEp = (uint8_t *)(&UbxSol + 1); // data end pointer
ubxSp = (uint8_t *)&UbxSol.Status; // status pointer
break;
 
case UBX_ID_VELNED: // velocity vector in tangent plane
ubxP = (uint8_t *)&UbxVelNed; // data start pointer
ubxEp = (uint8_t *)(&UbxVelNed + 1); // data end pointer
ubxSp = (uint8_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 = (uint16_t)c; // lowbyte first
cka += c;
ckb += cka;
ubxState = UBXSTATE_LEN2;
break;
 
case UBXSTATE_LEN2: // 2nd message length byte
msglen += ((uint16_t)c)<<8; // high byte last
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 )
{
ubxState = UBXSTATE_IDLE;
Update_GPSData(); //update GPS info respectively
}
else // data invalid or allready processd
{
*ubxSp = INVALID; // mark invalid during buffer filling
ubxState = UBXSTATE_DATA;
}
break;
 
case UBXSTATE_DATA: // collecting 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
}
else // rx buffer overrun
{
ubxState = UBXSTATE_IDLE;
}
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
Update_GPSData(); //update GPS info respectively
}
else
{ // if checksum not match then set data invalid
*ubxSp = INVALID;
}
ubxState = UBXSTATE_IDLE; // ready to parse new data
break;
 
default: // unknown ubx state
ubxState = UBXSTATE_IDLE;
break;
 
}
DebugOut.Analog[9] = GPSData.Speed_North;
DebugOut.Analog[10] = GPSData.Speed_East;
DebugOut.Analog[11] = GPSData.Speed_Top;
DebugOut.Analog[12] = GPSData.NumOfSats;
DebugOut.Analog[13] = GPSData.Position.Longitude;
DebugOut.Analog[14] = GPSData.Position.Latitude;
DebugOut.Analog[15] = GPSData.Position.Altitude;
}
/FollowMe/trunk/ubx.h
0,0 → 1,57
#ifndef _UBX_H
#define _UBX_H
 
#include <inttypes.h>
 
 
// 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)
 
#define INVALID 0x00
#define NEWDATA 0x01
#define PROCESSED 0x02
 
typedef struct
{
int32_t Longitude; // in 1E-7 deg
int32_t Latitude; // in 1E-7 deg
int32_t Altitude; // in mm
uint8_t Status; // validity of data
} __attribute__((packed)) GPS_Pos_t;
 
 
typedef struct
{
GPS_Pos_t Position; // Lat/Lon/Alt
uint8_t Flags; // Status Flags
uint8_t NumOfSats; // number of satelites
uint8_t SatFix; // type of satfix
uint32_t Position_Accuracy; // in cm 3d position accuracy
int32_t Speed_North; // in cm/s
int32_t Speed_East; // in cm/s
int32_t Speed_Top; // in cm/s
uint32_t Speed_Ground; // 2D ground speed in cm/s
int32_t Heading; // 1e-05 deg Heading 2-D (curent flight direction)
uint32_t Speed_Accuracy; // in cm/s 3d velocity accuracy
uint8_t Status; // status of data
} __attribute__((packed)) gps_data_t;
 
// The data are valid if the GPSData.Status is NEWDATA or PROCESSED.
// To achieve new data after reading the GPSData.Status should be set to PROCESSED.
extern gps_data_t GPSData;
extern uint16_t CheckGPSOkay;
 
void UBX_Init(void);
void UBX_Parser(uint8_t c);
 
#endif // _UBX_H