/branches/V0.1 killagreg/uart.h |
---|
File deleted |
/branches/V0.1 killagreg/GPSUart.c |
---|
File deleted |
/branches/V0.1 killagreg/GPSUart.h |
---|
File deleted |
/branches/V0.1 killagreg/uart.c |
---|
File deleted |
/branches/V0.1 killagreg/GPS.c |
---|
1,252 → 1,377 |
/*#######################################################################################*/ |
/* !!! 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 <math.h> |
#include "91x_lib.h" |
#include "main.h" |
#include "uart.h" |
#include "uart1.h" |
#include "ubx.h" |
#include "GPS.h" |
#include "fat16.h" |
#include "timer.h" |
#include "spi_slave.h" |
u8 OsdBar; // Direction home for OSD |
s16 OsdDistance; // Distance home |
#define M_PI_180 (M_PI / 180.0f) |
#define GPS_UPDATETIME_MS 200 // 200ms or 5Hz |
GPSStick_t GPSStick; |
GPSParameter_t GPSParameter; |
typedef enum |
{ |
GPS_FLIGHT_MODE_UNDEF, |
GPS_FLIGHT_MODE_FREE, |
GPS_FLIGHT_MODE_AID, |
GPS_FLIGHT_MODE_HOME, |
} FlightMode_t; |
u8 logtext[100]; |
typedef struct |
{ |
float Gain; |
float P; |
float I; |
float D; |
float ACC; |
u8 MinSat; |
s8 StickThreshold; |
FlightMode_t FlightMode; |
} __attribute__((packed)) GPS_Parameter_t; |
typedef enum |
typedef struct |
{ |
GPS_MODE_FREE, |
GPS_MODE_AID, |
GPS_MODE_HOLD, |
GPS_MODE_HOME, |
} GpsFlightMode_t; |
s32 North; |
s32 East; |
s32 Bearing; |
s32 Distance; |
} __attribute__((packed)) GPS_Deviation_t; |
GpsFlightMode_t GpsFlightMode = GPS_MODE_FREE; |
GPS_Stick_t GPS_Stick; |
GPS_Parameter_t GPS_Parameter; |
GPS_Deviation_t TargetDeviation; |
// the reference positions |
GPS_Pos_t GPSTargetPosition = {0,0,0, INVALID}; |
GPS_Pos_t GPSTHomePosition = {0,0,0, INVALID}; |
GPS_Pos_t PCGPSTargetPosition = {0,0,0, INVALID}; |
u8 OsdBar = 0; |
u8 OsdDistance = 0; |
// the gps reference positions |
GPS_Pos_t GPSHoldPosition = {0,0,0, INVALID}; |
GPS_Pos_t GPSHomePosition = {0,0,0, INVALID}; |
GPS_Pos_t GPSPCPosition = {0,0,0, INVALID}; |
GPS_Pos_t *pTargetPosition = NULL; |
//------------------------------------------------------------- |
// Update GPSParamter |
void GPS_UpdateParameter(void) |
{ |
static FlightMode_t FlightMode_Old = GPS_FLIGHT_MODE_UNDEF; |
// in case of bad receiving conditions |
if(FC.RC_Quality < 100) |
{ // set fixed parameter |
GPS_Parameter.FlightMode = GPS_FLIGHT_MODE_FREE; |
GPS_Parameter.Gain = (100); |
GPS_Parameter.P = (float) (90); |
GPS_Parameter.I = (float) (90); |
GPS_Parameter.D = (float) (90); |
GPS_Parameter.ACC = (float) (90); |
GPS_Parameter.MinSat = 6; |
GPS_Parameter.StickThreshold = 8; |
} |
else |
{ |
// update paramter from FC |
if (Parameter.NaviGpsModeControl < 50) GPS_Parameter.FlightMode = GPS_FLIGHT_MODE_AID; |
else if(Parameter.NaviGpsModeControl < 180) GPS_Parameter.FlightMode = GPS_FLIGHT_MODE_FREE; |
else GPS_Parameter.FlightMode = GPS_FLIGHT_MODE_HOME; |
GPS_Parameter.Gain = (float) (Parameter.NaviGpsGain); |
GPS_Parameter.P = (float) (Parameter.NaviGpsP); |
GPS_Parameter.I = (float) (Parameter.NaviGpsI); |
GPS_Parameter.D = (float) (Parameter.NaviGpsD); |
GPS_Parameter.ACC = (float) (Parameter.NaviGpsACC); |
GPS_Parameter.MinSat = (u8)Parameter.NaviGpsMinSat; |
GPS_Parameter.StickThreshold = (s8)Parameter.NaviStickThreshold; |
} |
// FlightMode changed? |
if(GPS_Parameter.FlightMode != FlightMode_Old) BeepTime = 100; // beep to indicate that mode has switched |
FlightMode_Old = GPS_Parameter.FlightMode; |
} |
//------------------------------------------------------------- |
// This function defines a good GPS signal condition |
u8 GPS_IsSignalOK(void) |
{ |
static u8 GPSFix = 0; |
if( (GPSData.Status != INVALID) && (GPSData.SatFix == SATFIX_3D) && (GPSData.Flags & FLAG_GPSFIXOK) && ( (GPSData.NumOfSats >= GPS_Parameter.MinSat) || GPSFix) ) |
{ |
GPSFix = 1; // if once GPS_SAT_MIN has been found the signal is also OK of the number of sats drops below that value |
return(1); |
} |
else return(0); |
} |
//------------------------------------------------------------ |
// Checks for manual control action |
u8 GPS_IsManuallyControlled(void) |
{ |
if(abs(FC.StickNick) > GPS_Parameter.StickThreshold || abs(FC.StickRoll) > GPS_Parameter.StickThreshold) return 1; |
else return 0; |
} |
//------------------------------------------------------------ |
// set position to current GPS position |
u8 GPS_SetCurrPosition(GPS_Pos_t * pGPSPos) |
{ |
u8 retval = 0; |
if(pGPSPos == NULL) return(retval); // bad pointer |
if(GPS_IsSignalOK()) |
{ // is GPS signal condition is fine |
pGPSPos->Longitude = GPSData.Longitude; |
pGPSPos->Latitude = GPSData.Latitude; |
pGPSPos->Altitude = GPSData.Altitude; |
pGPSPos->Status = NEWDATA; |
retval = 1; |
} |
else |
{ // bad GPS signal condition |
pGPSPos->Status = INVALID; |
retval = 0; |
} |
return(retval); |
} |
//------------------------------------------------------------ |
// clear position data |
u8 GPS_ClearPosition(GPS_Pos_t * pGPSPos) |
{ |
u8 retval = 0; |
if(pGPSPos == NULL) return(retval); // bad pointer |
else |
{ |
pGPSPos->Longitude = 0; |
pGPSPos->Latitude = 0; |
pGPSPos->Altitude = 0; |
pGPSPos->Status = INVALID; |
retval = 1; |
} |
return (retval); |
} |
//------------------------------------------------------------ |
void GPS_Neutral() |
{ |
GPSStick.Nick = 0; |
GPSStick.Roll = 0; |
GPSStick.Yaw = 0; |
GPS_Stick.Nick = 0; |
GPS_Stick.Roll = 0; |
GPS_Stick.Yaw = 0; |
} |
//------------------------------------------------------------ |
// Init variables or send configuration to GPS module |
void GPS_Init(void) |
{ |
SerialPutString("\r\nGPS init..."); |
UBX_Init(); |
GPS_Neutral(); |
GPS_ClearPosition(&GPSHoldPosition); |
GPS_ClearPosition(&GPSHomePosition); |
GPS_ClearPosition(&GPSPCPosition); |
pTargetPosition = NULL; |
SerialPutString("ok"); |
} |
OsdDistance = 0; |
OsdBar = 0; |
//------------------------------------------------------------ |
// calculates the bearing to target position from its deviation |
s32 DirectionToTarget_N_E(float northdev, float eastdev) |
{ |
s32 bearing; |
bearing = (s32)(atan2(northdev, eastdev) / M_PI_180); |
bearing = (270 - bearing)%360; |
return(bearing); |
} |
GPSParameter.P = 100; |
GPSParameter.I = 100; |
GPSParameter.D = 100; |
GPSParameter.ACC = 100; |
GPSParameter.ModeSwitch = 100; |
GPSParameter.Amplification = 100; |
//------------------------------------------------------------ |
// transform the integer deg into float radians |
inline double RadiansFromGPS(s32 deg) |
{ |
return ((double)deg * 1e-7 * M_PI_180); // 1E-7 because deg is the value in ° * 1E7 |
} |
GpsFlightMode = GPS_MODE_FREE; |
//------------------------------------------------------------ |
// transform the integer deg into float deg |
inline double DegFromGPS(s32 deg) |
{ |
return ((double)deg * 1e-7); // 1E-7 because deg is the value in ° * 1E7 |
} |
//----------------------------------------------------------------------- |
void LogGPSData(void) |
//------------------------------------------------------------ |
// calculate the deviation from the given target position |
u8 GPS_CalculateDeviation( GPS_Pos_t * pTargetPos) |
{ |
static u32 Flushtime = 0; |
static File_t *GPSLogFile = 0; |
s16 i1, i2, i3; |
double temp1, temp2; |
// if given pointer is NULL |
if(pTargetPos == NULL) goto baddata; |
// if data of given target position are invalid |
if(pTargetPos->Status == INVALID) goto baddata; |
// if current GPS Signal is not sufficient |
if(!GPS_IsSignalOK()) goto baddata; |
// The deviation from the target position along north and east direction is |
// simple the lat/lon difference. To convert that angular deviation into an |
// arc length the spherical projection has to be considered. |
// The mean earth radius is 6371km. Therfore the arc length per latitude degree |
// is always 6371km * 2 * Pi / 360deg = 111.2 km/deg. |
// The arc length per longitude degree depends on the correspondig latitude and |
// is 111.2km * cos(latitude). |
if((GPSData.Status != INVALID) && (GPSData.SatFix == SATFIX_3D)) |
{ |
// if logfile is not opened |
if(!GPSLogFile) |
{ |
GPSLogFile = fopen_("/LOG/GPSLOG.TXT", 'a'); |
if(GPSLogFile) SerialPutString("Opening GPSLog\r\n"); |
Flushtime = SetDelay(5000L); // every 5 seconds |
// calculate the shortest longitude deviation from target |
temp1 = DegFromGPS(GPSData.Longitude) - DegFromGPS(pTargetPos->Longitude); |
// outside an angular difference of -180 deg ... +180 deg it shorter to go the other way around |
// In our application we wont fly more than 20.000 km but along the date line this is important. |
if(temp1 > 180.0f) temp1 -= 360.0f; |
else if (temp1 < -180.0f) temp1 += 360.0f; |
// calculate latitude deviation from target |
// this is allways within -180 deg ... 180 deg */ |
temp1 *= cos(RadiansFromGPS(pTargetPos->Latitude)); |
temp2 = DegFromGPS(GPSData.Latitude) - DegFromGPS(pTargetPos->Latitude); |
// deviation from target position in cm |
TargetDeviation.North = (s32)(11119492.7 * temp2); |
TargetDeviation.East = (s32)(11119492.7 * temp1); |
} |
// if logfile |
if(GPSLogFile) |
{ |
sprintf(logtext,"%02d/%02d/%04d %02d:%02d:%02d.%03d\t", SystemTime.Month, SystemTime.Day, SystemTime.Year, SystemTime.Hour, SystemTime.Min, SystemTime.Sec, SystemTime.mSec ); |
fputs_(logtext, GPSLogFile); |
i1 = (s16)(GPSData.Longitude/10000000L); |
i2 = abs((s16)((GPSData.Longitude%10000000L)/10000L)); |
i3 = abs((s16)(((GPSData.Longitude%10000000L)%10000L)/10L)); |
sprintf(logtext,"%03d.%.3d%.3d\t",i1, i2, i3); |
fputs_(logtext, GPSLogFile); |
i1 = (s16)(GPSData.Latitude/10000000L); |
i2 = abs((s16)((GPSData.Latitude%10000000L)/10000L)); |
i3 = abs((s16)(((GPSData.Latitude%10000000L)%10000L)/10L)); |
sprintf(logtext,"%03d.%.3d%.3d\t",i1, i2, i3); |
fputs_(logtext, GPSLogFile); |
i1 = (s16)(GPSData.Altitude/1000L); |
i2 = abs((s16)(GPSData.Altitude%1000L)); |
sprintf(logtext,"%d.%.3d\r\n",i1, i2); |
fputs_(logtext, GPSLogFile); |
if(CheckDelay(Flushtime)) |
{ |
fflush_(GPSLogFile); |
Flushtime = SetDelay(5000L); // every 5 seconds |
} |
} |
} |
// If the position deviation is small enough to neglect the earth curvature |
// (this is for our application always fulfilled) the distance to target |
// can be calculated by the pythagoras of north and east deviation. |
TargetDeviation.Distance = (s32)(11119492.7f * hypot(temp1, temp2)); |
if (TargetDeviation.Distance == 0L) TargetDeviation.Bearing = 0L; |
else TargetDeviation.Bearing = DirectionToTarget_N_E(temp2, temp1); |
return(1); |
baddata: |
TargetDeviation.North = 0L; |
TargetDeviation.East = 0L; |
TargetDeviation.Distance = 0L; |
TargetDeviation.Bearing = 0L; |
return(0); |
} |
//------------------------------------------------------------ |
u8 Navigation(void) |
void GPS_Navigation(void) |
{ |
static GpsFlightMode_t oldGpsFlightMode = GPS_MODE_FREE; |
static u32 beep_rythm; |
static u32 GPSDataTimeout = 0; |
beep_rythm++; |
// update paramter |
GPSParameter.ModeSwitch = Parameter.User1; |
GPSParameter.Amplification = (float) Parameter.User2 / (100.0); |
GPSParameter.P = (float) Parameter.User3; |
GPSParameter.I = (float) Parameter.User4; |
GPSParameter.D = (float) Parameter.User5; |
GPSParameter.ACC = (float) Parameter.User6; |
// in case of bad receiving conditions |
if(FC.RC_Quality < 100) |
{ // set fixed parameter |
GPSParameter.ModeSwitch = 0; |
GPSParameter.Amplification = 100; |
GPSParameter.P = (float) 90; |
GPSParameter.I = (float) 90; |
GPSParameter.D = (float) 90; |
GPSParameter.ACC = (float) 90; |
} |
// update GPS Parameter from FC-Data via SPI interface |
GPS_UpdateParameter(); |
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
//+ GPS-Mode Selection |
//+ Check for new data from GPS-receiver |
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
oldGpsFlightMode = GpsFlightMode; |
if(GPSParameter.ModeSwitch < 50) GpsFlightMode = GPS_MODE_AID; |
else if(GPSParameter.ModeSwitch < 180) GpsFlightMode = GPS_MODE_FREE; |
else GpsFlightMode = GPS_MODE_HOME; |
// Mode changed? |
if(GpsFlightMode != oldGpsFlightMode) BeepTime = 100; // indicate that mode has switched |
// look for new data from GPS |
switch(GPSData.Status) |
{ |
case INVALID: // no gps data available |
// do nothing |
break; |
case NEWDATA: // handle new gps data |
// wait maximum of 3 times the normal data update time |
GPSDataTimeout = SetDelay(3*GPSData.UpdateTime); |
LogGPSData(); // write gps position to file |
// set debug values |
DebugOut.Analog[21] = (s16)GPSData.Speed_North; |
DebugOut.Analog[22] = (s16)GPSData.Speed_East; |
DebugOut.Analog[31] = GPSData.NumOfSats; |
// wait maximum of 3 times the normal data update time before data timemout |
GPSDataTimeout = SetDelay(3* GPS_UPDATETIME_MS); |
beep_rythm++; |
// debug |
DebugOut.Analog[21] = (u16)GPSData.Speed_North; |
DebugOut.Analog[22] = (u16)GPSData.Speed_East; |
DebugOut.Analog[31] = (u16)GPSData.NumOfSats; |
// If GPS signal condition is sufficient for a reliable position measurement |
if(GPS_IsSignalOK()) |
{ |
// if calibration on fc is active |
if(FC.MKFlags & MKFLAG_CALIBRATE) |
{ // set home position to current position |
if (GPS_SetCurrPosition(&GPSHomePosition)) BeepTime = 700; |
} |
// update home position from serial data |
#define MAX_TARGET_DISTANCE 30000 // 300m |
if(GPSPCPosition.Status == NEWDATA) |
{ |
// calculate distance to transmitted position |
if(GPS_CalculateDeviation(&GPSPCPosition)) |
{ // if distance is within the limit |
if(TargetDeviation.Distance <= MAX_TARGET_DISTANCE) |
{ // update home position |
GPSHomePosition.Status = INVALID; |
GPSHomePosition.Latitude = GPSPCPosition.Latitude; |
GPSHomePosition.Longitude = GPSPCPosition.Longitude; |
GPSHomePosition.Altitude = GPSPCPosition.Altitude; |
GPSHomePosition.Status = NEWDATA; |
GPSPCPosition.Status = PROCESSED; |
BeepTime = 700; |
} |
} |
} |
// check for current flight mode |
switch(GPS_Parameter.FlightMode) |
{ |
case GPS_FLIGHT_MODE_FREE: |
GPS_SetCurrPosition(&GPSHoldPosition); |
pTargetPosition = NULL; |
break; |
case GPS_FLIGHT_MODE_AID: |
if(GPS_IsManuallyControlled()) |
{ |
GPS_SetCurrPosition(&GPSHoldPosition); |
pTargetPosition = NULL; |
} |
else |
{ |
pTargetPosition = &GPSHoldPosition; |
} |
break; |
case GPS_FLIGHT_MODE_HOME: |
if(GPSHomePosition.Status == INVALID) |
{ |
pTargetPosition = &GPSHoldPosition; // fall back to hold mode if home position is not available |
BeepTime = 255; |
} |
else // home position is valid |
{ |
pTargetPosition = &GPSHomePosition; |
} |
break; |
case GPS_FLIGHT_MODE_UNDEF: |
default: |
// no target position |
GPS_SetCurrPosition(&GPSHoldPosition); |
pTargetPosition = NULL; |
break; |
} |
// calculate deviation from target position |
if(GPS_CalculateDeviation(pTargetPosition)) |
{ |
// put your control loop algorithm here to update the members of GPS_Stick |
// using the the GPS_Parameter and TargetDeviation. |
GPS_Neutral(); |
} |
}// eof if GPSSignalOK |
else // GPSSignal not OK |
{ |
GPS_Neutral(); |
// beep if signal is not sufficient |
if(!(GPSData.Flags & FLAG_GPSFIXOK) && !(beep_rythm % 5)) BeepTime = 100; |
else if (GPSData.NumOfSats < GPS_Parameter.MinSat && !(beep_rythm % 5)) BeepTime = 10; |
} |
GPSData.Status = PROCESSED; // mark as processed |
break; |
case PROCESSED: |
case PROCESSED: // the current data have been allready processed |
// if no new data are available within the timeout switch to invalid state. |
if(CheckDelay(GPSDataTimeout)) GPSData.Status = INVALID; |
break; |
} |
if((GPSData.Status != INVALID)) // there are valid data from the GPS |
{ |
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
//+ Fix okay and enough sats |
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
if((GPSData.Flags & FLAG_GPSFIXOK) && (GPSData.NumOfSats >= GPS_SAT_MIN)) |
{ |
// here is a good place to put your GPS code... |
GPSStick.Nick = 0; // do nothing |
GPSStick.Roll = 0; // do nothing |
} |
else |
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
//+ No Fix or not enough sats |
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
{ |
GPS_Neutral(); // disable gps control |
/* |
if(!(GPSData.Flags & FLAG_GPSFIXOK) && !(beep_rythm % 5)) BeepTime = 100; |
else if (GPSData.NumOfSats < GPS_SAT_MIN && !(beep_rythm % 5)) BeepTime = 10;*/ |
} |
} |
else // GPS Data are invalid |
{ |
GPS_Neutral(); // disable gps control |
} |
DebugOut.Analog[29] = GPSStick.Nick; |
DebugOut.Analog[30] = GPSStick.Roll; |
return (0); |
return; |
} |
/branches/V0.1 killagreg/GPS.h |
---|
1,11 → 1,8 |
#ifndef __GPS_H |
#define __GPS_H |
#include "91x_lib.h" |
#include "GPSUart.h" |
#include "ubx.h" |
#define GPS_SAT_MIN 6 |
typedef struct |
{ |
s32 Longitude; |
12,41 → 9,27 |
s32 Latitude; |
s32 Altitude; |
Status_t Status; |
} GPS_Pos_t; |
} __attribute__((packed)) GPS_Pos_t; |
extern GPS_Pos_t GPSTargetPosition; |
extern GPS_Pos_t GPSTHomePosition; |
extern GPS_Pos_t PCGPSTargetPosition; |
extern GPS_Pos_t GPSPCPosition; |
extern GPS_Pos_t GPSHomePosition; |
extern GPS_Pos_t * pTargetPosition; |
typedef struct |
{ |
float Amplification; |
float P; |
float I; |
float D; |
float ACC; |
s32 ModeSwitch; |
} __attribute__((packed)) GPSParameter_t; |
extern GPSParameter_t GPSParameter; |
extern u8 OsdBar; |
extern s16 OsdDistance; |
typedef struct |
{ |
s16 Nick; |
s16 Roll; |
s16 Yaw; |
} __attribute__((packed)) GPSStick_t; |
} __attribute__((packed)) GPS_Stick_t; |
extern GPSStick_t GPSStick; |
extern GPS_Stick_t GPS_Stick; |
extern void GPS_Navigation(void); |
extern void GPS_Init(void); |
extern u8 OsdBar; |
extern u8 OsdDistance; |
extern u8 Navigation(void); |
extern void GPS_Init(void); |
#endif //__GPS_H |
#endif |
/branches/V0.1 killagreg/Navi-Ctrl.Uv2 |
---|
11,7 → 11,6 |
Group (USB-Lib) |
File 1,1,<.\main.c><main.c> |
File 1,1,<.\uart.c><uart.c> |
File 1,1,<.\interrupt.c><interrupt.c> |
File 1,1,<.\ramfunc.c><ramfunc.c> |
File 1,1,<.\menu.c><menu.c> |
20,7 → 19,6 |
File 1,1,<.\spi_slave.c><spi_slave.c> |
File 1,1,<.\i2c.c><i2c.c> |
File 1,1,<.\GPS.c><GPS.c> |
File 1,1,<.\GPSUart.c><GPSUart.c> |
File 1,1,<.\usb.c><usb.c> |
File 1,1,<.\fat16.c><fat16.c> |
File 1,1,<.\sdc.c><sdc.c> |
33,9 → 31,12 |
File 1,1,<.\usb_pwr.c><usb_pwr.c> |
File 1,1,<.\led.c><led.c> |
File 1,1,<.\crc16.c><crc16.c> |
File 1,1,<.\ubx.c><ubx.c> |
File 1,1,<.\uart0.c><uart0.c> |
File 1,1,<.\uart1.c><uart1.c> |
File 1,1,<.\kml.c><kml.c> |
File 2,5,<.\ramfunc.h><ramfunc.h> |
File 2,5,<.\main.h><main.h> |
File 2,5,<.\uart.h><uart.h> |
File 2,5,<.\menu.h><menu.h> |
File 2,5,<.\printf_P.h><printf_P.h> |
File 2,5,<.\settings.h><settings.h> |
42,7 → 43,6 |
File 2,5,<.\timer.h><timer.h> |
File 2,5,<.\usb.h><usb.h> |
File 2,5,<.\spi_slave.h><spi_slave.h> |
File 2,5,<.\GPSUart.h><GPSUart.h> |
File 2,5,<.\i2c.h><i2c.h> |
File 2,5,<.\sdc.h><sdc.h> |
File 2,5,<.\ssc.h><ssc.h> |
51,6 → 51,11 |
File 2,5,<.\libstr91x\include\91x_lib.h><91x_lib.h> |
File 2,5,<.\led.h><led.h> |
File 2,5,<.\crc16.h><crc16.h> |
File 2,5,<.\ubx.h><ubx.h> |
File 2,5,<.\uart0.h><uart0.h> |
File 2,5,<.\uart1.h><uart1.h> |
File 2,5,<.\kml_header.h><kml_header.h> |
File 2,5,<.\kml.h><kml.h> |
File 3,2,<.\startup912.s><startup912.s> |
File 4,1,<.\libstr91x\src\91x_scu.c><91x_scu.c> |
File 4,1,<.\libstr91x\src\91x_gpio.c><91x_gpio.c> |
/branches/V0.1 killagreg/fat16.c |
---|
59,7 → 59,7 |
#include "timer.h" |
#include "fat16.h" |
#include "sdc.h" |
#include "uart.h" |
#include "uart1.h" |
//________________________________________________________________________________________________________________________________________ |
132,24 → 132,32 |
*/ |
// Partition Types: |
#define PART_TYPE_UNKNOWN 0x00 |
#define PART_TYPE_FAT12 0x01 |
#define PART_TYPE_XENIX 0x02 |
#define PART_TYPE_DOSFAT16 0x04 |
#define PART_TYPE_EXTDOS 0x05 |
#define PART_TYPE_FAT16 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_ONTRACK 0x33 |
#define PART_TYPE_NOVELL 0x40 |
#define PART_TYPE_PCIX 0x4B |
#define PART_TYPE_PHOENIXSAVE 0xA0 |
#define PART_TYPE_CPM 0xDB |
#define PART_TYPE_DBFS 0xE0 |
#define PART_TYPE_BBT 0xFF |
#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 |
/* |
185,7 → 193,7 |
typedef struct |
{ |
u8 JumpCode[3]; // Jump Code + NOP |
u8 OEMName[8]; // OEM Name |
s8 OEMName[8]; // OEM Name |
u16 BytesPerSector; // Bytes Per Sector |
u8 SectorsPerCluster; // Sectors Per Cluster |
u16 ReservedSectors; // Reserved Sectors |
201,8 → 209,8 |
u16 DriveNo; // Logical Drive Number of Partition |
u8 ExtendedSig; // Extended Signature (0x29) |
u32 SerialNo; // Serial Number of the Partition |
u8 VolumeName[11]; // Volume Name of the Partititon |
u8 FATName[8]; // FAT Name (FAT16) |
s8 VolumeName[11]; // Volume Name of the Partititon |
s8 FATName[8]; // FAT Name (FAT16) |
u8 ExecutableCode[446]; // 446 bytes for machine start code |
u16 ExecutableMarker; // Executable Marker (0x55 0xAA) |
} __attribute__((packed)) VBR_Entry_t; |
219,7 → 227,7 |
*/ |
typedef struct |
{ |
u8 Name[8]; // 8 bytes name, padded with spaces. |
s8 Name[8]; // 8 bytes name, padded with spaces. |
u8 Extension[3]; // 3 bytes extension, padded with spaces. |
u8 Attribute; // attribute of the directory entry (unused,archive,read-only,system,directory,volume) |
u8 Reserved[10]; // reserved bytes within the directory entry. |
344,34 → 352,34 |
} |
/****************************************************************************************************************************************/ |
/* Function: UnlockFilePointer(File_t *); */ |
/* Function: UnlockFilePointer(file_t *); */ |
/* */ |
/* Description: This function trys to unlock a file pointer. */ |
/* */ |
/* Returnvalue: Returns 1 if file pointer was freed else 0. */ |
/****************************************************************************************************************************************/ |
u8 UnlockFilePointer(File_t * File) |
u8 UnlockFilePointer(File_t * file) |
{ |
u8 cnt; |
if(File == 0) return(0); |
if(file == NULL) return(0); |
for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++) |
{ |
if(&FilePointer[cnt] == File) // filepointer to be freed found? |
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 = 0; |
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); |
} |
} |
379,17 → 387,17 |
} |
/****************************************************************************************************************************************/ |
/* Function: SeperateDirName(u8*, u8*, u8*); */ |
/* Function: SeperateDirName(s8*, s8*); */ |
/* */ |
/* 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 0 on error ot pointer to subpath */ |
/* Returnvalue: Return 0 on error or pointer to subpath */ |
/****************************************************************************************************************************************/ |
u8* SeperateDirName(const u8 *filepath, u8 *dirname) |
s8* SeperateDirName(const s8 *filepath, s8 *dirname) |
{ |
u8* subpath = 0; |
s8* subpath = 0; |
u8 readpointer = 0; |
u8 writepointer = 0; |
401,12 → 409,13 |
{ |
if(((filepath[readpointer] == 0) || (filepath[readpointer] == '/'))) // if '/' found or end of filepath reached |
{ |
subpath = (u8*)&filepath[readpointer]; // store the position of the first "/" found after the beginning of the filenpath |
subpath = (s8*)&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. |
417,12 → 426,12 |
if(writepointer >= 11) return 0; // dirname to long |
if(filepath[readpointer] == '.') // seperating dirname and extension. |
{ |
if(writepointer<8) |
if(writepointer <= 8) |
{ |
readpointer++; // next character in filename |
writepointer = 8; // jump to start of extension |
readpointer++; // next character in filename |
writepointer = 8; // jump to start of extension |
} |
else return (0); // dirbasename to long |
else return (0); // dirbasename to long |
} |
else |
{ |
508,12 → 517,14 |
u8 Fat16_Init(void) |
{ |
u8 cnt = 0; |
u32 PartitionFirstSector; |
u32 partitionfirstsector; |
VBR_Entry_t *VBR; |
MBR_Entry_t *MBR; |
File_t *File; |
u8 result; |
File_t *file; |
u8 result = 0; |
SerialPutString("\r\n FAT16 init..."); |
Partition.IsValid = 0; |
// declare the filepointers as unused. |
522,37 → 533,34 |
FilePointer[cnt].State = FSTATE_UNUSED; |
} |
// set current file pinter to first position in list |
File = &FilePointer[0]; |
file = &FilePointer[0]; |
// try to initialise the sd-card. |
cnt = 0; |
while(SD_SUCCESS != SDC_Init()) |
if(SD_SUCCESS != SDC_Init()) |
{ |
if(cnt > 3) |
{ |
SerialPutString("SD-Card could not be initialized.\r\n"); |
result = 1; |
goto end; |
} |
cnt++; |
SerialPutString("SD-Card could not be initialized."); |
result = 1; |
goto end; |
} |
// SD-Card is initialized successfully |
if(SD_SUCCESS != SDC_GetSector((u32)MBR_SECTOR,File->Cache)) // Read the MasterBootRecord |
if(SD_SUCCESS != SDC_GetSector((u32)MBR_SECTOR,file->Cache)) // Read the MasterBootRecord |
{ |
SerialPutString("Error reading the MBR.\r\n"); |
SerialPutString("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) |
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; |
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 |
if(SD_SUCCESS != SDC_GetSector(partitionfirstsector,file->Cache)) // Read the volume boot record |
{ |
SerialPutString("Error reading the VBR.\r\n"); |
SerialPutString("Error reading the VBR."); |
result = 3; |
goto end; |
} |
559,13 → 567,13 |
} |
else // maybe the medium has no partition assuming sector 0 is the vbr |
{ |
PartitionFirstSector = 0; |
partitionfirstsector = 0; |
} |
VBR = (VBR_Entry_t *) File->Cache; // Enter the VBR using the structure VBR_Entry_t. |
VBR = (VBR_Entry_t *) file->Cache; // Enter the VBR using the structure VBR_Entry_t. |
if(VBR->BytesPerSector != BYTES_PER_SECTOR) |
{ |
SerialPutString("VBR: Sector size not supported.\r\n"); |
SerialPutString("VBR: Sector size not supported."); |
result = 4; |
goto end; |
} |
577,7 → 585,7 |
/* Calculate the sectorpositon of the FAT, the Rootdirectory and the first Datacluster. */ |
// Calculate the position of the FileAllocationTable: |
// Start + # of Reserved Sectors |
Partition.FirstFatSector = (u32)(PartitionFirstSector + (u32)(VBR->ReservedSectors)); |
Partition.FirstFatSector = (u32)(partitionfirstsector + (u32)(VBR->ReservedSectors)); |
// Calculate the position of the Rootdirectory: |
// Start + # of Reserved Sectors + (# of Sectors Per FAT * # of FAT Copies) |
Partition.FirstRootDirSector = Partition.FirstFatSector + (u32)((u32)Partition.SectorsPerFat*(u32)Partition.FatCopies); |
587,7 → 595,7 |
// Calculate the last data sector |
if(VBR->NoSectors == 0) |
{ |
SerialPutString("VBR: Bad number of sectors.\r\n"); |
SerialPutString("VBR: Bad number of sectors."); |
result = 5; |
goto end; |
} |
595,7 → 603,7 |
// 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'))) |
{ |
SerialPutString("VBR: Partition ist not FAT16 type.\r\n"); |
SerialPutString("VBR: Partition ist not FAT16 type."); |
result = 6; |
goto end; |
} |
603,6 → 611,7 |
result = 0; |
end: |
if(result != 0) Fat16_Deinit(); |
else SerialPutString("ok"); |
return(result); |
} |
609,24 → 618,24 |
/****************************************************************************************************************************************/ |
/* Function: ClearCurrCluster(File_t file); */ |
/* Function: ClearCurrCluster(File_t*); */ |
/* */ |
/* Description: This function fills the current cluster with 0. */ |
/* */ |
/* Returnvalue: The function returns 1 on success else 0. */ |
/****************************************************************************************************************************************/ |
u8 ClearCurrCluster(File_t * File) |
u8 ClearCurrCluster(File_t * file) |
{ |
u8 retvalue = 1; |
u32 i; |
if((!Partition.IsValid) || (File == 0)) return(0); |
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 < 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)) |
file->SectorInCache = file->FirstSectorOfCurrCluster + i; |
if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache)) |
{ |
Fat16_Deinit(); |
retvalue = 0; |
636,24 → 645,24 |
} |
/*****************************************************************************************************************************************/ |
/* Function: GetNextCluster(File_t file); */ |
/* 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. */ |
/*****************************************************************************************************************************************/ |
u16 GetNextCluster(File_t * File) |
u16 GetNextCluster(File_t * file) |
{ |
u16 cluster = 0; |
u32 fat_byte_offset, sector, byte; |
Fat16Entry_t * Fat; |
Fat16Entry_t * fat; |
if((!Partition.IsValid) || (File == 0)) return(cluster); |
if((!Partition.IsValid) || (file == NULL)) return(cluster); |
// if sector is within the data area |
if((Partition.FirstDataSector <= File->FirstSectorOfCurrCluster)&& (File->FirstSectorOfCurrCluster <= Partition.LastDataSector)) |
if((Partition.FirstDataSector <= file->FirstSectorOfCurrCluster)&& (file->FirstSectorOfCurrCluster <= Partition.LastDataSector)) |
{ |
// determine current file cluster |
cluster = SectorToFat16Cluster(File->FirstSectorOfCurrCluster); |
cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster); |
// calculate byte offset in the fat for corresponding entry |
fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster |
// calculate the sector that contains the current cluster within the fat |
661,10 → 670,10 |
// 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) |
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 |
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); |
671,8 → 680,8 |
} |
} |
// read the next cluster from cache |
Fat = (Fat16Entry_t *)(&(File->Cache[byte])); |
cluster = Fat->NextCluster; |
fat = (Fat16Entry_t *)(&(file->Cache[byte])); |
cluster = fat->NextCluster; |
// if last cluster fat entry |
if(FAT16_CLUSTER_LAST_MIN <= cluster) |
{ |
680,9 → 689,9 |
} |
else |
{ |
File->FirstSectorOfCurrCluster = Fat16ClusterToSector(cluster); |
File->SectorOfCurrCluster = 0; |
File->ByteOfCurrSector = 0; |
file->FirstSectorOfCurrCluster = Fat16ClusterToSector(cluster); |
file->SectorOfCurrCluster = 0; |
file->ByteOfCurrSector = 0; |
} |
} |
return(cluster); |
690,21 → 699,21 |
/****************************************************************************************************************************************/ |
/* Function: FindNextFreeCluster(File_t *file); */ |
/* 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. */ |
/****************************************************************************************************************************************/ |
u16 FindNextFreeCluster(File_t *File) |
u16 FindNextFreeCluster(File_t *file) |
{ |
u32 fat_sector; // current sector within the fat relative to the first sector of the fat. |
u32 curr_sector; // current sector |
u16 fat_entry; // index to an fatentry within the actual sector (256 fatentries are possible within one sector). |
u16 free_cluster = 0; // next free cluster number. |
Fat16Entry_t * Fat; |
Fat16Entry_t * fat; |
if((!Partition.IsValid) || (File == 0)) return(0); |
if((!Partition.IsValid) || (file == NULL)) return(0); |
// start searching for an empty cluster at the beginning of the fat. |
fat_sector = 0; |
711,21 → 720,21 |
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. |
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 |
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!! |
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. |
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); |
742,18 → 751,18 |
/****************************************************************************************************************************************************/ |
/* Function: s16 fseek_(File *, s32 *, u8) */ |
/* Function: s16 fseek_(File_t *, s32 *, u8) */ |
/* */ |
/* 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 */ |
/****************************************************************************************************************************************************/ |
s16 fseek_(File_t *File, s32 offset, s16 origin) |
s16 fseek_(File_t *file, s32 offset, s16 origin) |
{ |
s32 fposition = 0; |
s16 retvalue = 1; |
if((!Partition.IsValid) || (File == 0)) return(0); |
if((!Partition.IsValid) || (file == NULL)) return(0); |
switch(origin) |
{ |
case SEEK_SET: // Fileposition relative to the beginning of the file. |
760,53 → 769,110 |
fposition = 0; |
break; |
case SEEK_END: // Fileposition relative to the end of the file. |
fposition = (s32)File->Size; |
fposition = (s32)file->Size; |
break; |
case SEEK_CUR: // Fileposition relative to the current position of the file. |
default: |
fposition = File->Position; |
fposition = file->Position; |
break; |
} |
fposition += offset; |
if((fposition >= 0) && (fposition <= (s32)File->Size)) // is the pointer still within the file? |
if((fposition >= 0) && (fposition <= (s32)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; |
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 |
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->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. |
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. |
if(GetNextCluster(file)) // Sets the clusterpointer of the file to the next datacluster. |
{ |
File->SectorOfCurrCluster = 0; |
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 |
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; |
if(file->Position == fposition) retvalue = 0; |
return(retvalue); |
} |
/****************************************************************************************************************************************/ |
/* Function: u16 DeleteClusterChain(File *file); */ |
/* */ |
/* Description: This function trances along a cluster chain in the fat and frees all clusters visited. */ |
/* */ |
/****************************************************************************************************************************************/ |
u8 DeleteClusterChain(u16 StartCluster) |
{ |
u16 cluster; |
u32 fat_byte_offset, sector, byte; |
Fat16Entry_t * fat; |
u8 buffer[BYTES_PER_SECTOR]; |
u32 sector_in_buffer = 0; |
u8 repeat = 0; |
if(!Partition.IsValid) return 0; |
cluster = StartCluster; // init chain trace |
// calculate byte offset in the fat for corresponding entry |
fat_byte_offset = ((u32)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 = ((u32)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: u16 AppendCluster(File *file); */ |
/* */ |
/* Description: This function looks in the fat to find the next free cluster and appends it to the file. */ |
813,54 → 879,54 |
/* */ |
/* Returnvalue: The function returns the appened cluster number or 0 of no cluster was appended. */ |
/****************************************************************************************************************************************/ |
u16 AppendCluster(File_t *File) |
u16 AppendCluster(File_t *file) |
{ |
u16 last_cluster, new_cluster = 0; |
u32 fat_byte_offset, sector, byte; |
Fat16Entry_t * Fat; |
Fat16Entry_t * fat; |
if((!Partition.IsValid) || (File == 0)) return(new_cluster); |
if((!Partition.IsValid) || (file == NULL)) return(new_cluster); |
new_cluster = FindNextFreeCluster(File); // the next free cluster found on the disk. |
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 |
fseek_(file, 0, SEEK_END); // jump to the end of the file |
last_cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster); // determine current file cluster |
fat_byte_offset = ((u32)last_cluster)<<1; |
sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR); |
byte = fat_byte_offset % BYTES_PER_SECTOR; |
if(File->SectorInCache != 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 |
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. |
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; |
file->FirstSectorOfCurrCluster = Fat16ClusterToSector(new_cluster); |
file->SectorOfCurrCluster = 0; |
file->ByteOfCurrSector = 0; |
} |
return(new_cluster); |
} |
/****************************************************************************************************************************************************/ |
/* Function: DirectoryEntryExist(u8 *, u8, u8, File_t *) */ |
/* Function: DirectoryEntryExist(s8 *, u8, u8, 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. */ |
/****************************************************************************************************************************************************/ |
u8 DirectoryEntryExist(u8 *dirname, u8 attribfilter, u8 attribmask, File_t *File) |
u8 DirectoryEntryExist(s8 *dirname, u8 attribfilter, u8 attribmask, File_t *file) |
{ |
u32 dir_sector, max_dir_sector, curr_sector; |
u16 dir_entry = 0; |
868,45 → 934,45 |
u16 end_of_directory_not_reached = 0; |
u8 i = 0; |
u8 direntry_exist = 0; |
DirEntry_t * Dir; |
DirEntry_t * dir; |
// if incomming pointers are useless return immediatly |
if((!Partition.IsValid) || (File == 0) || (dirname == 0)) return(direntry_exist); |
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; |
file->FirstSectorOfFirstCluster = 0; |
// no current directory exist therefore assume searching in the root |
if(File->DirectorySector == 0) |
if(file->DirectorySector == 0) |
{ |
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR; |
File->FirstSectorOfFirstCluster = Partition.FirstRootDirSector; |
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)) |
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)) |
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) |
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. |
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(Dir[File->DirectoryIndex].Name[0]) // check if current directory exist |
dir = (DirEntry_t *)file->Cache; // set pointer to directory |
switch((u8)dir[file->DirectoryIndex].Name[0]) // check if current directory exist |
{ |
case SLOT_EMPTY: |
case SLOT_DELETED: |
915,19 → 981,19 |
return (direntry_exist); |
break; |
default: // and is a real directory |
if((Dir[File->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY) |
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); |
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; |
file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster; |
file->SectorOfCurrCluster = 0; |
file->ByteOfCurrSector = 0; |
do // loop over all data clusters of the current directory entry |
{ |
934,18 → 1000,18 |
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 |
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 |
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(Dir[dir_entry].Name[0]) |
switch((u8)dir[dir_entry].Name[0]) |
{ |
case SLOT_EMPTY: |
case SLOT_DELETED: |
953,20 → 1019,20 |
break; |
default: |
// if existing check attributes before names are compared will safe performance |
if ((Dir[dir_entry].Attribute & attribmask) != attribfilter) break; // attribute must match |
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++; |
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; |
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 |
976,9 → 1042,9 |
}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)) |
if(!direntry_exist && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster)) |
{ |
end_of_directory_not_reached = GetNextCluster(File); // updates 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); |
986,7 → 1052,7 |
/****************************************************************************************************************************************/ |
/* Function: CreateDirectoryEntry(u8 *, u16, File_t *) */ |
/* Function: CreateDirectoryEntry(s8 *, u16, 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. */ |
993,53 → 1059,53 |
/* */ |
/* Returnvalue: Return 0 on error */ |
/****************************************************************************************************************************************/ |
u8 CreateDirectoryEntry(u8 *dirname, u8 attrib, File_t *File) |
u8 CreateDirectoryEntry(s8 *dirname, u8 attrib, File_t *file) |
{ |
u32 dir_sector, max_dir_sector, curr_sector; |
u16 dir_entry = 0; |
u16 SubDirCluster, DirCluster = 0; |
u16 subdircluster, dircluster = 0; |
u16 end_of_directory_not_reached = 0; |
u8 i = 0; |
u8 retvalue = 0; |
DirEntry_t *Dir; |
DirEntry_t *dir; |
if((!Partition.IsValid) || (File == 0) || (dirname == 0)) return (retvalue); |
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; |
file->FirstSectorOfFirstCluster = 0; |
// no current directory exist therefore assume creating in the root |
if(File->DirectorySector == 0) |
if(file->DirectorySector == 0) |
{ |
max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR; |
DirCluster = 0; |
File->FirstSectorOfFirstCluster = Partition.FirstRootDirSector; |
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)) |
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)) |
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) |
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. |
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(Dir[File->DirectoryIndex].Name[0]) // check if current directory exist |
dir = (DirEntry_t *)file->Cache; // set pointer to directory |
switch((u8)dir[file->DirectoryIndex].Name[0]) // check if current directory exist |
{ |
case SLOT_EMPTY: |
case SLOT_DELETED: |
1046,83 → 1112,83 |
return (retvalue); |
break; |
default: // and is a real directory |
if((Dir[File->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY) |
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); |
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) |
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; |
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. |
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 |
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((Dir[dir_entry].Name[0] == SLOT_EMPTY) || (Dir[dir_entry].Name[0] == SLOT_DELETED)) |
if(((u8)dir[dir_entry].Name[0] == SLOT_EMPTY) || ((u8)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 |
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; |
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. |
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; |
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; |
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. |
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); |
1137,9 → 1203,9 |
}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)) |
if(!retvalue && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster)) |
{ |
end_of_directory_not_reached = GetNextCluster(File); // updates 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. |
1151,7 → 1217,7 |
} |
/********************************************************************************************************************************************/ |
/* Function: FileExist(const u8* filename, u8 attribfilter, u8 attribmask, File_t *File); */ |
/* Function: FileExist(const s8* filename, u8 attribfilter, u8 attribmask, File_t *file); */ |
/* */ |
/* Description: This function looks for the specified filemincluding its subdirectories beginning */ |
/* in the rootdirectory of the drive. If the file is found the Filepointer properties are */ |
1159,23 → 1225,24 |
/* */ |
/* Returnvalue: 1 if file is found else 0. */ |
/********************************************************************************************************************************************/ |
u8 FileExist(const u8* filename, const u8 attribfilter, const u8 attribmask, File_t *File) |
u8 FileExist(const s8* filename, const u8 attribfilter, const u8 attribmask, File_t *file) |
{ |
u8 *path = 0, *subpath = 0; |
s8* path = 0; |
s8* subpath = 0; |
u8 af, am, file_exist = 0; |
u8 dirname[11]; |
s8 dirname[12]; |
// if incomming pointers are useless return immediatly |
if ((filename == 0) || (File == 0) || (!Partition.IsValid)) return 0; |
if ((filename == 0) || (file == NULL) || (!Partition.IsValid)) return 0; |
// trace along the filepath |
path = (u8*)filename; // start a the beginning of the filename string |
File->DirectorySector = 0; // start at RootDirectory with file search |
File->DirectoryIndex = 0; |
path = (s8*)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 |
if((subpath = SeperateDirName(path, dirname))) |
if(subpath != 0) |
{ |
if(*subpath == 0) |
{ // empty subpath indicates last element of dir chain |
1187,7 → 1254,7 |
af = ATTR_SUBDIRECTORY; |
am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL; |
} |
if(!DirectoryEntryExist(dirname, af, am, File)) |
if(!DirectoryEntryExist(dirname, af, am, file)) |
{ |
return (file_exist); // subdirectory does not exist |
} |
1211,7 → 1278,7 |
/********************************************************************************************************************************************/ |
/* Function: FileCreate(const u8* filename, u8 attrib, File_t *File); */ |
/* 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 */ |
1219,24 → 1286,24 |
/* */ |
/* Returnvalue: 1 if file was created else 0. */ |
/********************************************************************************************************************************************/ |
u8 FileCreate(const u8* filename, const u8 attrib, File_t *File) |
u8 FileCreate(const s8* filename, const u8 attrib, File_t *file) |
{ |
u8 *path = 0; |
u8 *subpath = 0; |
s8 *path = 0; |
s8 *subpath = 0; |
u8 af, am, file_created = 0; |
u8 dirname[11]; |
s8 dirname[12]; |
// if incomming pointers are useless return immediatly |
if ((filename == 0) || (File == 0) || (!Partition.IsValid)) return 0; |
if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0; |
// trace along the filepath |
path = (u8*)filename; // start a the beginning of the filename string |
File->DirectorySector = 0; // start at RootDirectory with file search |
File->DirectoryIndex = 0; |
path = (s8*)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 |
if((subpath = SeperateDirName(path, dirname))) |
if(subpath != 0) |
{ |
if(*subpath == 0) |
{ // empty subpath indicates last element of dir chain |
1248,10 → 1315,10 |
af = ATTR_SUBDIRECTORY; |
am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL; |
} |
if(!DirectoryEntryExist(dirname, af, am, File)) // if subdir or file is not existent |
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)) |
if(!CreateDirectoryEntry(dirname, af, file)) |
{ // could not be created |
return(file_created); |
} |
1270,7 → 1337,7 |
/********************************************************************************************************************************************/ |
/* Function: File_t * fopen_(u8* filename, s8 mode); */ |
/* Function: File_t * fopen_(s8* filename, s8 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. */ |
1277,68 → 1344,77 |
/* */ |
/* Returnvalue: The filepointer to the file or 0 if faild. */ |
/********************************************************************************************************************************************/ |
File_t * fopen_(const u8 *filename, const s8 mode) |
File_t * fopen_(const s8 *filename, const s8 mode) |
{ |
File_t *File = 0; |
File_t *file = 0; |
if((!Partition.IsValid) || (filename == 0)) return(File); |
if((!Partition.IsValid) || (filename == 0)) return(file); |
// Look for an unused filepointer in the file pointer list? |
File = LockFilePointer(); |
file = LockFilePointer(); |
// if no unused file pointer was found return 0 |
if(File == 0) return(File); |
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. |
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)) |
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) |
if((file->Attribute & ATTR_READONLY) == ATTR_READONLY) |
{ // file is marked as readonly --> do not open this file |
File->State = FSTATE_UNUSED; // release file pointer |
File = 0; |
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 |
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) |
if((file->Attribute & ATTR_READONLY) == ATTR_READONLY) |
{ // file is marked as readonly --> do not open this file |
File->State = FSTATE_UNUSED; // release file pointer |
File = 0; |
fclose_(file); |
file = NULL; |
} |
else |
{ // file is not marked as read only --> goto start of file |
fseek_(File, 0, SEEK_SET); |
// 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 to file |
case 'r': // if mode is: read from file |
// goto end of file |
fseek_(File, 0, SEEK_SET); |
fseek_(file, 0, SEEK_SET); |
break; |
default: // other modes are not supported |
File->State = FSTATE_UNUSED; // release file pointer |
File = 0; |
fclose_(file); |
file = NULL; |
break; |
} |
return(File); |
return(file); |
} |
else // file does not exist |
{ |
1347,24 → 1423,24 |
case 'a': |
case 'w': // if mode is write or append |
// try to create the file |
if(!FileCreate(filename, ATTR_ARCHIVE, File)) |
if(!FileCreate(filename, ATTR_ARCHIVE, file)) |
{ // if it could not be created |
File->State = FSTATE_UNUSED; // release file pointer |
File = 0; |
fclose_(file); |
file = NULL; |
} |
break; |
case 'r': // else opend for 'r' |
case 'r': // else opened for 'r' |
default: // of unsupported mode |
File->State = FSTATE_UNUSED; // release file pointer |
File = 0; |
fclose_(file); |
file = NULL; |
break; |
} |
return(File); |
return(file); |
} |
// we should never come to this point |
File->State = FSTATE_UNUSED; // release file pointer |
File = 0; |
return(File); |
fclose_(file); |
file = NULL; |
return(file); |
} |
/****************************************************************************************************************************************************/ |
1374,35 → 1450,35 |
/* */ |
/* Returnvalue: 0 on success EOF on error */ |
/****************************************************************************************************************************************************/ |
s16 fflush_(File_t *File) |
s16 fflush_(File_t *file) |
{ |
DirEntry_t *Dir; |
DirEntry_t *dir; |
if((File == 0) || (!Partition.IsValid)) return (EOF); |
if((file == NULL) || (!Partition.IsValid)) return (EOF); |
switch(File->Mode) |
switch(file->Mode) |
{ |
case 'a': |
case 'w': |
if(File->ByteOfCurrSector > 0) // has data been added to the file? |
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 |
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. |
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 |
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); |
1425,13 → 1501,13 |
/* */ |
/* Returnvalue: 0 on success EOF on error */ |
/****************************************************************************************************************************************/ |
s16 fclose_(File_t *File) |
s16 fclose_(File_t *file) |
{ |
s16 returnvalue = EOF; |
if(File == 0) return(returnvalue); |
returnvalue = fflush_(File); |
UnlockFilePointer(File); |
if(file == NULL) return(returnvalue); |
returnvalue = fflush_(file); |
UnlockFilePointer(file); |
return(returnvalue); |
} |
1443,45 → 1519,45 |
/* */ |
/* Returnvalue: The function returns the character read from the specified memorylocation as u8 casted to s16 or EOF. */ |
/********************************************************************************************************************************************/ |
s16 fgetc_(File_t *File) |
s16 fgetc_(File_t *file) |
{ |
s16 c = EOF; |
u32 curr_sector; |
if( (!Partition.IsValid) || (File == 0)) return(c); |
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 < File->Size) ) |
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; |
curr_sector = file->FirstSectorOfCurrCluster; // calculate the sector of the next character to be read. |
curr_sector += file->SectorOfCurrCluster; |
if(File->SectorInCache != curr_sector) |
if(file->SectorInCache != curr_sector) |
{ |
File->SectorInCache = curr_sector; |
if(SD_SUCCESS != SDC_GetSector(File->SectorInCache, File->Cache)) |
file->SectorInCache = curr_sector; |
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache,file->Cache)) |
{ |
Fat16_Deinit(); |
return(c); |
} |
} |
c = (s16) 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 |
c = (s16) 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. |
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(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. |
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 |
file->SectorOfCurrCluster--; // jump back to the last sector in the last cluster |
file->ByteOfCurrSector = BYTES_PER_SECTOR; // set ByteOfCurrSector one byte over sector end |
} |
} |
} |
1490,7 → 1566,7 |
} |
/********************************************************************************************************************************************/ |
/* Function: fputc_( const s8 c, File *File); */ |
/* 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. */ |
1497,26 → 1573,26 |
/* */ |
/* Returnvalue: The function returns the character written to the stream or EOF on error. */ |
/********************************************************************************************************************************************/ |
s16 fputc_(const u8 c, File_t *File) |
s16 fputc_(const s8 c, File_t *file) |
{ |
u32 curr_sector = 0; |
if((!Partition.IsValid) || (File == 0)) return(EOF); |
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((file->Position >= file->Size) && (file->ByteOfCurrSector >= BYTES_PER_SECTOR)) |
{ |
if(!AppendCluster(File)) return(EOF); |
if(!AppendCluster(file)) return(EOF); |
} |
curr_sector = File->FirstSectorOfCurrCluster; |
curr_sector += File->SectorOfCurrCluster; |
if(File->SectorInCache != curr_sector) |
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)) |
file->SectorInCache = curr_sector; |
if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache)) |
{ |
Fat16_Deinit(); |
return(EOF); |
1523,33 → 1599,33 |
} |
} |
File->Cache[File->ByteOfCurrSector] = 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 |
file->Cache[file->ByteOfCurrSector] = (u8)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)) |
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. |
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(!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. |
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 |
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. |
file->SectorOfCurrCluster = 0; // start reading new cluster at first sector of the cluster. |
} |
} |
} |
1565,7 → 1641,7 |
/* */ |
/* Returnvalue: The function returns the number of objects (not bytes) read from the file. */ |
/****************************************************************************************************************************************/ |
u32 fread_(void *buffer, u32 size, u32 count, File_t *File) |
u32 fread_(void *buffer, u32 size, u32 count, File_t *file) |
{ |
u32 object_cnt = 0; // count the number of objects read from the file. |
u32 object_size = 0; // count the number of bytes read from the actual object. |
1573,7 → 1649,7 |
u8 success = 1; // no error occured during read operation to the file. |
s16 c; |
if((!Partition.IsValid) || (File == 0) || (buffer == 0)) return(0); |
if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0); |
pbuff = (u8 *) buffer; // cast the void pointer to an u8 * |
1582,7 → 1658,7 |
object_size = size; |
while((size > 0) && success) |
{ |
c = fgetc_(File); |
c = fgetc_(file); |
if(c != EOF) |
{ |
*pbuff = (u8)c; // read a byte from the buffer to the opened file. |
1608,7 → 1684,7 |
/* */ |
/* Returnvalue: The function returns the number of objects (not bytes) read from the file. */ |
/****************************************************************************************************************************************/ |
u32 fwrite_(void *buffer, u32 size, u32 count, File_t *File) |
u32 fwrite_(void *buffer, u32 size, u32 count, File_t *file) |
{ |
u32 object_cnt = 0; // count the number of objects written to the file. |
u32 object_size = 0; // count the number of bytes written from the actual object. |
1616,7 → 1692,7 |
u8 success = 1; // no error occured during write operation to the file. |
s16 c; |
if((!Partition.IsValid) || (File == 0) || (buffer == 0)) return(0); |
if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0); |
pbuff = (u8 *) buffer; // cast the void pointer to an u8 * |
1625,7 → 1701,7 |
object_size = size; |
while((size > 0) && success) |
{ |
c = fputc_(*pbuff, File); // write a byte from the buffer to the opened file. |
c = fputc_(*pbuff, file); // write a byte from the buffer to the opened file. |
if(c != EOF) |
{ |
pbuff++; |
1644,22 → 1720,22 |
/****************************************************************************************************************************************/ |
/* Function: fputs_(const u8 *string, File_t *File); */ |
/* Function: fputs_(const s8 *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. */ |
/****************************************************************************************************************************************/ |
s16 fputs_(const u8 *string, File_t *File) |
s16 fputs_(const s8 *string, File_t *file) |
{ |
u8 i=0; |
s16 c = 0; |
if((!Partition.IsValid) || (File == 0) || (string == 0)) return(0); |
if((!Partition.IsValid) || (file == NULL) || (string == NULL)) return(0); |
while((string[i] != 0)&& (c != EOF)) |
{ |
c = fputc_(string[i], File); |
c = fputc_(string[i], file); |
i++; |
} |
return(c); |
1666,22 → 1742,22 |
} |
/****************************************************************************************************************************************/ |
/* Function: fgets_(u8 *, s16 , File_t *); */ |
/* Function: fgets_(s8 *, s16 , 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. */ |
/****************************************************************************************************************************************/ |
u8 * fgets_(u8 *string, s16 length, File_t *File) |
u8 * fgets_(s8 *string, s16 length, File_t *file) |
{ |
u8 *pbuff; |
s16 c = 0; |
if((!Partition.IsValid) || (File == 0) || (string == 0) || (length = 0)) return (0); |
if((!Partition.IsValid) || (file == NULL) || (string == NULL) || (length = 0)) return (0); |
pbuff = string; |
while(length > 1) // read the count-1 characters from the file to the string. |
{ |
c = fgetc_(File); // read a character from the opened file. |
c = fgetc_(file); // read a character from the opened file. |
switch(c) |
{ |
case 0x0A: |
1702,19 → 1778,39 |
} |
/****************************************************************************************************************************************/ |
/* Function: fexit_(const u8*); */ |
/* Function: fexist_(const u8*); */ |
/* */ |
/* Description: This function checks if a file already exist. */ |
/* */ |
/* Returnvalue: 1 if the file exist else 0. */ |
/****************************************************************************************************************************************/ |
u8 fexit_(const u8* filename) |
u8 fexist_(const s8* filename) |
{ |
u8 exist = 0; |
File_t *File = 0; |
File = LockFilePointer(); |
exist = FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, File); |
UnlockFilePointer(File); |
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. */ |
/****************************************************************************************************************************************/ |
u8 feof_(File_t *file) |
{ |
if(((file->Position)+1) < (file->Size)) |
{ |
return(0); |
} |
else |
{ |
return(1); |
} |
} |
/branches/V0.1 killagreg/fat16.h |
---|
44,22 → 44,24 |
// |
//________________________________________________________________________________________________________________________________________ |
extern u8 Fat16_Init(void); |
extern u8 Fat16_Deinit(void); |
u8 Fat16_Init(void); |
u8 Fat16_Deinit(void); |
extern File_t * fopen_(const u8 *filename, const s8 mode); |
extern s16 fclose_(File_t *File); |
extern u8 fexist_(const u8 *filename); |
extern s16 fflush_(File_t *File); |
extern s16 fseek_(File_t *File, s32 offset, s16 origin); |
extern s16 fgetc_(File_t *File); |
extern s16 fputc_(u8 c, File_t *File); |
extern u32 fread_(void *buffer, u32 size, u32 count, File_t *File); |
extern u32 fwrite_(void *buffer, u32 size, u32 count, File_t *File); |
extern s16 fputs_(const u8 *string, File_t *File); |
extern u8 * fgets_(u8 *string, s16 length, File_t *File); |
File_t *fopen_(const s8 *filename, const s8 mode); |
s16 fclose_(File_t *file); |
u8 fexist_(const s8 *filename); |
s16 fflush_(File_t *file); |
s16 fseek_(File_t *file, s32 offset, s16 origin); |
s16 fgetc_(File_t *file); |
s16 fputc_(s8 c, File_t *file); |
u32 fread_(void *buffer, u32 size, u32 count, File_t *file); |
u32 fwrite_(void *buffer, u32 size, u32 count, File_t *file); |
s16 fputs_(const s8 *string, File_t *file); |
u8 * fgets_(s8 *string, s16 length, File_t *file); |
u8 feof_(File_t *file); |
#endif //_FAT16_H |
/branches/V0.1 killagreg/i2c.c |
---|
56,122 → 56,198 |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
#include "91x_lib.h" |
#include "i2c.h" |
#include "uart.h" |
#include "uart1.h" |
#include "timer.h" |
#include "main.h" |
#include "led.h" |
volatile I2C_State_t I2C_State; |
// rxbuffer |
u8 I2C_RxBufferSize; |
u8 *I2C_RxBuffer; |
u8 Rx_Idx = 0; |
volatile u8 I2C_RxBufferSize; |
volatile u8 *I2C_RxBuffer; |
volatile u8 Rx_Idx = 0; |
// txbuffer |
u8 I2C_TxBufferSize; |
u8 *I2C_TxBuffer; |
u8 Tx_Idx = 0; |
volatile u8 I2C_TxBufferSize; |
volatile u8 *I2C_TxBuffer; |
volatile u8 Tx_Idx = 0; |
u8 I2C_Direction; |
u8 I2C_Command; |
volatile u8 I2C_Direction; |
volatile u8 I2C_Command; |
I2C_Heading_t I2C_Heading; |
I2C_WriteAttitude_t I2C_WriteAttitude; |
I2C_Mag_t I2C_Mag; |
I2C_EEPROM_t I2C_ReadEEPROM, I2C_WriteEEPROM; |
I2C_Version_t I2C_Version; |
I2C_WriteCal_t I2C_WriteCal; |
volatile I2C_Heading_t I2C_Heading; |
volatile I2C_WriteAttitude_t I2C_WriteAttitude; |
volatile I2C_Mag_t I2C_Mag; |
volatile I2C_EEPROM_t I2C_ReadEEPROM, I2C_WriteEEPROM; |
volatile I2C_Version_t I2C_Version; |
volatile I2C_WriteCal_t I2C_WriteCal; |
u8 CompassUpdateActiv = 0; |
u8 CompassCalState = 0; |
volatile u8 I2C_ReadRequest = 0; |
volatile u32 I2C1_Timeout = 0; |
//-------------------------------------------------------------- |
void I2C1_Init(void) |
{ |
I2C_InitTypeDef I2C_Struct; |
GPIO_InitTypeDef GPIO_Struct; |
GPIO_InitTypeDef GPIO_InitStructure; |
SerialPutString("I2C init..."); |
SerialPutString("\r\n I2C init..."); |
SCU_APBPeriphClockConfig(__I2C1,ENABLE); |
I2C_DeInit(I2C1); |
// configure P2.2->I2C1_CLKOUT and P2.3->I2C1_DOUT |
GPIO_Struct.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3; |
GPIO_Struct.GPIO_Type = GPIO_Type_OpenCollector; |
GPIO_Struct.GPIO_IPConnected = GPIO_IPConnected_Enable; |
GPIO_Struct.GPIO_Alternate=GPIO_OutputAlt2; //I2C1_CLKOUT, I2C1_DOUT |
GPIO_Init(GPIO2, &GPIO_Struct); |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_OpenCollector; |
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable; |
GPIO_InitStructure.GPIO_Alternate=GPIO_OutputAlt2; //I2C1_CLKOUT, I2C1_DOUT |
GPIO_Init(GPIO2, &GPIO_InitStructure); |
I2C_StructInit(&I2C_Struct); |
I2C_Struct.I2C_GeneralCall = I2C_GeneralCall_Disable; |
I2C_Struct.I2C_Ack = I2C_Ack_Enable; |
I2C_Struct.I2C_CLKSpeed = 20000; |
I2C_Struct.I2C_OwnAddress = I2C_SLAVE_ADDRESS; |
I2C_Struct.I2C_OwnAddress = 0x00; //?? |
I2C_Init(I2C1, &I2C_Struct); |
I2C_Cmd(I2C1, ENABLE); |
I2C_ITConfig(I2C1, ENABLE); |
VIC_Config(I2C1_ITLine, VIC_IRQ , 8); |
VIC_Config(I2C1_ITLine, VIC_IRQ , 0); |
VIC_ITCmd(I2C1_ITLine, ENABLE); |
I2C1_Timeout = SetDelay(1000); |
I2C_Heading.Heading = -1; |
SerialPutString("ok\n\r"); |
I2C_State = I2C_IDLE; |
SerialPutString("ok"); |
} |
//-------------------------------------------------------------- |
void I2C1_Deinit(void) |
{ |
SerialPutString("\r\n I2C deinit..."); |
I2C_GenerateStart(I2C1, DISABLE); |
I2C_GenerateSTOP(I2C1, ENABLE); |
VIC_ITCmd(I2C1_ITLine, DISABLE); |
I2C_ITConfig(I2C1, DISABLE); |
I2C_Cmd(I2C1, DISABLE); |
I2C_DeInit(I2C1); |
SCU_APBPeriphClockConfig(__I2C1,DISABLE); |
I2C_State = I2C_UNDEF; |
I2C1_Timeout = 0; |
I2C_Heading.Heading = 0; |
SerialPutString("ok"); |
} |
//-------------------------------------------------------------- |
void I2C1_IRQHandler(void) |
{ |
switch (I2C_GetLastEvent(I2C1)) |
{ |
// the start condition was initiated on the bus |
case I2C_EVENT_MASTER_MODE_SELECT: // EV5 |
// reset TX/RX buffer indices |
Tx_Idx = 0; |
Rx_Idx = 0; |
// update current bus state variable |
switch(I2C_Direction) |
{ |
case I2C_MODE_TRANSMITTER: |
I2C_State = I2C_TX_PROGRESS; |
break; |
case I2C_MODE_RECEIVER: |
I2C_State = I2C_RX_PROGRESS; |
break; |
default: |
I2C_State = I2C_UNDEF; |
break; |
} |
// send address/direction byte on the bus |
I2C_Send7bitAddress(I2C1, I2C_SLAVE_ADDRESS, I2C_Direction); |
// reset timeout |
I2C1_Timeout = SetDelay(500); // after 500 ms of inactivity the I2C1 bus will be reset |
break; |
// tha address byte was send |
case I2C_EVENT_MASTER_MODE_SELECTED: // EV6 |
// Clear EV6 by set again the PE bit |
I2C1->CR |= 0x20; |
if (I2C_Direction == I2C_MODE_TRANSMITTER) |
{ |
I2C_SendData(I2C1, I2C_Command); //EV8 just after EV6 |
} |
switch(I2C_State) |
{ |
case I2C_TX_PROGRESS: |
// send command 1st data byte (allways the command id) |
I2C_SendData(I2C1, I2C_Command); |
break; |
case I2C_RX_PROGRESS: |
// before the last byte is received the master should disable |
// the acknowledge bit to signal the slave that |
// no more bytes |
// the ACK is disabled here only if 1 byte is expected |
if(I2C_RxBufferSize == 1) I2C_AcknowledgeConfig(I2C1, DISABLE); |
break; |
default: |
// should never happen |
I2C_GenerateSTOP (I2C1, ENABLE); |
I2C_State = I2C_IDLE; |
break; |
} |
break; |
case I2C_EVENT_MASTER_BYTE_TRANSMITTED: // EV8 |
if ( Tx_Idx >= I2C_TxBufferSize ) |
// the master has transmitted a byte to the slave |
case I2C_EVENT_MASTER_BYTE_TRANSMITTED: // EV8 |
// if all bytes are transmitted |
if ( Tx_Idx >= I2C_TxBufferSize ) // all bytes transmitted |
{ |
I2C_GenerateSTOP (I2C1, ENABLE); |
Tx_Idx = 0; |
if (I2C_RxBufferSize > 0) // is answer expected? |
// generate a STOP condition on the bus |
I2C_GenerateSTOP (I2C1, ENABLE); // generate stop condition to free the bus |
if (I2C_RxBufferSize > 0) // is any answer byte expected? |
{ |
I2C_ReadRequest = 1; |
TimerI2CReadDelay = SetDelay(10); |
I2C_State = I2C_RX_PENDING; // data can be read back |
TimerI2CReadDelay = SetDelay(10); // start master receiver sequence in 10 ms |
} |
else I2C_State = I2C_IDLE; // ready for new actions |
} |
else |
else // some bytes have to be transmitted |
{ |
I2C_SendData(I2C1, I2C_TxBuffer[Tx_Idx]); |
I2C_SendData(I2C1, I2C_TxBuffer[Tx_Idx]); // send next byte |
Tx_Idx++; |
} |
break; |
case I2C_EVENT_MASTER_BYTE_RECEIVED: // EV7 |
// the master has received a byte from the slave |
case I2C_EVENT_MASTER_BYTE_RECEIVED: // EV7 |
DebugOut.Analog[16]++; |
// before the last byte |
if ( (Rx_Idx + 2) >= I2C_RxBufferSize ) |
{ // disable the ACK to signal the slave that the next received byte is the last one |
I2C_AcknowledgeConfig (I2C1, DISABLE); |
} |
// if the last byte was received |
if ( (Rx_Idx + 1) >= I2C_RxBufferSize ) |
{ |
// generate a STOP condition on the bus |
I2C_GenerateSTOP(I2C1, ENABLE); |
I2C_State = I2C_IDLE; |
LED_GRN_TOGGLE; |
} |
// as long as there is some space in the rx-buffer |
if (Rx_Idx < I2C_RxBufferSize) |
{ |
{ // copy received byte from the data register to the rx-buffer |
I2C_RxBuffer[Rx_Idx] = I2C_ReceiveData(I2C1); |
} |
else I2C_ReceiveData(I2C1); |
Rx_Idx++; |
if ( Rx_Idx == I2C_RxBufferSize-2 ) |
{ |
I2C_AcknowledgeConfig (I2C1, DISABLE); |
} |
if ( Rx_Idx == I2C_RxBufferSize -1 ) |
{ |
I2C_GenerateSTOP(I2C1, ENABLE); |
if (I2C_Command == I2C_CMD_READ_HEADING) CompassUpdateActiv = 0; |
} |
else I2C_ReceiveData(I2C1); // just read the data register |
Rx_Idx++; // set index to next byte |
break; |
default: |
179,10 → 255,16 |
} |
} |
//---------------------------------------------------------------- |
void SendI2C_Command(u8 command) |
void I2C1_SendCommand(u8 command) |
{ |
I2C_Command = command; |
//I2C_GenerateSTOP(I2C1, ENABLE); |
// If I2C transmission is in progress |
if (I2C_State != I2C_IDLE) return; // return |
// disable I2C IRQ to avoid read/write access to the tx/rx buffer pointers during |
// update of that buffer pointers and length |
I2C_ITConfig(I2C1, DISABLE); |
// update current command id |
I2C_Command = command; |
// set pointers to data area with respect to the command id |
switch (command) |
{ |
case I2C_CMD_VERSION: |
213,7 → 295,6 |
I2C_TxBufferSize = 0; |
break; |
case I2C_CMD_READ_HEADING: |
CompassUpdateActiv = 1; |
I2C_RxBuffer = (u8 *)&I2C_Heading; |
I2C_RxBufferSize = sizeof(I2C_Heading); |
I2C_TxBuffer = (u8 *)&I2C_WriteAttitude; |
221,14 → 302,28 |
break; |
} |
if (I2C_RxBufferSize > 0) |
{ |
I2C_RxBufferSize++; |
if (I2C_RxBufferSize < 3) I2C_RxBufferSize = 3; |
} |
I2C_AcknowledgeConfig (I2C1, ENABLE); |
// enable I2C IRQ again |
I2C_ITConfig(I2C1, ENABLE); |
// set direction to master transmitter |
I2C_Direction = I2C_MODE_TRANSMITTER; |
// enable acknowledge |
I2C_AcknowledgeConfig(I2C1, ENABLE); |
// initiale start condition on the bus |
I2C_GenerateStart(I2C1, ENABLE); |
// to be continued in the I2C1_IRQHandler() above |
} |
void I2C1_ReadAnswer(void) |
{ |
// only if the bus state is matching |
if (I2C_State == I2C_RX_PENDING) |
{ |
// set direction to master receiver |
I2C_Direction = I2C_MODE_RECEIVER; |
// enable acknowledge |
I2C_AcknowledgeConfig(I2C1, ENABLE); |
// initiale start condition on the bus |
I2C_GenerateStart(I2C1, ENABLE); |
// to be continued in the I2C1_IRQHandler() above |
} |
} |
/branches/V0.1 killagreg/i2c.h |
---|
54,22 → 54,33 |
u16 Heading; |
} __attribute__((packed)) I2C_Heading_t; |
typedef enum |
{ |
I2C_UNDEF, |
I2C_IDLE, |
I2C_TX_PROGRESS, |
I2C_RX_PENDING, |
I2C_RX_PROGRESS, |
} I2C_State_t; |
extern u8 Tx_Idx, Rx_Idx, I2C_Direction; |
extern u8 CompassCalState; |
extern volatile I2C_State_t I2C_State; |
extern volatile u8 I2C_Direction; |
extern volatile u32 I2C1_Timeout; |
extern I2C_Heading_t I2C_Heading; |
extern I2C_WriteAttitude_t I2C_WriteAttitude; |
extern I2C_Mag_t I2C_Mag; |
extern I2C_EEPROM_t I2C_ReadEEPROM, I2C_WriteEEPROM; |
extern I2C_Version_t I2C_Version; |
extern I2C_WriteCal_t I2C_WriteCal; |
extern volatile I2C_Heading_t I2C_Heading; |
extern volatile I2C_WriteAttitude_t I2C_WriteAttitude; |
extern volatile I2C_Mag_t I2C_Mag; |
extern volatile I2C_EEPROM_t I2C_ReadEEPROM, I2C_WriteEEPROM; |
extern volatile I2C_Version_t I2C_Version; |
extern volatile I2C_WriteCal_t I2C_WriteCal; |
extern void I2C1_Init(void); |
extern void SendI2C_Command(u8 command); |
extern u8 CompassUpdateActiv; |
extern volatile u8 I2C_ReadRequest; |
extern u8 CompassCalState; |
void I2C1_Init(void); |
void I2C1_Deinit(void); |
void I2C1_SendCommand(u8 command); |
void I2C1_ReadAnswer(void); |
#endif // I2C_H |
/branches/V0.1 killagreg/interrupt.c |
---|
57,6 → 57,9 |
//#include "main.h" |
#include "91x_lib.h" |
#include "usb_lib.h" |
#include "fat16.h" |
#include "main.h" |
#include "uart1.h" |
#define global extern /* to declare external variables and functions */ |
extern void USB_Istr(void); |
69,29 → 72,65 |
void Dummy_Handler(void) |
{ |
VIC0->VAR = 0xFF; |
VIC1->VAR = 0XFF; |
VIC0->VAR = 0xFF; |
VIC1->VAR = 0xFF; |
} |
/* avoid the surprising reset-like behaviour by spurious interrupts */ |
void Interrupt_Init(void) |
{ |
VIC0->DVAR = (u32)Dummy_Handler; |
VIC1->DVAR = (u32)Dummy_Handler; |
} |
/******************************************************************************* |
* Function Name : SWI_Handler |
* Description : This function handles SW exception. |
* Input : None |
* Output : None |
* Return : None |
*******************************************************************************/ |
void SWI_Handler (void) |
{ |
} |
/******************************************************************************* |
* Function Name : Abort_Handler |
* Description : This function handles data abort exception. |
* Input : None |
* Output : None |
* Return : None |
*******************************************************************************/ |
void Abort_Handler (void) |
{ |
SerialPutString("\r\nAbort Handler"); |
while(1) |
{ |
// infinite loop |
} |
} |
/******************************************************************************* |
* Function Name : Undefined_Handler |
* Description : This function handles undefined instruction exception. |
* Input : None |
* Output : None |
* Return : None |
*******************************************************************************/ |
void Undefined_Handler (void) |
{ |
SerialPutString("\r\nUndefined Handler"); |
while(1) |
{ |
// infinite loop |
} |
} |
/******************************************************************************* |
* Function Name : FIQ_Handler |
* Description : This function handles FIQ exception. |
* Input : None |
* Output : None |
* Return : None |
*******************************************************************************/ |
void FIQ_Handler (void) |
{ |
} |
101,6 → 140,11 |
*******************************************************************************/ |
void Prefetch_Handler(void) |
{ |
SerialPutString("\r\nPrefetch Handler"); |
while(1) |
{ |
// infinite loop |
} |
} |
/******************************************************************************* |
* Function Name : WDG_IRQHandler |
108,6 → 152,12 |
*******************************************************************************/ |
void WDG_IRQHandler(void) |
{ |
/*write your handler here*/ |
/* ... */ |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : SW_IRQHandler |
115,6 → 165,12 |
*******************************************************************************/ |
void SW_IRQHandler(void) |
{ |
/*write your handler here*/ |
/* ... */ |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : ARMRX_IRQHandler |
122,6 → 178,12 |
*******************************************************************************/ |
void ARMRX_IRQHandler(void) |
{ |
/*write your handler here*/ |
/* ... */ |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : ARMTX_IRQHandler |
129,6 → 191,12 |
*******************************************************************************/ |
void ARMTX_IRQHandler(void) |
{ |
/*write your handler here*/ |
/* ... */ |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : TIM0_IRQHandler |
136,14 → 204,24 |
*******************************************************************************/ |
void TIM0_IRQHandler(void) |
{ |
/*write your handler here*/ |
/* ... */ |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : TIM1_IRQHandler |
* Description : This function handles the TIM1 interrupt request |
*******************************************************************************/ |
//void TIM1_IRQHandler(void) |
//{ |
//} |
/* |
void TIM1_IRQHandler(void) |
{ |
// write any value to VIC0 VAR // |
VIC0->VAR = 0xFF; |
} |
*/ |
/******************************************************************************* |
* Function Name : TIM2_IRQHandler |
* Description : This function handles the TIM2 interrupt request |
150,6 → 228,12 |
*******************************************************************************/ |
void TIM2_IRQHandler(void) |
{ |
/*write your handler here*/ |
/* ... */ |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : TIM3_IRQHandler |
157,6 → 241,12 |
*******************************************************************************/ |
void TIM3_IRQHandler(void) |
{ |
/*write your handler here*/ |
/* ... */ |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : USBHP_IRQHandler |
164,7 → 254,9 |
*******************************************************************************/ |
void USBHP_IRQHandler(void) |
{ |
CTR_HP(); |
CTR_HP(); |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : USBLP_IRQHandler |
172,7 → 264,8 |
*******************************************************************************/ |
void USBLP_IRQHandler(void) |
{ |
USB_Istr(); |
USB_Istr(); /*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : SCU_IRQHandler |
180,6 → 273,12 |
*******************************************************************************/ |
void SCU_IRQHandler(void) |
{ |
/*write your handler here*/ |
/* ... */ |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : ENET_IRQHandler |
187,6 → 286,12 |
*******************************************************************************/ |
void ENET_IRQHandler(void) |
{ |
/*write your handler here*/ |
/* ... */ |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : DMA_IRQHandler |
194,6 → 299,12 |
*******************************************************************************/ |
void DMA_IRQHandler(void) |
{ |
/*write your handler here*/ |
/* ... */ |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : CAN_IRQHandler |
201,6 → 312,12 |
*******************************************************************************/ |
void CAN_IRQHandler(void) |
{ |
/*write your handler here*/ |
/* ... */ |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : MC_IRQHandler |
208,6 → 325,12 |
*******************************************************************************/ |
void MC_IRQHandler(void) |
{ |
/*write your handler here*/ |
/* ... */ |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : ADC_IRQHandler |
215,6 → 338,12 |
*******************************************************************************/ |
void ADC_IRQHandler(void) |
{ |
/*write your handler here*/ |
/* ... */ |
/*write any value to VIC0 VAR*/ |
VIC0->VAR = 0xFF; |
} |
/******************************************************************************* |
* Function Name : UART0_IRQHandler |
227,15 → 356,9 |
* Function Name : UART1_IRQHandler |
* Description : This function handles the UART1 interrupt request |
*******************************************************************************/ |
//void UART1_IRQHandler(void) __attribute__ ((interrupt ("IRQ"))); |
/*void UART1_IRQHandler(void) |
{ |
UART1->DR = UART1->DR; |
UART_ClearITPendingBit(UART1, UART_IT_Receive); |
} |
*/ |
{ |
} */ |
/******************************************************************************* |
* Function Name : UART2_IRQHandler |
* Description : This function handles the UART2 interrupt request |
303,9 → 426,19 |
* Function Name : EXTIT1_IRQHandler |
* Description : This function handles the EXTIT1 interrupt request |
*******************************************************************************/ |
/*void EXTIT1_IRQHandler(void) |
void EXTIT1_IRQHandler(void) |
{ |
}*/ |
VIC_ITCmd(EXTIT1_ITLine, DISABLE); |
if(WIU_GetITStatus(WIU_Line11) != RESET) |
{ |
BeepTime = 100; |
Fat16_Init(); // initialize sd-card file system. |
WIU_ClearFlag(WIU_Line1); |
WIU_ClearITPendingBit(WIU_Line11); |
} |
VIC_ITCmd(EXTIT1_ITLine, ENABLE); |
} |
/******************************************************************************* |
* Function Name : EXTIT2_IRQHandler |
* Description : This function handles the EXTIT2 interrupt request |
/branches/V0.1 killagreg/kml.c |
---|
0,0 → 1,382 |
/*#######################################################################################*/ |
/* !!! 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 "91x_lib.h" |
#include "kml.h" |
#include "kml_header.h" |
//________________________________________________________________________________________________________________________________________ |
// Module name: kml.c |
// Compiler used: avr-gcc 3.4.5 |
// Last Modifikation: 20.07.2008 |
// Version: 1.02 |
// Authors: Stephan Busker |
// 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(s8 *name, 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 |
//________________________________________________________________________________________________________________________________________ |
u8 KML_DocumentInit(KML_Document_t *doc) |
{ |
doc->name[0] = 0; // name of the document |
doc->state = DOC_CLOSED; // state of the kml-document |
doc->file = NULL; |
doc->place.name[0]=0; |
doc->place.description[0]=0; |
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. |
//________________________________________________________________________________________________________________________________________ |
u8 KML_DocumentOpen(s8 *name, KML_Document_t *doc) |
{ |
u8 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 = 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- footer to the document. |
} |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Function: DocumentClose(KML_Document_t *doc); |
// |
// Description: This function closes the document specified by doc. |
// |
// |
// Returnvalue: none |
//________________________________________________________________________________________________________________________________________ |
u8 KML_DocumentClose(KML_Document_t *doc) |
{ |
u8 retvalue = 1; |
if(doc == NULL) return(0); |
while(doc->state != DOC_CLOSED) // close linestring, placemark and document before closing the file on the memorycard |
{ |
switch(doc->state) |
{ |
case DOC_LINESTRING_OPENED: |
KML_LineStringEnd(doc); // write terminating tag to end linestring. |
doc->state = DOC_PLACEMARK_OPENED; |
break; |
case DOC_PLACEMARK_OPENED: // write terminating tag to close placemark. |
KML_PlaceMarkClose(doc); |
doc->state = DOC_OPENED; |
break; |
case 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 = DOC_CLOSED; |
break; |
default: |
doc->state = DOC_CLOSED; |
break; |
} |
} |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Function: u8 PlaceMarkOpen(s8 *name, File *file); |
// |
// Description: This function adds a placemark to the document. |
// |
// |
// Returnvalue: none |
//________________________________________________________________________________________________________________________________________ |
u8 KML_PlaceMarkOpen(s8 *name, KML_Document_t *doc) |
{ |
u8 retvalue = 0; |
if(doc->file != NULL) |
{ |
doc->state = 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: none |
//________________________________________________________________________________________________________________________________________ |
u8 KML_PlaceMarkClose(KML_Document_t *doc) |
{ |
u8 retvalue = 0; // close the Placemark-tag of the corosponding document. |
if(doc->state == DOC_PLACEMARK_OPENED) |
{ |
if(doc->file != NULL) |
{ |
doc->state = 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: none |
//________________________________________________________________________________________________________________________________________ |
u8 KML_LineStringBegin(KML_Document_t *doc) |
{ |
u8 retvalue = 0; |
if(doc->file != NULL) |
{ |
doc->state = DOC_LINESTRING_OPENED; |
fwrite_((void*)KML_LINESTRING_HEADER, sizeof(KML_LINESTRING_HEADER)-1,1,doc->file); |
retvalue = 1; |
} |
return(retvalue); |
} |
//________________________________________________________________________________________________________________________________________ |
// Function: u8 LineStringEnd(KML_Document_t *doc) |
// |
// Description: This function ends the placemark opened before. |
// |
// |
// Returnvalue: none |
//________________________________________________________________________________________________________________________________________ |
u8 KML_LineStringEnd(KML_Document_t *doc) |
{ |
u8 retvalue = 0; |
if(doc->state == DOC_LINESTRING_OPENED); |
if(doc->file != NULL) |
{ |
doc->state = 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: none |
//________________________________________________________________________________________________________________________________________ |
u8 KML_LineStringAddPoint(gps_data_t * pgpsdata ,KML_Document_t *doc) |
{ |
u8 retvalue = 0; |
s8 string[50]; |
if(doc == NULL || pgpsdata == NULL) return(0); |
if(pgpsdata->Status != INVALID) |
{ |
if(doc->state == DOC_LINESTRING_OPENED) |
{ |
if(doc->file != NULL) |
{ |
s32 i1, i2; |
i1 = GPSData.Longitude/10000000L; |
i2 = abs(GPSData.Longitude%10000000L); |
sprintf(string,"\r\n%+3ld.%07ld,",i1, i2); |
fputs_(string, doc->file); |
i1 = GPSData.Latitude/10000000L; |
i2 = abs(GPSData.Latitude%10000000L); |
sprintf(string," +%3ld.%07ld,",i1, i2); |
fputs_(string, doc->file); |
i1 = GPSData.Altitude/1000L; |
i2 = abs(GPSData.Altitude%1000L); |
sprintf(string," %+ld.%03ld",i1, i2); |
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: none |
//________________________________________________________________________________________________________________________________________ |
void KML_LoggGPSCoordinates(gps_data_t * pgpsdata, KML_Document_t *doc) |
{ |
while(doc->state != DOC_LINESTRING_OPENED) // automatic create document with default filename on the card. |
{ |
switch(doc->state) |
{ |
case DOC_CLOSED: // document hasn't been opened yet therefore it will be initialized automatically |
KML_DocumentInit(doc); // initialize the document to default values |
if(KML_DocumentOpen("default.kml",doc)) // open the kml-document with a standardname. |
{ |
doc->state = DOC_OPENED; |
} |
break; |
case DOC_OPENED: // if a document has been opened before but no placemark exists: |
if(KML_PlaceMarkOpen("MIKROKOPTER",doc)) |
{ |
doc->state = DOC_PLACEMARK_OPENED; // add a placemark to the document. |
} |
break; |
case DOC_PLACEMARK_OPENED: // add linestring to the placemark |
if(KML_LineStringBegin(doc)) |
{ |
doc->state = DOC_LINESTRING_OPENED; |
} |
break; |
default: |
break; |
} |
}; |
if(doc->state == DOC_LINESTRING_OPENED) // if the document was opened add coordinates to the document. |
{ |
KML_LineStringAddPoint(pgpsdata , doc); |
} |
} |
/branches/V0.1 killagreg/kml.h |
---|
0,0 → 1,50 |
#ifndef _KML_H |
#define _KML_H |
#include "fat16.h" |
#include "ubx.h" |
// possible state of an kml-document |
typedef enum |
{ |
DOC_CLOSED, |
DOC_OPENED, |
DOC_PLACEMARK_OPENED, |
DOC_LINESTRING_OPENED, |
DOC_END |
}KML_DocState_t; |
// structure of an kml-placemarkt |
typedef struct kml_place |
{ |
s8 name[10]; // the name of the placemark |
s8 description[40]; // some text as a description to the placemark |
} KML_PlaceMark_t; |
// structure of an kml-document |
typedef struct kml_doc |
{ |
u8 name[40]; // name of the document |
KML_DocState_t state; // state of the kml-document |
File_t *file; // filepointer to the file where the data should be saved. |
KML_PlaceMark_t place; |
} KML_Document_t; |
void KML_LoggGPSCoordinates(gps_data_t* pGPSData , KML_Document_t *); // intializes the kml-document with standard filename and adds points to the file |
u8 KML_DocumentInit(KML_Document_t *); // Init the new kml-document |
u8 KML_DocumentOpen(s8 *, KML_Document_t *); // opens a new kml-document. a new file is created on the sd-memorycard |
u8 KML_DocumentClose(KML_Document_t *doc); // closes the specified document saving remaining data to the file. |
u8 KML_PlaceMarkOpen(s8 *name, KML_Document_t *doc); // opens a new placemark within the open kml-document |
u8 KML_PlaceMarkClose(KML_Document_t *doc); // closes the actual placemark |
u8 KML_LineStringBegin(KML_Document_t *doc); // begins a new linestring within the actual placemark |
u8 KML_LineStringEnd(KML_Document_t *doc); // close the actual linestring within the actual placemark |
u8 KML_LineStringAddPoint(gps_data_t* pGPSData, KML_Document_t *); // adds a point from the gps (longitude, altitude, height) to the linestring |
#endif //_KML_H |
/branches/V0.1 killagreg/kml_header.h |
---|
0,0 → 1,91 |
//________________________________________________________________________________________________________________________________________ |
// |
// Definition of KML header and footer elements for documents, placemarks and linestrings |
// |
//________________________________________________________________________________________________________________________________________ |
const s8 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 s8 KML_DOCUMENT_FOOTER[] = |
{ |
"</Document>\r\n" |
"</kml>\r\n" |
}; |
//________________________________________________________________________________________________________________________________________ |
// |
// Header of an placemark |
// |
//________________________________________________________________________________________________________________________________________ |
const s8 KML_PLACEMARK_HEADER[] = |
{ |
"<Placemark>\r\n" |
"<name>flight</name>\r\n" |
"<styleUrl>#MK_gps-style</styleUrl>\r\n" |
}; |
//________________________________________________________________________________________________________________________________________ |
// |
// Footer of an placemark |
// |
//________________________________________________________________________________________________________________________________________ |
const s8 KML_PLACEMARK_FOOTER[] = |
{ |
"</Placemark>\r\n" |
}; |
//________________________________________________________________________________________________________________________________________ |
// |
// Footer of an placemark |
// |
//________________________________________________________________________________________________________________________________________ |
const s8 KML_LINESTRING_HEADER[] = |
{ |
"<LineString>\r\n" |
"<tessellate>1</tessellate>\r\n" |
"<altitudeMode>absolute</altitudeMode>\r\n" |
"<coordinates>\r\n" |
}; |
//________________________________________________________________________________________________________________________________________ |
// |
// Footer of an linestring |
// |
//________________________________________________________________________________________________________________________________________ |
const s8 KML_LINESTRING_FOOTER[] = |
{ |
"\r\n</coordinates>" |
"\r\n</LineString>\r\n" |
}; |
/branches/V0.1 killagreg/led.c |
---|
1,6 → 1,6 |
#include "91x_lib.h" |
#include "led.h" |
void Led_Init(void) |
{ |
GPIO_InitTypeDef GPIO_InitStructure; |
8,18 → 8,12 |
SCU_APBPeriphClockConfig(__GPIO5, ENABLE); // Enable the GPIO5 Clock |
/*Configure LED_GRN at pin GPIO5.6 and LED_ROT at pin GPIO5.7*/ |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ; |
GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt1 ; |
GPIO_Init(GPIO5, &GPIO_InitStructure); |
/* Configure SD_SWITCH at pin GPIO5.3*/ |
GPIO_InitStructure.GPIO_Direction = GPIO_PinInput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull; |
GPIO_InitStructure.GPIO_Alternate = GPIO_InputAlt1; |
GPIO_Init(GPIO5, &GPIO_InitStructure); |
LED_GRN_OFF; |
LED_RED_OFF; |
/branches/V0.1 killagreg/led.h |
---|
1,8 → 1,6 |
#ifndef _LED_H |
#define _LED_H |
#include "91x_lib.h" |
#define LED_GRN_ON GPIO_WriteBit(GPIO5, GPIO_Pin_6, Bit_SET) |
#define LED_GRN_OFF GPIO_WriteBit(GPIO5, GPIO_Pin_6, Bit_RESET) |
#define LED_GRN_TOGGLE if (GPIO_ReadBit(GPIO5, GPIO_Pin_6)) LED_GRN_OFF; else LED_GRN_ON; |
15,3 → 13,4 |
#endif //_LED_H |
/branches/V0.1 killagreg/main.c |
---|
55,13 → 55,15 |
// + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// + POSSIBILITY OF SUCH DAMAGE. |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
//#define MCLK96MHZ |
const unsigned long _Main_Crystal = 25000; |
#include <stdio.h> |
#include "91x_lib.h" |
#include "led.h" |
#include "GPSUart.h" |
#include "uart0.h" |
#include "uart1.h" |
//#include "uart2.h" |
#include "GPS.h" |
#include "uart.h" |
#include "i2c.h" |
#include "timer.h" |
#include "spi_slave.h" |
68,48 → 70,66 |
#include "fat16.h" |
#include "usb.h" |
#include "sdc.h" |
#include "kml.h" |
#include "main.h" |
u32 TimerCompassUpdate; |
u32 TimerI2CReadDelay; |
u32 TimerDebugDataDelay; |
u32 TimerKmlAddPointDelay; |
u8 BeepTime; |
void Init_Undef(void); |
u16 BeepTime; |
u8 ClearMKFlags = 0; |
Param_t Parameter; |
FC_t FC; |
void SCU_Config(void) |
{ |
/* configure PLL and set it as master clock source */ |
SCU_MCLKSourceConfig(SCU_MCLK_OSC); // set master clock source to external oscillator clock (25MHz) before diabling the PLL |
SCU_PLLCmd(DISABLE); // now disable the PLL |
#ifdef MCLK96MHZ |
SCU_BRCLKDivisorConfig(SCU_BRCLK_Div2); // set BRCLK to MCLK/2 = 48MHz |
SCU_PCLKDivisorConfig(SCU_PCLK_Div4); // set PCLK (APB bus clock) divisor to 4 (half Reference Clock) |
SCU_RCLKDivisorConfig(SCU_RCLK_Div2); // set RCLK (Reference Clock) divisor to 1 (full PPL clock) |
SCU_HCLKDivisorConfig(SCU_HCLK_Div2); // set HCLK (AHB bus clock) divisor to 1 (full Reference Clock) |
SCU_PLLFactorsConfig(192,25,2); // PLL = 96 MHz, Feedback Divider N=192, Pre-Divider M=25, Post-Divider P=2 |
#else |
SCU_BRCLKDivisorConfig(SCU_BRCLK_Div1); // set BRCLK to MCLK = 48MHz |
SCU_PCLKDivisorConfig(SCU_PCLK_Div2); // set PCLK (APB bus clock) divisor to 2 (half Reference Clock) |
SCU_RCLKDivisorConfig(SCU_RCLK_Div1); // set RCLK (Reference Clock) divisor to 1 (full PPL clock) |
SCU_HCLKDivisorConfig(SCU_HCLK_Div1); // set HCLK (AHB bus clock) divisor to 1 (full Reference Clock) |
SCU_PLLFactorsConfig(192,25,3); // PLL = 48 MHz, Feedback Divider N=192, Pre-Divider M=25, Post-Divider P=3 |
#endif |
SCU_PLLCmd(ENABLE); // Enable PLL (is disabled by SCU_PLLFactorsConfig) |
SCU_MCLKSourceConfig(SCU_MCLK_PLL); // set master clock source to PLL |
} |
//---------------------------------------------------------------------------------------------------- |
void OutputStartupData(void) |
{ |
u8 text[20]; |
u8 msg[20]; |
SerialPutString("\n\r--------------\n\r"); |
sprintf(text,"NaviCtrl V%d.%d\n\r", VersionInfo.Major, VersionInfo.Minor); |
SerialPutString(text); |
sprintf(msg,"NaviCtrl V%d.%d\n\r", VersionInfo.Major, VersionInfo.Minor); |
SerialPutString(msg); |
} |
//---------------------------------------------------------------------------------------------------- |
int main(void) |
{ |
static u8 oldCompassCalState = 0; |
u8 oldCompassCalState = 0; |
u8 kml_state = 0; |
u8 kml_count = 0; |
KML_Document_t mydocument; |
/* Configure the system clocks */ |
SCU_Config(); |
/* configure PLL and set it as master clock source */ |
SCU_MCLKSourceConfig(SCU_MCLK_OSC); // set master clock source to external oscillator clock (25MHz) before diabling the PLL |
SCU_PLLCmd(DISABLE); // now disable the PLL |
SCU_RCLKDivisorConfig(SCU_RCLK_Div1); // set RCLK (Reference Clock) divisor to 1 (full PPL clock) |
SCU_HCLKDivisorConfig(SCU_HCLK_Div1); // set HCLK (AHB bus clock) divisor to 1 (full Reference Clock) |
SCU_PCLKDivisorConfig(SCU_PCLK_Div2); // set PCLK (APB bus clock) divisor to 2 (half Reference Clock) |
//SCU_BRCLKDivisorConfig(SCU_BRCLK_Div2); // set BRCLK to MCLK/2 |
SCU_PLLFactorsConfig(192,25,3); // PLL = 48 MHz, Feedback Divider N=192, Pre-Divider M=25, Post-Divider P=3 |
SCU_PLLCmd(ENABLE); // Enable PLL (is disabled by SCU_PLLFactorsConfig) |
SCU_MCLKSourceConfig(SCU_MCLK_PLL); // set master clock source to PLL |
KML_DocumentInit(&mydocument); // Initialize the new kml-document for further use. |
/* Fill Version Info Structure */ |
VersionInfo.Major = VERSION_MAJOR; |
VersionInfo.Minor = VERSION_MINOR; |
123,113 → 143,135 |
Interrupt_Init(); |
// initialize timer 1 |
TIMER1_Init(); |
// initialize the LEDs |
// initialize the LEDs (needs Timer 1) |
Led_Init(); |
// initialize the debug UART1 |
UART1_Init(); |
OutputStartupData(); |
// initialize the uart to MKGPS module |
GPS_UART0_Init(); |
// iniitalize the gps position controller |
GPS_Init(); |
// initialize UART2 to FLIGHTCTRL |
//UART2_Init(); |
// initialize UART0 (to MKGPS or MK3MAG) |
UART0_Init(); |
// initialize usb |
USB_ConfigInit(); |
// initialize SPI0 to FC |
SPI0_Init(); |
// initialize i2c bus to MK3MAG |
I2C1_Init(); |
// initialize fat16 partition on sd card |
// initialize i2c bus to MK3MAG (needs Timer 1) |
I2C1_Init(); |
// initialize the gps position controller (needs Timer 1) |
GPS_Init(); |
// initialize fat16 partition on sd card (needs Timer 1) |
Fat16_Init(); |
// get version from MK3MAG |
I2C_Version.Major = 0xFF; |
SendI2C_Command(I2C_CMD_VERSION); |
I2C_Version.Minor = 0xFF; |
I2C_Version.Patch = 0xFF; |
I2C1_SendCommand(I2C_CMD_VERSION); |
TimerCompassUpdate = SetDelay(50); |
while (!CheckDelay(TimerCompassUpdate)); |
TimerCompassUpdate = SetDelay(5); |
TimerI2CReadDelay = SetDelay(5); |
TimerKmlAddPointDelay = SetDelay(250); |
SerialPutString("\r\n---------------------------------------------"); |
/* |
ReadSetting(1); |
*/ |
SerialPutString("Init done\n\r."); |
SerialPutString("--------------\n\n\r"); |
*/ |
SerialPutString("\r\n---------------------------------------------\r\n\r\n"); |
for (;;) |
{ |
if(rxd_buffer_locked) |
if(rxd_buffer_locked) // new incomming command |
{ |
UART1_ProcessRxData(); |
UART1_TransmitTxData(); |
UART1_ProcessRxData(); // process command |
UART1_TransmitTxData(); // send answer |
} |
UpdateSPI_Buffer(); |
SPI_CheckSlaveSelect(); |
UART1_Transmit(); // empty txd buffer |
// ----------- I2C Timing ------------------------- |
if (CheckDelay(TimerCompassUpdate)) |
{ |
if(oldCompassCalState != CompassCalState) |
{ |
oldCompassCalState = CompassCalState; |
TimerCompassUpdate = SetDelay(25); |
SendI2C_Command(I2C_CMD_WRITE_CAL); |
} |
else |
{ |
LED_GRN_TOGGLE; |
TimerCompassUpdate = SetDelay(25); |
SendI2C_Command(I2C_CMD_READ_HEADING); |
} |
// ------------------------- I2C Timing -------------------------------- |
if (CheckDelay(TimerCompassUpdate)) |
{ |
// check for hanging I2C bus |
if(CheckDelay(I2C1_Timeout)) |
{ // reset I2C |
I2C1_Deinit(); |
I2C1_Init(); |
} |
else |
{ |
if(oldCompassCalState != CompassCalState) |
{ |
oldCompassCalState = CompassCalState; |
TimerCompassUpdate = SetDelay(25); // every 25 ms |
I2C1_SendCommand(I2C_CMD_WRITE_CAL); |
} |
else |
{ |
TimerCompassUpdate = SetDelay(25); // every 25 ms |
I2C1_SendCommand(I2C_CMD_READ_HEADING); |
} |
} |
} |
} |
if (CheckDelay(TimerI2CReadDelay)) |
{ |
I2C1_ReadAnswer(); |
TimerI2CReadDelay = SetDelay(1000); |
} |
// ---------------- Debug Timing ---------------------------------- |
if (CheckDelay(TimerDebugDataDelay)) |
{ |
UART1_TransmitTxData(); |
TimerDebugDataDelay = SetDelay(500); |
} |
// ---------------- KML Timing ------------------------------------ |
if(CheckDelay(TimerKmlAddPointDelay)) |
{ |
TimerKmlAddPointDelay = SetDelay(500); |
switch(kml_state) |
{ |
case 0: |
if((GPSData.Status != INVALID) && (GPSData.Flags & FLAG_GPSFIXOK) && (GPSData.SatFix == SATFIX_3D)) |
{ |
if(KML_DocumentOpen("Flight01.kml",&mydocument)) // create a new kml-document on the memorycard. |
{ |
SerialPutString("\r\nopening kml-file\r\nadding data"); |
kml_state = 1; // goto next step |
} |
else |
{ |
SerialPutString("\r\nError opening kml-file"); |
// try to reinitialize the FAT16 |
if(0 != Fat16_Init()) TimerKmlAddPointDelay = SetDelay(5000); // try again in 5 sec |
} |
} |
break; // document.state will be changed to DOC_OPENED automatic. |
case 1: // linestring opened, so datapoint (gps_coordinates) can be added to the document. |
if(kml_count++ < 20) // add 10 datapoints to the document. |
{ |
KML_LoggGPSCoordinates(&GPSData, &mydocument); |
} |
else // after the datapoints have been written to the document close the document. |
{ |
KML_DocumentClose(&mydocument); |
SerialPutString("\r\nfile closed"); |
kml_state = 2; |
} |
break; |
if (CheckDelay(TimerI2CReadDelay)) |
{ |
if (I2C_ReadRequest) |
{ |
I2C_ReadRequest= 0; |
I2C_Direction = I2C_MODE_RECEIVER; |
I2C_GenerateStart(I2C1, ENABLE); |
default: |
break; // all data has been written to card. open new document to add new data. |
} |
} |
TimerI2CReadDelay = SetDelay(1000); |
} |
if (CheckDelay(TimerDebugDataDelay)) |
{ |
Request_GPS_Position = 1; |
UART1_TransmitTxData(); |
TimerDebugDataDelay = SetDelay(500); |
} |
// ---------------------------------------------------- |
} |
} |
} |
//________________________________________________________________________________________________________________________________________ |
// Funtion: EXTIT1_IRQHandler(void); |
// |
// Description: This function handles the external interrupts from port 5.3 (SD_SWITCH) |
// |
// |
// Returnvalue: none |
//________________________________________________________________________________________________________________________________________ |
void EXTIT1_IRQHandler(void) |
{ |
VIC_ITCmd(EXTIT1_ITLine, DISABLE); |
if(WIU_GetITStatus(WIU_Line11) != RESET) |
{ |
BeepTime = 100; |
Fat16_Init(); // initialize sd-card file system. |
WIU_ClearFlag(WIU_Line1); |
WIU_ClearITPendingBit(WIU_Line11); |
} |
VIC_ITCmd(EXTIT1_ITLine, ENABLE); |
} |
/branches/V0.1 killagreg/main.h |
---|
1,7 → 1,6 |
#ifndef _MAIN_H |
#define _MAIN_H |
#include "91x_lib.h" |
#define VERSION_MAJOR 0 |
#define VERSION_MINOR 1 |
9,19 → 8,31 |
extern u32 TimerCompassUpdate; |
extern u32 TimerI2CReadDelay; |
extern u8 BeepTime; |
extern u16 BeepTime; |
extern u8 ClearMKFlags; |
void Interrupt_Init(void); |
typedef struct |
{ |
u8 User1; |
u8 User2; |
u8 User3; |
u8 User4; |
u8 User5; |
u8 User6; |
u8 User7; |
u8 User8; |
u8 ActiveSetting; |
u8 User1; |
u8 User2; |
u8 User3; |
u8 User4; |
u8 User5; |
u8 User6; |
u8 User7; |
u8 User8; |
u8 NaviGpsModeControl; |
u8 NaviGpsGain; |
u8 NaviGpsP; |
u8 NaviGpsI; |
u8 NaviGpsD; |
u8 NaviGpsACC; |
u8 NaviGpsMinSat; |
u8 NaviStickThreshold; |
u8 NaviRadiusAlert; |
u8 LowVoltageWarning; |
} __attribute__((packed)) Param_t; |
typedef struct |
35,7 → 46,17 |
u8 Poti3; |
u8 Poti4; |
u8 RC_Quality; |
u8 MotorsOn; |
u8 UBat; |
// MK_Flags |
#define MKFLAG_MOTOR_RUN 0x01 |
#define MKFLAG_FLY 0x02 |
#define MKFLAG_CALIBRATE 0x04 |
#define MKFLAG_START 0x08 |
#define MKFLAG_EMERGENCY_LANDING 0x10 |
#define MKFLAG_RESERVE1 0x20 |
#define MKFLAG_RESERVE2 0x40 |
#define MKFLAG_RESERVE3 0x80 |
u8 MKFlags; |
} __attribute__((packed)) FC_t; |
/branches/V0.1 killagreg/menu.c |
---|
58,7 → 58,9 |
#include "91x_lib.h" |
#include "printf_P.h" |
#include "main.h" |
#include "GPSUart.h" |
#include "ubx.h" |
#include "GPS.h" |
#include "timer.h" |
#include "i2c.h" |
#include "spi_slave.h" |
#include "menu.h" |
91,9 → 93,9 |
// Display with 20 characters in 4 lines |
void LCD_PrintMenu(void) |
{ |
static u8 MaxMenuItem = 9; |
static u8 MaxMenuItem = 12; |
static u8 MenuItem=0; |
s16 i1,i2,i3; |
s32 i1,i2; |
// if KEY1 is activated goto previous menu item |
if(RemoteButtons & KEY1) |
{ |
132,10 → 134,10 |
case 1: |
if (GPSData.Status == INVALID) |
{ |
LCD_printfxy(0,0,"No GPS data! "); |
LCD_printfxy(0,1," "); |
LCD_printfxy(0,2," "); |
LCD_printfxy(0,3," "); |
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 |
{ |
154,26 → 156,24 |
LCD_printfxy(0,0,"Sats:%02d Fix:?? ", GPSData.NumOfSats); |
break; |
} |
i1 = (s16)(GPSData.Longitude/10000000L); |
i2 = abs((s16)((GPSData.Longitude%10000000L)/10000L)); |
i3 = abs((s16)(((GPSData.Longitude%10000000L)%10000L)/10L)); |
LCD_printfxy(0,1,"Lon: %3d.%.3d%.3d deg",i1, i2, i3); |
i1 = (s16)(GPSData.Latitude/10000000L); |
i2 = abs((s16)((GPSData.Latitude%10000000L)/10000L)); |
i3 = abs((s16)(((GPSData.Latitude%10000000L)%10000L)/10L)); |
LCD_printfxy(0,2,"Lat: %3d.%.3d%.3d deg",i1, i2, i3); |
i1 = (s16)(GPSData.Altitude/1000L); |
i2 = abs((s16)(GPSData.Altitude%1000L)); |
LCD_printfxy(0,3,"Alt: %3d.%.3d m",i1, i2); |
i1 = GPSData.Longitude/10000000L; |
i2 = abs(GPSData.Longitude%10000000L); |
LCD_printfxy(0,1,"Lon:%+3ld.%07ld deg",i1, i2); |
i1 = GPSData.Latitude/10000000L; |
i2 = abs(GPSData.Latitude%10000000L); |
LCD_printfxy(0,2,"Lat:%+3ld.%07ld deg",i1, i2); |
i1 = GPSData.Altitude/1000L; |
i2 = abs(GPSData.Altitude%1000L); |
LCD_printfxy(0,3,"Alt:%4ld.%03ld m",i1, i2); |
} |
break; |
case 2: |
if (GPSData.Status == INVALID) |
{ |
LCD_printfxy(0,0,"No GPS data! "); |
LCD_printfxy(0,1," "); |
LCD_printfxy(0,2," "); |
LCD_printfxy(0,3," "); |
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 |
{ |
192,64 → 192,91 |
LCD_printfxy(0,0,"Sats:%02d Fix:?? ", GPSData.NumOfSats); |
break; |
} |
i1 = (s16)(GPSData.Speed_North); |
i2 = (s16)(GPSData.Speed_East); |
i3 = (s16)(GPSData.Speed_Top); |
LCD_printfxy(0,1,"Speed N: %4i cm/s",i1); |
LCD_printfxy(0,2,"Speed E: %4i cm/s",i2); |
LCD_printfxy(0,3,"Speed T: %4i cm/s",i3); |
LCD_printfxy(0,1,"Speed N: %+4ld cm/s",GPSData.Speed_North); |
LCD_printfxy(0,2,"Speed E: %+4ld cm/s",GPSData.Speed_East); |
LCD_printfxy(0,3,"Speed T: %+4ld cm/s",GPSData.Speed_Top); |
} |
break; |
case 3: |
LCD_printfxy(0,0,"GPS UTC Time"); |
if (!SystemTime.Valid) |
{ |
LCD_printfxy(0,0,"No GPS time data!"); |
LCD_printfxy(0,0,"GPS UTC Time"); |
LCD_printfxy(0,1," "); |
LCD_printfxy(0,2," "); |
LCD_printfxy(0,2," No time data! "); |
LCD_printfxy(0,3," "); |
} |
else // newdata or processed |
{ |
LCD_printfxy(0,0,"GPS UTC Time: "); |
LCD_printfxy(0,1,""); |
LCD_printfxy(0,2,"Date: %02i/%02i/%04i ",SystemTime.Month, SystemTime.Day, SystemTime.Year); |
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; |
case 4: // RC stick controls from FC |
case 4: // Navi Params from FC |
LCD_printfxy(0,0,"NaviMode: %3i" , Parameter.NaviGpsModeControl); |
LCD_printfxy(0,1,"G :%3i P :%3i ",Parameter.NaviGpsGain, Parameter.NaviGpsP); |
LCD_printfxy(0,2,"I :%3i D :%3i ",Parameter.NaviGpsI, Parameter.NaviGpsD); |
LCD_printfxy(0,3,"ACC:%3i SAT:%3i ",Parameter.NaviGpsACC, Parameter.NaviGpsMinSat); |
break; |
case 5: |
LCD_printfxy(0,0,"Home Position"); |
if(GPSHomePosition.Status == INVALID) |
{ |
LCD_printfxy(0,1," "); |
LCD_printfxy(0,2," Is not set. "); |
LCD_printfxy(0,3," "); |
} |
else |
{ |
i1 = GPSHomePosition.Longitude/10000000L; |
i2 = abs(GPSHomePosition.Longitude%10000000L); |
LCD_printfxy(0,1,"Lon: %3ld.%07ld deg",i1, i2); |
i1 = GPSHomePosition.Latitude/10000000L; |
i2 = abs(GPSHomePosition.Latitude%10000000L); |
LCD_printfxy(0,2,"Lat: %3ld.%07ld deg",i1, i2); |
i1 = GPSHomePosition.Altitude/1000L; |
i2 = abs(GPSHomePosition.Altitude%1000L); |
LCD_printfxy(0,3,"Alt:%4ld.%03ld m",i1, i2); |
} |
break; |
case 6: // RC stick controls from FC |
LCD_printfxy(0,0,"RC-Sticks" ); |
LCD_printfxy(0,1,"Ni:%4i Ro:%4i ",FC.StickNick, FC.StickRoll); |
LCD_printfxy(0,2,"Gs:%4i Ya:%4i ",FC.StickGas, FC.StickYaw); |
break; |
case 5: // RC poti controls from FC |
case 7: // RC poti controls from FC |
LCD_printfxy(0,0,"RC-Potis" ); |
LCD_printfxy(0,1,"Po1:%3i Po2:%3i ",FC.Poti1, FC.Poti2); |
LCD_printfxy(0,2,"Po3:%3i Po4:%3i ",FC.Poti3, FC.Poti4); |
break; |
case 6: // attitude from FC |
case 8: // attitude from FC |
LCD_printfxy(0,0,"IntNick: %5i", FromFlightCtrl.IntegralNick); |
LCD_printfxy(0,1,"IntRoll: %5i", FromFlightCtrl.IntegralRoll); |
LCD_printfxy(0,2,"AccNick: %5i", FromFlightCtrl.AccNick); |
LCD_printfxy(0,3,"AccRoll: %5i", FromFlightCtrl.AccRoll); |
break; |
case 7: // gyros from FC |
case 9: // gyros from FC |
LCD_printfxy(0,0,"GyroNick: %4i", FromFlightCtrl.GyroNick); |
LCD_printfxy(0,1,"GyroRoll: %4i", FromFlightCtrl.GyroRoll); |
LCD_printfxy(0,2,"GyroYaw: %4i", FromFlightCtrl.GyroYaw); |
break; |
case 8: // Remote Control Level from FC |
case 10: // Remote Control Level from FC |
LCD_printfxy(0,0,"RC-Level: %3i", FC.RC_Quality); |
LCD_printfxy(0,1,"Motors On: %1i", FC.MotorsOn); |
LCD_printfxy(0,1,"Ubat: %3i", FC.UBat); |
LCD_printfxy(0,2,"CompHeading: %3i", I2C_Heading.Heading); |
LCD_printfxy(0,3,"GyroHeading: %3i", FromFlightCtrl.GyroHeading); |
break; |
case 9: // User Parameter |
case 11: // User Parameter |
LCD_printfxy(0,0,"UP1:%3i UP2:%3i ",Parameter.User1,Parameter.User2); |
LCD_printfxy(0,1,"UP3:%3i UP4:%3i ",Parameter.User3,Parameter.User4); |
LCD_printfxy(0,2,"UP5:%3i UP6:%3i ",Parameter.User5,Parameter.User6); |
LCD_printfxy(0,3,"UP7:%3i UP8:%3i ",Parameter.User7,Parameter.User8); |
break; |
case 12: // MK3MAG |
LCD_printfxy(0,0,"MK3MAG V%i.%i.%i",I2C_Version.Major,I2C_Version.Minor, I2C_Version.Patch); |
break; |
default: |
MaxMenuItem = MenuItem - 1; |
MenuItem = 0; |
/branches/V0.1 killagreg/menu.h |
---|
1,7 → 1,6 |
#ifndef _MENU_H |
#define _MENU_H |
#include "91x_lib.h" |
#define DISPLAYBUFFSIZE 80 |
/branches/V0.1 killagreg/printf_P.c |
---|
88,7 → 88,7 |
#else |
#include <varargs.h> |
#endif |
#include "91x_lib.h" |
#include "menu.h" |
/branches/V0.1 killagreg/sdc.c |
---|
57,10 → 57,10 |
#include <stdio.h> |
#include <string.h> |
#include "91x_lib.h" |
#include "uart.h" |
#include "timer.h" |
#include "uart1.h" |
#include "sdc.h" |
#include "ssc.h" |
#include "timer.h" |
#include "main.h" |
#include "crc16.h" |
68,7 → 68,7 |
// Module name: sdc.c |
// Compiler used: avr-gcc 3.4.5 |
// Last Modifikation: 08.06.2008 |
// Version: 1.06 |
// Version: 1.07 |
// Authors: Stephan Busker, Gregor Stobrawa |
// Description: Source files for connecting to an sd-card using the SSC |
// |
181,8 → 181,26 |
return(crc); |
} |
u8 SDC_WaitForBusy(u32 timeout) |
{ |
u8 rsp = 0; |
u32 timestamp = 0; |
SSC_ClearRxFifo(); |
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_SendCMD(u8 CmdNo, u32 arg); |
// Function: SDC_SendCMDR1(u8 CmdNo, u32 arg); |
// |
// Description: This function send a command frame to the SD-Card in spi-mode. |
// |
189,27 → 207,17 |
// |
// Returnvalue: The function returns the first response byte like for R1 commands |
//________________________________________________________________________________________________________________________________________ |
u8 SDC_SendCMD(u8 CmdNo, u32 arg) |
u8 SDC_SendCMDR1(u8 CmdNo, u32 arg) |
{ |
u8 r1; |
u32 Timeout = 0; |
u16 timeout = 0; |
u16 a; |
u8 cmd[6]; |
SSC_ClearRxFifo(); // clear the rx fifo |
SSC_Enable(); // enable chipselect. |
// wait if card is busy |
Timeout = SetDelay(1000); |
do |
{ |
r1 = SSC_GetChar(); |
if (CheckDelay(Timeout)) |
{ |
return(r1); |
} |
}while(r1 != 0xFF); |
SDC_WaitForBusy(500); // wait 500ms until card is busy |
SSC_ClearRxFifo(); // clear the rx fifo |
SSC_GetChar(); // dummy to sync |
cmd[0] = 0x40|CmdNo; // set command index |
223,11 → 231,11 |
SSC_PutChar(cmd[a]); |
} |
SSC_ClearRxFifo(); // clear the rx fifo to discard the bytes received during the transmission of the 6 command bytes |
Timeout = SetDelay(50); |
do |
{ |
r1 = SSC_GetChar(); // get byte from sd-card |
if (CheckDelay(Timeout)) break; |
if (timeout++ >500) break; |
}while(r1 == 0xFF); // wait for the response byte from sd-card. |
return(r1); |
} |
235,7 → 243,7 |
//________________________________________________________________________________________________________________________________________ |
// Function: SDC_SendACMDR1(u8 CmdNo, u32 arg); |
// |
// |
// Description: This function send a application command frame to the SD-Card in spi-mode. |
// |
// |
243,10 → 251,10 |
//________________________________________________________________________________________________________________________________________ |
u8 SDC_SendACMDR1(u8 CmdNo, u32 arg) |
{ |
u8 r1; |
r1 = SDC_SendCMD(CMD_APP_CMD, 0UL); |
u8 r1 = 0xFF; |
r1 = SDC_SendCMDR1(CMD_APP_CMD, 0UL); |
if(r1 & R1_BAD_RESPONSE) return(r1); |
r1 = SDC_SendCMD(CmdNo, arg); |
r1 = SDC_SendCMDR1(CmdNo, arg); |
return(r1); |
} |
263,12 → 271,11 |
SD_Result_t SDC_GetData(u8 CmdNo, u32 addr, u8 *Buffer, u32 len) |
{ |
u8 rsp; |
u32 Timeout; |
u16 a, Crc16; |
u16 a, crc16; |
SD_Result_t result = SD_ERROR_UNKNOWN; |
// send the command |
rsp = SDC_SendCMD(CmdNo, addr); |
rsp = SDC_SendCMDR1(CmdNo, addr); |
if (rsp != R1_NO_ERR) |
{ |
result = SD_ERROR_BAD_RESPONSE; |
275,7 → 282,6 |
goto end; |
} |
SSC_ClearRxFifo(); |
Timeout = SetDelay(200); |
do |
{ |
rsp = SSC_GetChar(); |
284,11 → 290,6 |
result = SD_ERROR_READ_DATA; |
goto end; |
} |
if (CheckDelay(Timeout)) |
{ |
result = SD_ERROR_TIMEOUT; |
goto end; |
} |
}while(rsp != DATA_START_TOKEN); |
// data start token received |
for (a = 0; a < len; a++) // read the block from the SSC |
296,10 → 297,10 |
Buffer[a] = SSC_GetChar(); |
} |
// Read two bytes CRC16-Data checksum |
Crc16 = SSC_GetChar(); // highbyte fisrt |
Crc16 = (Crc16<<8)|SSC_GetChar(); // lowbyte last |
if(Crc16 != CRC16(Buffer, len)) result = SD_ERROR_CRC_DATA; |
else result = SD_SUCCESS; |
crc16 = SSC_GetChar(); // highbyte fisrt |
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) |
391,16 → 392,18 |
SD_Result_t SDC_Init(void) |
{ |
u32 Timeout = 0; |
u32 timeout = 0; |
u8 text[50]; |
u8 rsp[6]; // SD-SPI response buffer |
SD_Result_t result = SD_ERROR_UNKNOWN; |
SerialPutString("SDC init..."); |
if(SD_SWITCH) // init only if the SD-Switch is indicating a card in the slot |
{ |
SerialPutString("\r\n SSC init..."); |
SSC_Init(); |
SerialPutString("ok"); |
SerialPutString("\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 |
408,37 → 411,36 |
SSC_Disable(); // set SD_CS high |
SSC_ClearRxFifo(); // clear the rx fifo |
for (Timeout = 0; Timeout < 15; Timeout++) // 15*8 = 120 cycles |
for (timeout = 0; timeout < 15; timeout++) // 15*8 = 120 cycles |
{ |
SSC_PutChar(0xFF); |
} |
// switch to idle state |
Timeout = SetDelay(200); |
while(SDC_SendCMD(CMD_GO_IDLE_STATE, 0UL) != R1_IDLE_STATE) |
while(SDC_SendCMDR1(CMD_GO_IDLE_STATE, 0UL) != R1_IDLE_STATE) |
{ |
if (CheckDelay(Timeout)) |
if (timeout++ > 20) |
{ |
SerialPutString("reset timeout.\r\n"); |
SerialPutString("reset timeout"); |
result = SD_ERROR_RESET; |
goto end; |
} |
} |
// enable crc feature |
if(SDC_SendCMD(CMD_CRC_ON_OFF, 1UL) != R1_IDLE_STATE) |
/* if(SDC_SendCMDR1(CMD_CRC_ON_OFF, 1UL) != R1_IDLE_STATE) |
{ |
sprintf(text,"Bad cmd59 R1=%02X.\r\n", rsp[0]); |
sprintf(text,"Bad cmd59 R1=%02X.", rsp[0]); |
SerialPutString(text); |
result = SD_ERROR_BAD_RESPONSE; |
goto end; |
} |
}*/ |
// check for card hw version |
// 2.7-3.6V Range = 0x01, check pattern 0xAA |
rsp[0] = SDC_SendCMD(CMD_SEND_IF_COND, 0x000001AA); |
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) |
{ |
sprintf(text,"Bad cmd8 R1=%02X.\r\n", rsp[0]); |
sprintf(text,"Bad cmd8 R1=%02X.", rsp[0]); |
SerialPutString(text); |
result = SD_ERROR_BAD_RESPONSE; |
goto end; |
453,9 → 455,9 |
// 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++) |
for(timeout = 1; timeout < 5; timeout++) |
{ |
rsp[Timeout] = SSC_GetChar(); |
rsp[timeout] = SSC_GetChar(); |
} |
//check pattern |
if(rsp[4]!= 0xAA) |
473,11 → 475,11 |
} |
} |
rsp[0] = SDC_SendCMD(CMD_READ_OCR, 0UL); |
rsp[0] = SDC_SendCMDR1(CMD_READ_OCR, 0UL); |
// answer to cmd58 is an R3 response (R1 + 4Byte OCR) |
if(rsp[0] & R1_BAD_RESPONSE) |
{ |
sprintf(text,"Bad cmd58 R1 %02x.\r\n", rsp[0]); |
sprintf(text,"Bad cmd58 R1 %02x.", rsp[0]); |
SerialPutString(text); |
result = SD_ERROR_BAD_RESPONSE; |
goto end; |
484,39 → 486,39 |
} |
if(rsp[0] & R1_ILLEGAL_CMD) |
{ |
SerialPutString("Not an SD-CARD.\r\n"); |
SerialPutString("Not an SD-CARD."); |
result = SD_ERROR_NO_SDCARD; |
goto end; |
} |
// read 4 bytes of OCR register |
for(Timeout = 1; Timeout < 5; Timeout++) |
for(timeout = 1; timeout < 5; timeout++) |
{ |
rsp[Timeout] = SSC_GetChar(); |
rsp[timeout] = SSC_GetChar(); |
} |
// NavicCtrl uses 3.3 V, therefore check for bit 20 & 21 |
if((rsp[2] & 0x30) != 0x30) |
{ |
// supply voltage is not supported by sd-card |
SerialPutString("Card is incompatible to 3.3V.\r\n"); |
SerialPutString("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(1000); |
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) |
{ |
sprintf(text,"Bad Acmd41 R1=%02X.\r\n", rsp[0]); |
sprintf(text,"Bad Acmd41 R1=%02X.", rsp[0]); |
SerialPutString(text); |
result = SD_ERROR_BAD_RESPONSE; |
goto end; |
} |
if(CheckDelay(Timeout)) |
if(CheckDelay(timeout)) |
{ |
SerialPutString("Init timeout.\r\n"); |
SerialPutString("Init timeout."); |
result = SD_ERROR_INITIALIZE; |
goto end; |
} |
524,19 → 526,21 |
if(rsp[0] != R1_NO_ERR) |
{ |
SerialPutString("Init error.\r\n"); |
SerialPutString("Init error."); |
result = SD_ERROR_INITIALIZE; |
goto end; |
} |
/* set block size to 512 bytes */ |
if(SDC_SendCMD(CMD_SET_BLOCKLEN, 512UL) != R1_NO_ERR) |
if(SDC_SendCMDR1(CMD_SET_BLOCKLEN, 512UL) != R1_NO_ERR) |
{ |
SerialPutString("Error setting block length to 512.\r\n"); |
SerialPutString("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 boud rate to maximum |
//SSC_Enable(); // set SD_CS high |
// read CID register |
result = SDC_GetCID((u8 *)&SDCardInfo.CID); |
550,7 → 554,7 |
result = SDC_GetCSD((u8 *)&SDCardInfo.CSD); |
if(result != SD_SUCCESS) |
{ |
SerialPutString("Error reading CSD.\r\n"); |
SerialPutString("Error reading CSD."); |
goto end; |
} |
604,19 → 608,22 |
switch(SDCardInfo.Version) |
{ |
case VER_1X: |
SerialPutString("SD-CARD V1.x\r\n"); |
SerialPutString(" SD-CARD V1.x"); |
break; |
case VER_20: |
SerialPutString("SD-CARD V2.0 or later\r\n"); |
SerialPutString(" SD-CARD V2.0 or later"); |
default: |
break; |
} |
u16 mb_size = (u16)(SDCardInfo.Capacity/(1024L*1024L)); |
sprintf(text, "Capacity = %i MB\r\n", mb_size); |
sprintf(text, "\r\n Capacity = %i MB", mb_size); |
SerialPutString(text); |
SDC_PrintCID((u8 *)&SDCardInfo.CID); |
SDCardInfo.Valid = 1; |
// jump point for error condition before |
end: |
SSC_Disable(); |
} |
else |
{ |
623,10 → 630,8 |
SSC_Deinit(); |
SDCardInfo.Valid = 0; |
result = SD_ERROR_NOCARD; |
SerialPutString("No Card in Slot.\r\n"); |
SerialPutString("No Card in Slot."); |
} |
// jump point for error condition before |
end: |
return(result); |
} |
642,7 → 647,7 |
SD_Result_t SDC_Deinit(void) |
{ |
SerialPutString("SDC deinit..."); |
SerialPutString("\r\n SDC deinit..."); |
SSC_Deinit(); |
SDCardInfo.Valid = 0; |
649,7 → 654,7 |
SDCardInfo.Capacity = 0; |
SDCardInfo.Version = VER_UNKNOWN; |
SerialPutString("ok\r\n"); |
SerialPutString("ok"); |
return(SD_SUCCESS); |
} |
666,12 → 671,12 |
SD_Result_t SDC_PutSector(u32 addr, const u8 *Buffer) |
{ |
u8 rsp; |
u16 a, Crc16; |
u32 Timeout = 0; |
u16 a, crc16; |
u16 timeout = 0; |
SD_Result_t result = SD_ERROR_UNKNOWN; |
addr = addr << 9; // convert sectoradress to byteadress |
rsp = SDC_SendCMD(CMD_WRITE_SINGLE_BLOCK, addr); |
rsp = SDC_SendCMDR1(CMD_WRITE_SINGLE_BLOCK, addr); |
if (rsp != R1_NO_ERR) |
{ |
result = SD_ERROR_BAD_RESPONSE; |
678,11 → 683,11 |
goto end; |
} |
SSC_ClearRxFifo(); |
for (a=0;a<100;a++) // at least one byte |
for (a=0;a<20;a++) // at least one byte |
{ |
SSC_GetChar(); |
} |
Crc16 = CRC16(Buffer, 512); // calc checksum for data block |
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. |
690,14 → 695,13 |
SSC_PutChar(Buffer[a]); |
} |
// write two bytes of crc16 to the sdcard |
SSC_PutChar((u8)(Crc16>>8)); // write high byte first |
SSC_PutChar((u8)(0x00FF&Crc16)); // lowbyte last |
SSC_PutChar((u8)(crc16>>8)); // write high byte first |
SSC_PutChar((u8)(0x00FF&crc16)); // lowbyte last |
SSC_ClearRxFifo(); |
Timeout = SetDelay(500); |
do // wait for data response token |
{ |
rsp = SSC_GetChar(); |
if(CheckDelay(Timeout)) |
if(timeout++ > 500) |
{ |
result = SD_ERROR_TIMEOUT; |
goto end; |
723,19 → 727,16 |
break; |
} |
// wait until the sdcard is busy. |
Timeout = SetDelay(1000); |
do |
// wait 2 seconds until the sdcard is busy. |
rsp = SDC_WaitForBusy(2000); |
if(rsp != 0xFF) |
{ |
rsp = SSC_GetChar(); |
if (CheckDelay(Timeout)) |
{ |
result = SD_ERROR_TIMEOUT; |
goto end; |
} |
}while(rsp != 0xFF); |
result = SD_ERROR_TIMEOUT; |
goto end; |
} |
// check card status |
rsp = SDC_SendCMD(CMD_SEND_STATUS, 0); |
rsp = SDC_SendCMDR1(CMD_SEND_STATUS, 0); |
// first byte of R2 response is like R1 response |
if(rsp != R1_NO_ERR) |
{ |
/branches/V0.1 killagreg/sdc.h |
---|
1,7 → 1,6 |
#ifndef _SDC_H |
#define _SDC_H |
#include "91x_lib.h" |
//________________________________________________________________________________________________________________________________________ |
// |
/branches/V0.1 killagreg/settings.c |
---|
60,7 → 60,7 |
#include "91x_lib.h" |
#include "fat16.h" |
#include "settings.h" |
#include "uart.h" |
#include "uart1.h" |
struct str_setting_parameter CFG_Parameter[] = |
{ |
/branches/V0.1 killagreg/spi_slave.c |
---|
58,9 → 58,9 |
#include <string.h> |
#include "91x_lib.h" |
#include "led.h" |
#include "GPSUart.h" |
//#include "GPSUart.h" |
#include "GPS.h" |
#include "uart.h" |
#include "uart1.h" |
#include "spi_slave.h" |
#include "i2c.h" |
#include "timer.h" |
79,8 → 79,8 |
} SPI_State_t; |
//communication packets |
FromFlightCtrl_t FromFlightCtrl; |
ToFlightCtrl_t ToFlightCtrl; |
volatile FromFlightCtrl_t FromFlightCtrl; |
volatile ToFlightCtrl_t ToFlightCtrl; |
// tx packet buffer |
#define SPI_TXBUFFER_LEN (2 + sizeof(ToFlightCtrl)) // 2 bytes at start are for synchronization |
210,7 → 210,7 |
GPIO_InitTypeDef GPIO_InitStructure; |
SSP_InitTypeDef SSP_InitStructure; |
SerialPutString("SPI init..."); |
SerialPutString("\r\n SPI init..."); |
SCU_APBPeriphClockConfig(__GPIO2 ,ENABLE); |
SCU_APBPeriphClockConfig(__SSP0 ,ENABLE); |
217,6 → 217,7 |
GPIO_DeInit(GPIO2); |
//SSP0_CLK, SSP0_MOSI, SSP0_NSS pins |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinInput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ; |
225,6 → 226,7 |
GPIO_Init (GPIO2, &GPIO_InitStructure); |
// SSP0_MISO pin GPIO2.6 |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ; |
255,33 → 257,21 |
VIC_Config(SSP0_ITLine, VIC_IRQ, 1); |
VIC_ITCmd(SSP0_ITLine, ENABLE); |
SerialPutString("ok\n\r"); |
SerialPutString("ok"); |
} |
//------------------------------------------------------ |
void SPI_CheckSlaveSelect(void) |
{ |
DebugOut.Analog[0] = FromFlightCtrl.IntegralNick; |
DebugOut.Analog[1] = FromFlightCtrl.IntegralRoll; |
DebugOut.Analog[2] = (30*FromFlightCtrl.AccNick)/108; |
DebugOut.Analog[3] = (30*FromFlightCtrl.AccRoll)/108; |
DebugOut.Analog[25] = FromFlightCtrl.GyroHeading; |
} |
//------------------------------------------------------ |
void UpdateSPI_Buffer(void) |
{ |
if (SPI_RxBuffer_Request) |
{ |
if (CompassUpdateActiv) return; // testweise deaktiviert |
// avoid sending data via SPI during the update of the ToFlightCtrl structure |
VIC_ITCmd(SSP0_ITLine, DISABLE); // disable SPI interrupt |
ToFlightCtrl.CompassHeading = I2C_Heading.Heading; |
ToFlightCtrl.GPS_Nick = GPSStick.Nick; |
ToFlightCtrl.GPS_Roll = GPSStick.Roll; |
ToFlightCtrl.GPS_Yaw = GPSStick.Yaw; |
ToFlightCtrl.GPS_Nick = GPS_Stick.Nick; |
ToFlightCtrl.GPS_Roll = GPS_Stick.Roll; |
ToFlightCtrl.GPS_Yaw = GPS_Stick.Yaw; |
DebugOut.Analog[26] = I2C_Heading.Heading; |
// cycle spi commands |
ToFlightCtrl.Command = SPI_CommandSequence[SPI_CommandCounter++]; |
300,8 → 290,24 |
break; |
case SPI_CMD_GPS_TARGET: |
ToFlightCtrl.Param.Long[0] = GPSTargetPosition.Longitude; |
ToFlightCtrl.Param.Long[1] = GPSTargetPosition.Latitude; |
if(pTargetPosition != NULL) |
{ |
if(pTargetPosition->Status != INVALID) |
{ |
ToFlightCtrl.Param.Long[0] = pTargetPosition->Longitude; |
ToFlightCtrl.Param.Long[1] = pTargetPosition->Latitude; |
} |
else |
{ |
ToFlightCtrl.Param.Long[0] = 0; |
ToFlightCtrl.Param.Long[1] = 0; |
} |
} |
else |
{ |
ToFlightCtrl.Param.Long[0] = 0; |
ToFlightCtrl.Param.Long[1] = 0; |
} |
break; |
default: |
309,7 → 315,7 |
} |
VIC_ITCmd(SSP0_ITLine, ENABLE); // enable SPI interrupt |
if (I2C_Heading.Heading <= 359) |
/* if (I2C_Heading.Heading <= 359) |
{ |
// nothing? |
} |
317,7 → 323,7 |
{ |
if (I2C_Version.Major != 0xFF) TimerCompassUpdate = SetDelay(1); |
return; |
} |
}*/ |
switch(FromFlightCtrl.Command) |
{ |
330,9 → 336,31 |
Parameter.User6 = FromFlightCtrl.Param.Byte[5]; |
Parameter.User7 = FromFlightCtrl.Param.Byte[6]; |
Parameter.User8 = FromFlightCtrl.Param.Byte[7]; |
if(ClearMKFlags) |
{ |
FC.MKFlags = 0; |
ClearMKFlags = 0; |
} |
FC.MKFlags |= FromFlightCtrl.Param.Byte[8]; |
FC.UBat = FromFlightCtrl.Param.Byte[9]; |
Parameter.LowVoltageWarning = FromFlightCtrl.Param.Byte[10]; |
Parameter.ActiveSetting = FromFlightCtrl.Param.Byte[11]; |
break; |
case SPI_CMD_PARAMETER1: |
Parameter.NaviGpsModeControl = FromFlightCtrl.Param.Byte[0]; |
Parameter.NaviGpsGain = FromFlightCtrl.Param.Byte[1]; |
Parameter.NaviGpsP = FromFlightCtrl.Param.Byte[2]; |
Parameter.NaviGpsI = FromFlightCtrl.Param.Byte[3]; |
Parameter.NaviGpsD = FromFlightCtrl.Param.Byte[4]; |
Parameter.NaviGpsACC = FromFlightCtrl.Param.Byte[5]; |
Parameter.NaviGpsMinSat = FromFlightCtrl.Param.Byte[6]; |
Parameter.NaviStickThreshold = FromFlightCtrl.Param.Byte[7]; |
Parameter.NaviRadiusAlert = FromFlightCtrl.Param.Byte[8]; |
break; |
case SPI_CMD_STICK: |
FC.StickGas = FromFlightCtrl.Param.sByte[0]; |
FC.StickGas = FromFlightCtrl.Param.sByte[0]; |
FC.StickYaw = FromFlightCtrl.Param.sByte[1]; |
FC.StickRoll = FromFlightCtrl.Param.sByte[2]; |
FC.StickNick = FromFlightCtrl.Param.sByte[3]; |
341,7 → 369,6 |
FC.Poti3 = FromFlightCtrl.Param.Byte[6]; |
FC.Poti4 = FromFlightCtrl.Param.Byte[7]; |
FC.RC_Quality = FromFlightCtrl.Param.Byte[8]; |
FC.MotorsOn = FromFlightCtrl.Param.Byte[9]; |
break; |
case SPI_CMD_CAL_COMPASS: |
358,9 → 385,17 |
I2C_WriteAttitude.Nick = FromFlightCtrl.IntegralNick; |
// every time we got new data from the FC via SPI call the navigation routine |
Navigation(); |
GPS_Navigation(); |
ClearMKFlags = 1; |
SPI_RxBuffer_Request = 0; |
DebugOut.Analog[0] = FromFlightCtrl.IntegralNick; |
DebugOut.Analog[1] = FromFlightCtrl.IntegralRoll; |
DebugOut.Analog[2] = (30*FromFlightCtrl.AccNick)/108; |
DebugOut.Analog[3] = (30*FromFlightCtrl.AccRoll)/108; |
DebugOut.Analog[25] = FromFlightCtrl.GyroHeading; |
} |
} |
/branches/V0.1 killagreg/spi_slave.h |
---|
1,14 → 1,14 |
#ifndef _SPI_SLAVE_H |
#define _SPI_SLAVE_H |
#define SS_PIN GPIO_ReadBit(GPIO2, GPIO_Pin_7) |
#define SPI_PROTOCOL_COMP 1 |
#define SS_PIN GPIO_ReadBit(GPIO2, GPIO_Pin_7) |
#define SPI_CMD_USER 10 |
#define SPI_CMD_STICK 11 |
#define SPI_CMD_CAL_COMPASS 12 |
#define SPI_CMD_PARAMETER1 13 |
typedef struct |
{ |
44,7 → 44,7 |
s16 GPS_Yaw; |
s16 CompassHeading; |
s16 Status; |
u8 BeepTime; |
u16 BeepTime; |
union |
{ |
s8 sByte[12]; |
56,11 → 56,10 |
u8 Chksum; |
} __attribute__((packed)) ToFlightCtrl_t; |
extern FromFlightCtrl_t FromFlightCtrl; |
extern ToFlightCtrl_t ToFlightCtrl; |
extern volatile FromFlightCtrl_t FromFlightCtrl; |
extern volatile ToFlightCtrl_t ToFlightCtrl; |
extern void SPI0_Init(void); |
extern void SPI_CheckSlaveSelect(void); |
extern void UpdateSPI_Buffer(void); |
#endif //_SPI_SLAVE_H |
/branches/V0.1 killagreg/ssc.c |
---|
126,6 → 126,7 |
// enable APB clock for SPI1 |
SCU_APBPeriphClockConfig(__SSP1 ,ENABLE); |
// configure P5.4 -> SD-CS as an output pin |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ; |
133,6 → 134,7 |
GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt1; |
GPIO_Init (GPIO5, &GPIO_InitStructure); |
// configure P3.4 -> SCK1 and P3.6 -> MOSI1 as an output pin |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_6; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ; |
140,6 → 142,7 |
GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt2; |
GPIO_Init (GPIO3, &GPIO_InitStructure); |
// configure P3.5 <- MISO1 as an input pin |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinInput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull; |
/branches/V0.1 killagreg/ssc.h |
---|
2,7 → 2,6 |
#define _SSC_H |
#include "91x_lib.h" |
//________________________________________________________________________________________________________________________________________ |
// |
// Functions needed for accessing the sdcard low level via SPI. |
/branches/V0.1 killagreg/timer.c |
---|
56,7 → 56,7 |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
#include "91x_lib.h" |
#include "timer.h" |
#include "uart.h" |
#include "uart1.h" |
u32 CountMilliseconds; |
DateTime_t SystemTime; |
64,11 → 64,14 |
//---------------------------------------------------------------------------------------------------- |
void TIM1_IRQHandler(void) |
{ |
TIM1->OC1R += 200; // Timerfreq is 200kHz, generate an interrupt every 1ms |
CountMilliseconds++; |
//if (GPIO_ReadBit(GPIO6, GPIO_Pin_3)) GPIO_WriteBit(GPIO6, GPIO_Pin_3, Bit_RESET); else GPIO_WriteBit(GPIO6, GPIO_Pin_3, Bit_SET); |
TIM_ClearFlag(TIM1, TIM_FLAG_OC1); // clear irq pending bit |
TIM_ClearFlag(TIM1, TIM_FLAG_OC1); // clear irq pending bit |
TIM1->OC1R += 200; // Timerfreq is 200kHz, generate an interrupt every 1ms |
CountMilliseconds++; |
//if (GPIO_ReadBit(GPIO6, GPIO_Pin_3)) GPIO_WriteBit(GPIO6, GPIO_Pin_3, Bit_RESET); else GPIO_WriteBit(GPIO6, GPIO_Pin_3, Bit_SET); |
// write any value to VIC0 Vector address register |
VIC0->VAR = 0xFF; |
} |
//---------------------------------------------------------------------------------------------------- |
/branches/V0.1 killagreg/timer.h |
---|
1,6 → 1,7 |
#ifndef _TIMER_H |
#define _TIMER_H |
typedef struct{ |
u16 Year; |
u8 Month; |
/branches/V0.1 killagreg/uart0.c |
---|
0,0 → 1,267 |
/*#######################################################################################*/ |
/* !!! 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 "91x_lib.h" |
#include "uart1.h" |
#include "ubx.h" |
//------------------------------------------------------------------------------------ |
// global variables |
// UART0 MUXER |
typedef enum |
{ |
UART0_UNDEF, |
UART0_MK3MAG, |
UART0_MKGPS |
} UART0_MuxerState_t; |
UART0_MuxerState_t UART0_Muxer = UART0_UNDEF; |
//------------------------------------------------------------------------------------ |
// functions |
/********************************************************/ |
/* Connect RXD & TXD to GPS */ |
/********************************************************/ |
void UART0_Connect_to_MKGPS(void) |
{ |
GPIO_InitTypeDef GPIO_InitStructure; |
UART0_Muxer = UART0_UNDEF; |
SCU_APBPeriphClockConfig(__GPIO6, ENABLE); // Enable the GPIO6 Clock |
// unmap UART0 from Compass |
// set port pin 5.1 (serial data from compass) to input and disconnect from IP |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinInput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ; |
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Disable; |
GPIO_InitStructure.GPIO_Alternate = GPIO_InputAlt1; |
GPIO_Init(GPIO5, &GPIO_InitStructure); |
// set port pin 5.0 (serial data to compass) to input |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinInput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull; |
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Disable; |
GPIO_InitStructure.GPIO_Alternate = GPIO_InputAlt1; |
GPIO_Init(GPIO5, &GPIO_InitStructure); |
// map UART0 to GPS |
// set port pin 6.6 (serial data from gps) to input and connect to IP |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinInput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ; |
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable; |
GPIO_InitStructure.GPIO_Alternate = GPIO_InputAlt1; //UART0_RxD |
GPIO_Init(GPIO6, &GPIO_InitStructure); |
// set port pin 6.7 (serial data to gps) to output |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull; |
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable; |
GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt3; //UART0_TX |
GPIO_Init(GPIO6, &GPIO_InitStructure); |
UART0_Muxer = UART0_MKGPS; |
} |
/********************************************************/ |
/* Connect RXD & TXD to MK3MAG */ |
/********************************************************/ |
void UART0_Connect_to_MK3MAG(void) |
{ |
GPIO_InitTypeDef GPIO_InitStructure; |
UART0_Muxer = UART0_UNDEF; |
SCU_APBPeriphClockConfig(__GPIO5, ENABLE); |
// unmap UART0 from GPS |
// set port pin 6.6 (serial data from gps) to input and disconnect from IP |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinInput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull; |
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Disable; |
GPIO_InitStructure.GPIO_Alternate = GPIO_InputAlt1; |
GPIO_Init(GPIO6, &GPIO_InitStructure); |
// set port pin 6.7 (serial data to gps) to input |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinInput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull; |
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Disable; |
GPIO_InitStructure.GPIO_Alternate = GPIO_InputAlt1; |
GPIO_Init(GPIO6, &GPIO_InitStructure); |
// map UART0 to Compass |
// set port pin 5.1 (serial data from compass) to input and connect to IP |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinInput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ; |
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable; |
GPIO_InitStructure.GPIO_Alternate = GPIO_InputAlt1; //UART0_RxD |
GPIO_Init(GPIO5, &GPIO_InitStructure); |
// set port pin 5.0 (serial data to compass) to output |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull; |
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable; |
GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt3; //UART0_TX |
GPIO_Init(GPIO5, &GPIO_InitStructure); |
UART0_Muxer = UART0_MK3MAG; |
} |
/********************************************************/ |
/* Initialize UART0 */ |
/********************************************************/ |
void UART0_Init(void) |
{ |
UART_InitTypeDef UART_InitStructure; |
SerialPutString("\r\n UART0 init..."); |
SCU_APBPeriphClockConfig(__UART0, ENABLE); // Enable the UART0 Clock |
UART0_Connect_to_MKGPS(); // to GPS serial interface |
/* UART0 configured as follow: |
- Word Length = 8 Bits |
- One Stop Bit |
- No parity |
- BaudRate = 57600 baud |
- Hardware flow control Disabled |
- Receive and transmit enabled |
- Receive and transmit FIFOs are Disabled |
*/ |
UART_StructInit(&UART_InitStructure); |
UART_InitStructure.UART_WordLength = UART_WordLength_8D; |
UART_InitStructure.UART_StopBits = UART_StopBits_1; |
UART_InitStructure.UART_Parity = UART_Parity_No ; |
UART_InitStructure.UART_BaudRate = BAUD_RATE; |
UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None; |
UART_InitStructure.UART_Mode = UART_Mode_Tx_Rx; |
UART_InitStructure.UART_FIFO = UART_FIFO_Enable; |
UART_InitStructure.UART_TxFIFOLevel = UART_FIFOLevel_1_2; |
UART_InitStructure.UART_RxFIFOLevel = UART_FIFOLevel_1_2; |
UART_DeInit(UART0); // reset uart 0 to default |
UART_Init(UART0, &UART_InitStructure); // initialize uart 0 |
// enable uart 0 interrupts selective |
UART_ITConfig(UART0, UART_IT_Receive | UART_IT_ReceiveTimeOut, ENABLE); |
UART_Cmd(UART0, ENABLE); // enable uart 0 |
// configure the uart 0 interupt line as an IRQ with priority 10 (0 is highest) |
VIC_Config(UART0_ITLine, VIC_IRQ, 10); |
// enable the uart 0 IRQ |
VIC_ITCmd(UART0_ITLine, ENABLE); |
SerialPutString("ok"); |
} |
/********************************************************/ |
/* UART0 Interrupt Handler */ |
/********************************************************/ |
void UART0_IRQHandler(void) |
{ |
u8 c; |
// if receive irq or receive timeout irq has occured |
if((UART_GetITStatus(UART0, UART_IT_Receive) != RESET) || (UART_GetITStatus(UART0, UART_IT_ReceiveTimeOut) != RESET) ) |
{ |
UART_ClearITPendingBit(UART0, UART_IT_Receive); // clear receive interrupt flag |
UART_ClearITPendingBit(UART0, UART_IT_ReceiveTimeOut); // clear receive timeout interrupt flag |
// if debug UART is UART0 |
if (DebugUART == UART0) |
{ // forward received data to the UART1 tx buffer |
while(UART_GetFlagStatus(UART0, UART_FLAG_RxFIFOEmpty) != SET) |
{ |
// wait for space in the tx buffer of the UART1 |
while(UART_GetFlagStatus(UART1, UART_FLAG_TxFIFOFull) == SET) {}; |
// move the byte from the rx buffer of UART0 to the tx buffer of UART1 |
UART_SendData(UART1, UART_ReceiveData(UART0)); |
} |
} |
else // UART0 is not the DebugUART (normal operation) |
{ |
// repeat until no byte is in the RxFIFO |
while (UART_GetFlagStatus(UART0, UART_FLAG_RxFIFOEmpty) != SET) |
{ |
c = UART_ReceiveData(UART0); // get byte from rx fifo |
switch(UART0_Muxer) |
{ |
case UART0_MKGPS: |
UBX_Parser(c); // if connected to GPS forward byte to ubx parser |
break; |
case UART0_MK3MAG: |
// ignora any byte send from MK3MAG |
break; |
case UART0_UNDEF: |
default: |
// ignore the byte from unknown source |
break; |
} // eof switch(UART0_Muxer) |
} // eof while |
} // eof UART0 is not the DebugUART |
} // eof receive irq or receive timeout irq |
} |
/branches/V0.1 killagreg/uart0.h |
---|
0,0 → 1,9 |
#ifndef __UART0_H |
#define __UART0_H |
void UART0_Init (void); |
void UART0_Connect_to_MKGPS(void); |
void UART0_Connect_to_MK3MAG(void); |
#endif //__UART0_H |
/branches/V0.1 killagreg/uart1.c |
---|
0,0 → 1,552 |
/*#######################################################################################*/ |
/* !!! 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 "91x_lib.h" |
#include "ramfunc.h" |
#include "menu.h" |
#include "printf_P.h" |
#include "GPS.h" |
#include "uart0.h" |
#include "uart1.h" |
//#include "uart2.h" |
#include "timer.h" |
#include "usb.h" |
#include "main.h" |
#define FALSE 0 |
#define TRUE 1 |
u8 Request_VerInfo = FALSE; |
u8 Request_ExternalControl = FALSE; |
u8 Request_Display = FALSE; |
u8 Request_DebugData = FALSE; |
u8 Request_DebugLabel = 255; |
u8 Request_ChannelOnly = FALSE; |
u8 Request_GPS_Position = FALSE; |
u8 Remote_PollDisplayLine = 0; |
UART_TypeDef *DebugUART = UART1; |
volatile u8 txd_buffer[TXD_BUFFER_LEN]; |
volatile u8 rxd_buffer_locked = FALSE; |
volatile u8 rxd_buffer[RXD_BUFFER_LEN]; |
volatile u8 txd_complete = TRUE; |
volatile u8 ReceivedBytes = 0; |
volatile u8 CntCrcError = 0; |
u8 text[50]; |
u8 PcAccess = 100; |
u8 MotorTest[4] = {0,0,0,0}; |
u8 MySlaveAddr = 0; |
u8 ConfirmFrame; |
DebugOut_t DebugOut; |
ExternControl_t ExternControl; |
VersionInfo_t VersionInfo; |
GPSPosition_t GPS_Position; |
s32 Debug_Timer; |
static u16 ptr_txd_buffer = 0; |
const u8 ANALOG_LABEL[32][16] = |
{ |
//1234567890123456 |
"AngleNick ", //0 |
"AngleRoll ", |
"AccNick ", |
"AccRoll ", |
" ", |
" ", //5 |
" ", |
" ", |
" ", |
" ", |
" ", //10 |
" ", |
"SPI Error ", |
"SPI Okay ", |
" ", |
" ", //15 |
"I2C_ReadByte ", |
"ACC_Speed_N ", |
"ACC_Speed_E ", |
" ", |
" ", //20 |
"N_Speed ", |
"E_Speed ", |
"KalmDist_N ", |
"KalmDist_E ", |
"GyroHeading ", //25 |
"CompassHeading ", |
"Distance N ", |
"Distance E ", |
"GPS_Nick ", |
"GPS_Roll ", //30 |
"Used_Sats " |
}; |
/********************************************************/ |
/* Initialization the UART1 */ |
/********************************************************/ |
void UART1_Init (void) |
{ |
GPIO_InitTypeDef GPIO_InitStructure; |
UART_InitTypeDef UART_InitStructure; |
SCU_APBPeriphClockConfig(__UART1, ENABLE); // Enable the UART1 Clock |
SCU_APBPeriphClockConfig(__GPIO3, ENABLE); // Enable the GPIO3 Clock |
/*Configure UART1_Rx pin GPIO3.2*/ |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinInput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull; |
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable; |
GPIO_InitStructure.GPIO_Alternate = GPIO_InputAlt1; // UART1_RxD |
GPIO_Init(GPIO3, &GPIO_InitStructure); |
/*Configure UART1_Tx pin GPIO3.3*/ |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull; |
GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt2; // UART1_TX |
GPIO_Init(GPIO3, &GPIO_InitStructure); |
/* UART1 configured as follow: |
- Word Length = 8 Bits |
- One Stop Bit |
- No parity |
- BaudRate = 57600 baud |
- Hardware flow control Disabled |
- Receive and transmit enabled |
- Receive and transmit FIFOs are Disabled |
*/ |
UART_StructInit(&UART_InitStructure); |
UART_InitStructure.UART_WordLength = UART_WordLength_8D; |
UART_InitStructure.UART_StopBits = UART_StopBits_1; |
UART_InitStructure.UART_Parity = UART_Parity_No ; |
UART_InitStructure.UART_BaudRate = BAUD_RATE; |
UART_InitStructure. UART_HardwareFlowControl = UART_HardwareFlowControl_None; |
UART_InitStructure.UART_Mode = UART_Mode_Tx_Rx; |
UART_InitStructure.UART_FIFO = UART_FIFO_Enable; |
UART_InitStructure.UART_TxFIFOLevel = UART_FIFOLevel_1_2; |
UART_InitStructure.UART_RxFIFOLevel = UART_FIFOLevel_1_2; |
UART_DeInit(UART1); // reset uart 1 to default |
UART_Init(UART1, &UART_InitStructure); // initialize uart 1 |
// enable uart 1 interrupts selective |
UART_ITConfig(UART1, UART_IT_Receive | UART_IT_ReceiveTimeOut, ENABLE); |
UART_Cmd(UART1, ENABLE); // enable uart 1 |
// configure the uart 1 interupt line as an IRQ with priority 4 (0 is highest) |
VIC_Config(UART1_ITLine, VIC_IRQ, 4); |
// enable the uart 1 IRQ |
VIC_ITCmd(UART1_ITLine, ENABLE); |
// initialize the debug timer |
Debug_Timer = SetDelay(3000); |
// unlock rxd_buffer |
rxd_buffer_locked = FALSE; |
// no bytes to send |
txd_complete = TRUE; |
SerialPutString("\r\nUART1 init...ok"); |
} |
/****************************************************************/ |
/* USART1 receiver ISR */ |
/****************************************************************/ |
void UART1_IRQHandler(void) |
{ |
static u16 crc; |
static u8 ptr_rxd_buffer = 0; |
static u8 crc1, crc2; |
u8 c; |
if((UART_GetITStatus(UART1, UART_IT_Receive) != RESET) || (UART_GetITStatus(UART1, UART_IT_ReceiveTimeOut) != RESET) ) |
{ |
// clear the pending bits |
UART_ClearITPendingBit(UART1, UART_IT_Receive); |
UART_ClearITPendingBit(UART1, UART_IT_ReceiveTimeOut); |
// if debug UART is not UART1 |
if (DebugUART != UART1) |
{ // forward received data to the debug UART tx buffer |
while(UART_GetFlagStatus(UART1, UART_FLAG_RxFIFOEmpty) != SET) |
{ |
// wait for space in the tx buffer of the DebugUART |
while(UART_GetFlagStatus(DebugUART, UART_FLAG_TxFIFOFull) == SET) {}; |
// move the byte from the rx buffer of UART1 to the tx buffer of DebugUART |
UART_SendData(DebugUART, UART_ReceiveData(UART1)); |
} |
} |
else // DebugUART == UART1 (normal operation) |
{ |
while ((UART_GetFlagStatus(UART1, UART_FLAG_RxFIFOEmpty) != SET) && (!rxd_buffer_locked)) |
{ // some byes in the fifo and rxd buffer not locked |
// get byte from fifo |
c = UART_ReceiveData(UART1); |
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) // rxd buffer not full |
{ |
if (c != '\r') // no termination character received |
{ |
rxd_buffer[ptr_rxd_buffer++] = c; // copy byte to rxd buffer |
crc += c; // update crc |
} |
else // termination character 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_locked = TRUE; // lock the rxd buffer |
ReceivedBytes = ptr_rxd_buffer; // store number of received bytes |
rxd_buffer[ptr_rxd_buffer] = '\r'; // set termination character |
// if 2nd byte is an 'R' start bootloader |
if(rxd_buffer[2] == 'R') |
{ |
PowerOff(); |
VIC_DeInit(); |
Execute_Bootloader(); // Reset-Commando - Bootloader starten |
} |
} // eof checksum valid |
else |
{ // checksum invalid |
rxd_buffer_locked = FALSE; // unlock rxd buffer |
} // eof checksum invalid |
ptr_rxd_buffer = 0; // reset rxd buffer pointer |
} // eof termination character received |
} // rxd buffer not full |
else // rxd buffer overrun |
{ |
ptr_rxd_buffer = 0; // reset rxd buffer pointer |
rxd_buffer_locked = FALSE; // unlock rxd buffer |
} // eof rxd buffer overrrun |
} // some byes in the fifo and rxd buffer not locked |
} // eof DebugUart = UART1 |
} |
} |
/**************************************************************/ |
/* Transmit tx buffer via debug uart */ |
/**************************************************************/ |
void UART1_Transmit(void) |
{ |
u8 tmp_tx; |
// if something has to be send and the txd fifo is not full |
if((!txd_complete) && (UART_GetFlagStatus(UART1, UART_FLAG_TxFIFOFull) == RESET)) |
{ |
tmp_tx = txd_buffer[ptr_txd_buffer]; // read byte from txd buffer |
// if terminating character or end of txd buffer reached |
if((tmp_tx == '\r') || (ptr_txd_buffer == TXD_BUFFER_LEN)) |
{ |
ptr_txd_buffer = 0; // reset txd buffer pointer |
txd_complete = TRUE;// set complete flag |
} |
UART_SendData(UART1, tmp_tx); // put character to txd fifo |
// set pointer to next byte |
ptr_txd_buffer++; |
} |
} |
/**************************************************************/ |
/* Add CRC and initiate transmission via debug uart */ |
/**************************************************************/ |
void AddCRC(u16 datalen) |
{ |
u16 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'; |
ptr_txd_buffer = 0; |
txd_complete = FALSE; |
UART_SendData(UART1,txd_buffer[ptr_txd_buffer++]); // send first byte |
} |
/**************************************************************/ |
/* Code output data */ |
/**************************************************************/ |
void SendOutData(u8 cmd, u8 module, u8 *snd, u8 len) |
{ |
u16 pt = 0; |
u8 a,b,c; |
u8 ptr = 0; |
txd_buffer[pt++] = '#'; // Start character |
txd_buffer[pt++] = module; // Address (a=0; b=1,...) |
txd_buffer[pt++] = cmd; // Command |
while(len) |
{ |
if(len) { a = snd[ptr++]; len--;} else a = 0; |
if(len) { b = snd[ptr++]; len--;} else b = 0; |
if(len) { c = snd[ptr++]; len--;} 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); |
} |
AddCRC(pt); // add checksum after data block and initates the transmission |
} |
/**************************************************************/ |
/* Decode data */ |
/**************************************************************/ |
void Decode64(u8 *ptrOut, u8 len, u8 ptrIn ,u8 max) |
{ |
u8 a,b,c,d; |
u8 ptr = 0; |
u8 x,y,z; |
while(len) |
{ |
a = rxd_buffer[ptrIn++] - '='; |
b = rxd_buffer[ptrIn++] - '='; |
c = rxd_buffer[ptrIn++] - '='; |
d = rxd_buffer[ptrIn++] - '='; |
if(ptrIn > max - 2) break; |
x = (a << 2) | (b >> 4); |
y = ((b & 0x0f) << 4) | (c >> 2); |
z = ((c & 0x03) << 6) | d; |
if(len--) ptrOut[ptr++] = x; else break; |
if(len--) ptrOut[ptr++] = y; else break; |
if(len--) ptrOut[ptr++] = z; else break; |
} |
} |
/**************************************************************/ |
/* Process incomming data from debug uart */ |
/**************************************************************/ |
void UART1_ProcessRxData(void) |
{ |
// if data in the rxd buffer are not locked immediately return |
if((!rxd_buffer_locked) || (DebugUART != UART1) ) return; |
u8 tmp_char_arr2[2]; |
s32 tmp_long_arr3[2]; |
PcAccess = 255; |
switch(rxd_buffer[2]) |
{ |
case 'a':// Labels of the Analog Debug outputs |
Decode64((u8 *) &tmp_char_arr2[0], sizeof(tmp_char_arr2),3 ,ReceivedBytes); |
Request_DebugLabel = tmp_char_arr2[0]; |
break; |
case 'b': // extern control |
Decode64((u8 *) &ExternControl, sizeof(ExternControl), 3 ,ReceivedBytes); |
RemoteButtons |= ExternControl.RemoteButtons; |
ConfirmFrame = ExternControl.Frame; |
break; |
case 'c': // extern control with debug request |
Decode64((u8 *) &ExternControl, sizeof(ExternControl), 3, ReceivedBytes); |
RemoteButtons |= ExternControl.RemoteButtons; |
ConfirmFrame = ExternControl.Frame; |
Request_DebugData = TRUE; |
break; |
case 'h':// x-1 display columns |
Decode64((u8 *) &tmp_char_arr2[0], sizeof(tmp_char_arr2), 3, ReceivedBytes); |
RemoteButtons |= tmp_char_arr2[0]; |
if(tmp_char_arr2[1] == 255) Request_ChannelOnly = 1; else Request_ChannelOnly = 0; // no displaydata |
Request_Display = TRUE; |
break; |
case 's':// new GPSPCPosition |
Decode64((unsigned char *) &tmp_long_arr3[0], sizeof(tmp_long_arr3), 3,ReceivedBytes); |
GPSPCPosition.Status = INVALID; |
GPSPCPosition.Longitude = tmp_long_arr3[0]; |
GPSPCPosition.Latitude = tmp_long_arr3[1]; |
GPSPCPosition.Altitude = 0; |
GPSPCPosition.Status = NEWDATA; |
break; |
case 'v': // get version |
Request_VerInfo = TRUE; |
break; |
case 'g':// get external control data |
Request_ExternalControl = TRUE; |
break; |
case 'u': |
Decode64((unsigned char *) &tmp_char_arr2[0], sizeof(tmp_char_arr2), 3,ReceivedBytes); |
switch(tmp_char_arr2[0]) |
{ |
case UART_FLIGHTCTRL: |
//UART2_Init(); // initialize UART2 to FC pins |
//DebugUART = UART2; |
break; |
case UART_MK3MAG: |
UART0_Connect_to_MK3MAG(); // mux UART0 to MK3MAG pins |
DebugUART = UART0; |
break; |
case UART_MKGPS: |
UART0_Connect_to_MKGPS(); // connect UART0 to MKGPS pins |
DebugUART = UART0; |
break; |
} |
break; |
case 'l': |
case 'm': |
case 'n': |
case 'o': |
case 'p': |
break; |
} |
// unlock the rxd buffer after processing |
rxd_buffer_locked = FALSE; |
} |
/*****************************************************/ |
/* Send a character */ |
/*****************************************************/ |
s16 uart_putchar (char c) |
{ |
if (c == '\n') |
uart_putchar('\r'); |
// wait until txd fifo is not full |
while (UART_GetFlagStatus(UART1, UART_FLAG_TxFIFOFull) != RESET); |
// transmit byte |
UART_SendData(UART1, c); |
return (0); |
} |
/*****************************************************/ |
/* Send a sting to the debug uart */ |
/*****************************************************/ |
void SerialPutString(u8 *s) |
{ |
while (*s != '\0') |
{ |
uart_putchar(*s); |
s ++; |
} |
} |
/**************************************************************/ |
/* Send the answers to incomming commands at the debug uart */ |
/**************************************************************/ |
void UART1_TransmitTxData(void) |
{ |
if(!txd_complete || (DebugUART != UART1) ) return; |
if(Request_ExternalControl && txd_complete) // Bei Get werden die vom PC einstellbaren Werte vom PC zurückgelesen |
{ |
SendOutData('G',MySlaveAddr,(u8 *) &ExternControl,sizeof(ExternControl)); |
Request_ExternalControl = FALSE; |
} |
if((CheckDelay(Debug_Timer) || Request_DebugData) && txd_complete) |
{ |
SendOutData('D',MySlaveAddr,(u8 *) &DebugOut,sizeof(DebugOut)); |
Request_DebugData = FALSE; |
Debug_Timer = SetDelay(2000); |
} |
if(Request_DebugLabel != 255) // Texte für die Analogdaten |
{ |
SendOutData('A',Request_DebugLabel + '0',(u8 *) ANALOG_LABEL[Request_DebugLabel],16); |
Request_DebugLabel = 255; |
} |
if(Request_Display && txd_complete) |
{ |
LCD_PrintMenu(); |
Request_Display = FALSE; |
if(++Remote_PollDisplayLine == 4 || Request_ChannelOnly) |
{ |
SendOutData('4',0,(u8 *) &VersionInfo,sizeof(VersionInfo)); // DisplayZeile übertragen |
Remote_PollDisplayLine = -1; |
} |
else SendOutData('0' + Remote_PollDisplayLine,0,(u8 *)&DisplayBuff[20 * Remote_PollDisplayLine],20); // DisplayZeile übertragen |
} |
if(Request_VerInfo && txd_complete) |
{ |
SendOutData('V',MySlaveAddr,(u8 *) &VersionInfo,sizeof(VersionInfo)); |
Request_VerInfo = FALSE; |
} |
if(Request_GPS_Position && txd_complete) |
{ |
SendOutData('Q',MySlaveAddr,(u8 *) &GPS_Position,sizeof(GPS_Position)); |
Request_GPS_Position = FALSE; |
} |
} |
/branches/V0.1 killagreg/uart1.h |
---|
0,0 → 1,74 |
#ifndef _UART1_H |
#define _UART1_H |
#define UART_FLIGHTCTRL 0 |
#define UART_MK3MAG 1 |
#define UART_MKGPS 2 |
#define TXD_BUFFER_LEN 150 |
#define RXD_BUFFER_LEN 150 |
#define BAUD_RATE 57600 //Baud Rate for the serial interfaces |
typedef struct |
{ |
u8 Digital[2]; |
u16 Analog[32]; // Debugwerte |
} __attribute__((packed)) DebugOut_t; |
extern DebugOut_t DebugOut; |
typedef struct |
{ |
u8 Digital[2]; |
u8 RemoteButtons; |
s8 Nick; |
s8 Roll; |
s8 Yaw; |
u8 Gas; |
s8 Height; |
u8 free; |
u8 Frame; |
u8 Config; |
} __attribute__((packed)) ExternControl_t; |
extern ExternControl_t ExternControl; |
typedef struct GPSPosition |
{ |
s32 Longitude; |
s32 Latitude; |
s32 TargetLongitude; |
s32 TargetLatitude; |
s32 Distance2Target; |
s32 Angle2Target; |
u8 Used_Sat; |
} __attribute__((packed)) GPSPosition_t; |
extern u8 Request_GPS_Position; |
extern GPSPosition_t GPS_Position; |
typedef struct |
{ |
u8 Major; |
u8 Minor; |
u8 Patch; |
u8 Reserved[7]; |
} __attribute__((packed)) VersionInfo_t; |
extern VersionInfo_t VersionInfo; |
extern volatile u8 rxd_buffer[RXD_BUFFER_LEN]; |
extern volatile u8 ReceivedBytes; |
extern volatile u8 rxd_buffer_locked; |
extern UART_TypeDef *DebugUART; |
void UART1_Init(void); |
void UART1_Transmit(void); |
void UART1_TransmitTxData(void); |
void UART1_ProcessRxData(void); |
extern s16 uart_putchar (char c); |
extern void SerialPutString(u8 *s); |
extern u8 text[50]; |
#endif //_UART1_H |
/branches/V0.1 killagreg/uart2.c |
---|
0,0 → 1,156 |
/*#######################################################################################*/ |
/* !!! 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 "91x_lib.h" |
#include "uart1.h" |
/********************************************************/ |
/* Initialize UART2 */ |
/********************************************************/ |
void UART2_Init(void) |
{ |
UART_InitTypeDef UART_InitStructure; |
GPIO_InitTypeDef GPIO_InitStructure; |
SerialPutString("\r\n UART2 init..."); |
SCU_APBPeriphClockConfig(__UART2, ENABLE); // Enable the UART2 Clock |
SCU_APBPeriphClockConfig(__GPIO5, ENABLE); // Enable the GPIO5 Clock |
/*Configure UART2_Rx pin GPIO5.2*/ |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinInput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull; |
GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable; |
GPIO_InitStructure.GPIO_Alternate = GPIO_InputAlt1; // UART2_RxD |
GPIO_Init(GPIO5, &GPIO_InitStructure); |
SCU_APBPeriphClockConfig(__GPIO3, ENABLE); // Enable the GPIO3 Clock |
/*Configure UART2_Tx pin GPIO3.0*/ |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull; |
GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt2; // UART2_TX |
GPIO_Init(GPIO3, &GPIO_InitStructure); |
/* UART2 configured as follow: |
- Word Length = 8 Bits |
- One Stop Bit |
- No parity |
- BaudRate = 57600 baud |
- Hardware flow control Disabled |
- Receive and transmit enabled |
- Receive and transmit FIFOs are Disabled |
*/ |
UART_StructInit(&UART_InitStructure); |
UART_InitStructure.UART_WordLength = UART_WordLength_8D; |
UART_InitStructure.UART_StopBits = UART_StopBits_1; |
UART_InitStructure.UART_Parity = UART_Parity_No ; |
UART_InitStructure.UART_BaudRate = BAUD_RATE; |
UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None; |
UART_InitStructure.UART_Mode = UART_Mode_Tx_Rx; |
UART_InitStructure.UART_FIFO = UART_FIFO_Enable; |
UART_InitStructure.UART_TxFIFOLevel = UART_FIFOLevel_1_2; |
UART_InitStructure.UART_RxFIFOLevel = UART_FIFOLevel_1_2; |
UART_DeInit(UART2); // reset uart 0 to default |
UART_Init(UART2, &UART_InitStructure); // initialize uart 0 |
// enable uart 2 interrupts selective |
UART_ITConfig(UART2, UART_IT_Receive | UART_IT_ReceiveTimeOut, ENABLE); |
UART_Cmd(UART2, ENABLE); // enable uart 0 |
// configure the uart 2 interupt line as an IRQ with priority 9 (0 is highest) |
VIC_Config(UART2_ITLine, VIC_IRQ, 9); |
// enable the uart 2 IRQ |
VIC_ITCmd(UART2_ITLine, ENABLE); |
SerialPutString("ok"); |
} |
/********************************************************/ |
/* UART2 Interrupt Handler */ |
/********************************************************/ |
void UART2_IRQHandler(void) |
{ |
// if receive irq or receive timeout irq has occured |
if((UART_GetITStatus(UART2, UART_IT_Receive) != RESET) || (UART_GetITStatus(UART2, UART_IT_ReceiveTimeOut) != RESET) ) |
{ |
UART_ClearITPendingBit(UART2, UART_IT_Receive); // clear receive interrupt flag |
UART_ClearITPendingBit(UART2, UART_IT_ReceiveTimeOut); // clear receive timeout interrupt flag |
// if debug UART is UART2 |
if (DebugUART == UART2) |
{ // forward received data to the UART1 tx buffer |
while(UART_GetFlagStatus(UART2, UART_FLAG_RxFIFOEmpty) != SET) |
{ |
// wait for space in the tx buffer of the UART1 |
while(UART_GetFlagStatus(UART1, UART_FLAG_TxFIFOFull) == SET) {}; |
// move the byte from the rx buffer of UART0 to the tx buffer of UART1 |
UART_SendData(UART1, UART_ReceiveData(UART2)); |
} |
} |
else |
{ |
// ignore serial data from the FC |
while(UART_GetFlagStatus(UART2, UART_FLAG_RxFIFOEmpty) != SET) |
UART_ReceiveData(UART2); |
} |
} // eof receive irq or receive timeout irq |
} |
/branches/V0.1 killagreg/uart2.h |
---|
0,0 → 1,6 |
#ifndef __UART2_H |
#define __UART2_H |
void UART2_Init (void); |
#endif //__UART2_H |
/branches/V0.1 killagreg/ubx.c |
---|
0,0 → 1,434 |
/*#######################################################################################*/ |
/* !!! 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 "91x_lib.h" |
#include "uart1.h" |
#include "ubx.h" |
#include "led.h" |
#include "timer.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) |
const u32 Leap[ 13 ] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; |
const u32 Normal[ 13 ] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; |
#define LEAP_SECONDS_FROM_1980 13 |
// 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 |
{ |
u32 itow; // ms GPS Millisecond Time of Week |
s32 frac; // ns remainder of rounded ms above |
s16 week; // GPS week |
u8 GPSfix; // GPSfix Type, range 0..6 |
u8 Flags; // Navigation Status Flags |
s32 ECEF_X; // cm ECEF X coordinate |
s32 ECEF_Y; // cm ECEF Y coordinate |
s32 ECEF_Z; // cm ECEF Z coordinate |
u32 PAcc; // cm 3D Position Accuracy Estimate |
s32 ECEFVX; // cm/s ECEF X velocity |
s32 ECEFVY; // cm/s ECEF Y velocity |
s32 ECEFVZ; // cm/s ECEF Z velocity |
u32 SAcc; // cm/s Speed Accuracy Estimate |
u16 PDOP; // 0.01 Position DOP |
u8 res1; // reserved |
u8 numSV; // Number of SVs used in navigation solution |
u32 res2; // reserved |
Status_t Status; // invalid/newdata/processed |
} __attribute__((packed)) ubx_nav_sol_t; |
typedef struct |
{ |
u32 itow; // ms GPS Millisecond Time of Week |
s32 VEL_N; // cm/s NED north velocity |
s32 VEL_E; // cm/s NED east velocity |
s32 VEL_D; // cm/s NED down velocity |
u32 Speed; // cm/s Speed (3-D) |
u32 GSpeed; // cm/s Ground Speed (2-D) |
s32 Heading; // 1e-05 deg Heading 2-D |
u32 SAcc; // cm/s Speed Accuracy Estimate |
u32 CAcc; // deg Course / Heading Accuracy Estimate |
Status_t Status; // invalid/newdata/processed |
} __attribute__((packed)) ubx_nav_velned_t; |
typedef struct |
{ |
u32 itow; // ms GPS Millisecond Time of Week |
s32 LON; // 1e-07 deg Longitude |
s32 LAT; // 1e-07 deg Latitude |
s32 HEIGHT; // mm Height above Ellipsoid |
s32 HMSL; // mm Height above mean sea level |
u32 Hacc; // mm Horizontal Accuracy Estimate |
u32 Vacc; // mm Vertical Accuracy Estimate |
Status_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}; |
// shared buffer |
volatile gps_data_t GPSData = {0,0,0,0,0,0,0,0,0,0, INVALID}; |
DateTime_t GPSDateTime = {0,0,0,0,0,0,0, INVALID}; |
//------------------------------------------------------------------------------------ |
// functions |
u8 IsLeapYear(u16 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) |
{ |
u32 Days, Seconds, Week; |
u16 YearPart; |
u32 * MonthDayTab = 0; |
u8 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 = (u32)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 = (u16)(Days / DAYS_PER_400YEARS); |
pTimeStruct->Year += YearPart * 400; |
Days = Days % DAYS_PER_400YEARS; |
YearPart = (u16)(Days / DAYS_PER_100YEARS); |
pTimeStruct->Year += YearPart * 100; |
Days = Days % DAYS_PER_100YEARS; |
YearPart = (u16)(Days / DAYS_PER_4YEARS); |
pTimeStruct->Year += YearPart * 4; |
Days = Days % DAYS_PER_4YEARS; |
if(Days < (3* DAYS_PER_YEAR)) YearPart = (u16)(Days / DAYS_PER_YEAR); |
else YearPart = 3; |
pTimeStruct->Year += YearPart; |
// calculate remaining days of year |
Days -= (u32)(YearPart * DAYS_PER_YEAR); |
Days += 1; |
// check if current year is a leap year |
if(IsLeapYear(pTimeStruct->Year)) MonthDayTab = (u32*)Leap; |
else MonthDayTab = (u32*)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 = (u8)(Seconds / SECONDS_PER_HOUR); |
Seconds = Seconds % SECONDS_PER_HOUR; // remaining seconds of current hour |
pTimeStruct->Min = (u8)(Seconds / SECONDS_PER_MINUTE); |
Seconds = Seconds % SECONDS_PER_MINUTE; // remaining seconds of current minute |
pTimeStruct->Sec = (u8)(Seconds); |
pTimeStruct->mSec = (u16)(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) |
{ |
if ((UbxSol.Status == NEWDATA) && (UbxPosLlh.Status == NEWDATA) && (UbxVelNed.Status == NEWDATA)) |
{ |
LED_RED_TOGGLE; |
// update GPS data only if the status is INVALID or PROCESSED |
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.Longitude = UbxPosLlh.LON; |
GPSData.Latitude = UbxPosLlh.LAT; |
GPSData.Altitude = UbxPosLlh.HMSL; |
// 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.Status = NEWDATA; // new data available |
} |
// 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(u8 c) |
{ |
static ubxState_t ubxState = UBXSTATE_IDLE; |
static u16 msglen; |
static u8 cka, ckb; |
static u8 *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 = (u8 *)&UbxPosLlh; // data start pointer |
ubxEp = (u8 *)(&UbxPosLlh + 1); // data end pointer |
ubxSp = (u8 *)&UbxPosLlh.Status; // status pointer |
break; |
case UBX_ID_SOL: // navigation solution |
ubxP = (u8 *)&UbxSol; // data start pointer |
ubxEp = (u8 *)(&UbxSol + 1); // data end pointer |
ubxSp = (u8 *)&UbxSol.Status; // status pointer |
break; |
case UBX_ID_VELNED: // velocity vector in tangent plane |
ubxP = (u8 *)&UbxVelNed; // data start pointer |
ubxEp = (u8 *)(&UbxVelNed + 1); // data end pointer |
ubxSp = (u8 *)&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 = (u16)c; // lowbyte first |
cka += c; |
ckb += cka; |
ubxState = UBXSTATE_LEN2; |
break; |
case UBXSTATE_LEN2: // 2nd message length byte |
msglen += ((u16)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 |
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; |
} |
} |
/branches/V0.1 killagreg/ubx.h |
---|
0,0 → 1,48 |
#ifndef __UBX_H |
#define __UBX_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) |
typedef enum |
{ |
INVALID, |
NEWDATA, |
PROCESSED |
} Status_t; |
typedef struct |
{ |
u8 Flags; // Status Flags |
u8 NumOfSats; // number of satelites |
u8 SatFix; // type of satfix |
s32 Longitude; // in 1e-07 deg |
s32 Latitude; // in 1e-07 deg |
s32 Altitude; // in mm |
u32 Position_Accuracy; // in cm 3d position accuracy |
s32 Speed_North; // in cm/s |
s32 Speed_East; // in cm/s |
s32 Speed_Top; // in cm/s |
u32 Speed_Ground; // 2D ground speed in cm/s |
u32 Speed_Accuracy; // in cm/s 3d velocity accuracy |
Status_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 volatile gps_data_t GPSData; |
void UBX_Init(void); |
void UBX_Parser(u8 c); |
#endif // __UBX_H |
/branches/V0.1 killagreg/usb.c |
---|
55,18 → 55,21 |
// + POSSIBILITY OF SUCH DAMAGE. |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
#include "91x_lib.h" |
#include "uart1.h" |
#include "usb.h" |
#include "uart.h" |
//----------------------------------------------------------------- |
void USB_ConfigInit(void) |
{ |
GPIO_InitTypeDef GPIO_InitStructure; |
SerialPutString("USB init..."); |
//USB clock = MCLK= 48MHz |
SerialPutString("\r\n USB init..."); |
#ifdef MCLK96MHZ |
//USB clock = MCLK/2 = 48MHz |
SCU_USBCLKConfig(SCU_USBCLK_MCLK2); |
#else |
//USB clock = MCLK = 48MHz |
SCU_USBCLKConfig(SCU_USBCLK_MCLK); |
#endif |
//Enable USB clock |
SCU_AHBPeriphClockConfig(__USB,ENABLE); |
SCU_AHBPeriphReset(__USB,DISABLE); |
77,6 → 80,7 |
SCU_APBPeriphReset(__GPIO0,DISABLE); |
// GPIO_DeInit(P0.1); |
GPIO_StructInit(&GPIO_InitStructure); |
GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput; |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; |
GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ; |
92,7 → 96,7 |
USB_Init(); |
SerialPutString("ok\n\r"); |
SerialPutString("ok"); |
} |
//----------------------------------------------------------------- |
/branches/V0.1 killagreg/usb_endp.c |
---|
16,9 → 16,11 |
*******************************************************************************/ |
/* Includes ------------------------------------------------------------------*/ |
#include <stdio.h> |
#include "91x_lib.h" |
#include "uart1.h" |
#include "usb_lib.h" |
#include "usb_desc.h" |
#include "uart.h" |
/* Private typedef -----------------------------------------------------------*/ |
/* Private define ------------------------------------------------------------*/ |
/* Private macro -------------------------------------------------------------*/ |