No changes between revisions
/Designs/Data_loggers/GPSRL02A/SW/buffer/a2dtest.c |
---|
0,0 → 1,118 |
//***************************************************************************** |
// File Name : a2dtest.c |
// |
// Title : example usage of some avr library functions |
// Revision : 1.0 |
// Notes : |
// Target MCU : Atmel AVR series |
// Editor Tabs : 4 |
// |
// Revision History: |
// When Who Description of change |
// ----------- ----------- ----------------------- |
// 20-Oct-2002 pstang Created the program |
//***************************************************************************** |
//----- Include Files --------------------------------------------------------- |
#include <avr/io.h> // include I/O definitions (port names, pin names, etc) |
#include <avr/interrupt.h> // include interrupt support |
#include <string.h> |
#include "global.h" // include our global settings |
#include "uart.h" // include uart function library |
#include "rprintf.h" // include printf function library |
#include "timer.h" // include timer function library (timing, PWM, etc) |
#include "a2d.h" // include A/D converter function library |
#include "vt100.h" // include VT100 terminal support |
//----- Begin Code ------------------------------------------------------------ |
int main(void) |
{ |
u16 a=0; |
u08 i=0; |
// initialize our libraries |
// initialize the UART (serial port) |
uartInit(); |
// make all rprintf statements use uart for output |
rprintfInit(uartSendByte); |
// initialize the timer system |
timerInit(); |
// turn on and initialize A/D converter |
a2dInit(); |
// print a little intro message so we know things are working |
/* vt100ClearScreen(); |
vt100SetCursorPos(1,1); |
rprintf("Welcome to the a2d test!\r\n");*/ |
// configure a2d port (PORTA) as input |
// so we can receive analog signals |
DDRC = 0x00; |
// make sure pull-up resistors are turned off |
PORTC = 0x00; |
// set the a2d prescaler (clock division ratio) |
// - a lower prescale setting will make the a2d converter go faster |
// - a higher setting will make it go slower but the measurements |
// will be more accurate |
// - other allowed prescale values can be found in a2d.h |
a2dSetPrescaler(ADC_PRESCALE_DIV32); |
// set the a2d reference |
// - the reference is the voltage against which a2d measurements are made |
// - other allowed reference values can be found in a2d.h |
a2dSetReference(ADC_REFERENCE_AVCC); |
// use a2dConvert8bit(channel#) to get an 8bit a2d reading |
// use a2dConvert10bit(channel#) to get a 10bit a2d reading |
while(1) |
{ |
u08 c=0; |
u08 n,i; |
char radiace[10]; |
char radka[201]; |
for(n=0;n<=100;n++) radka[n]=0; // vynuluj bufferovaci pole |
for(n=0;n<10;n++) radiace[n]=0; // vynuluj bufferovaci pole |
n=0; |
while(1) // pockej na $ kterym zacina NMEA radka |
{ |
uartReceiveByte(&c); |
if(c == '$') break; |
} |
for(i=0;i<100;i++) // nacti maximalne 100 znaku do bufferu |
{ |
radka[n]=c; |
if(c == '\n') break; // kdyz narazis na konec radku zastav nacitani |
uartReceiveByte(&c); |
n++; |
} |
radka[n]=0; // naztav na konec retezce pro zpracovani pomoci strcat |
itoa(a2dConvert10bit(2),&radiace,10); //a2dConvert8bit(1) |
if(n != 0) |
{ |
strcat(radka, radiace); |
strcat(radka,"\r"); |
} |
n=0; |
uartFlushReceiveBuffer(); |
while (0!=radka[n]) |
{ |
uartSendByte(radka[n]); |
n++; |
timerPause(35); |
} |
} |
return 0; |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/gpsrl.hex |
---|
0,0 → 1,279 |
:100000003BC055C054C03EC676C50FC6B4C5E0C59A |
:1000100045C5F1C44CC0C6C64AC008C783C047C066 |
:1000200046C045C044C030313233343536373839B4 |
:1000300041424344454600000001000800400000E2 |
:1000400001000400000100080020004000800000C2 |
:100050000100041B5B25643B256448001B5B3F32A9 |
:10006000356C001B5B3F323568001B5B25646D00FF |
:100070001B5B324A001B630011241FBECFE5D4E096 |
:10008000DEBFCDBF10E0A0E6B0E0E4E4F1E102C0E5 |
:1000900005900D92A236B107D9F711E0A2E6B0E0C3 |
:1000A00001C01D92A43DB107E1F759D04AC8A8CFBD |
:1000B00033983798089596B1987F982B96B90895FC |
:1000C00097B18295880F880F807C9F73982B97B982 |
:1000D000089597B18F71907E892B87B90895349ACE |
:1000E000369A089586B19927807490700895109279 |
:1000F000B30197B18F71907E892B87B9349A369A64 |
:100100003699FECF24B185B19927982F88273327B8 |
:10011000822B932B0895EBDF96958795969587957F |
:10012000992708951F920F920FB60F9211248F9363 |
:100130008FEF8093B3018F910F900FBE0F901F90A0 |
:100140001895379A359886B1887F866086B981E0A0 |
:10015000B7DF3D98339A1092B30178940895CBE8B5 |
:10016000D3E0DEBFCDBFDFD688EB96E00FD1B7D5A9 |
:10017000E8DF14BA15BA85E09EDF81E0A1DF3CE03C |
:10018000C32ED12CCC0EDD1E21E7422E512C4C0E5D |
:100190005D1E92E0A92EB12CAC0EBD1E4E0108943E |
:1001A000811C911C80E6682E80E0782EF601119269 |
:1001B000E415F505E1F7F5011192EC15FD05E1F700 |
:1001C0001982C40169D689818432D9F700E010E030 |
:1001D000F02E8981F601E00FF11F80838A3041F013 |
:1001E000C4015AD6F3940F5F1F4F0436110581F7EF |
:1001F000F601EF0DF11D108282E079DF4AE050E058 |
:10020000B50100D7FF2031F0B501C601F0D6B3012A |
:10021000C601EDD6B6D500E010E004C0A9D583E252 |
:1002200090E000D3F601E00FF11D80810F5F1F4FBA |
:100230008823A1F7BBCFFC018FB7F894718360834B |
:100240005383428317821682158214828FBF0895CA |
:10025000CF93DF93DC014FB7F894EC018C819D8143 |
:10026000892B11F4E0E01CC0FD0186819781ED919E |
:10027000FC911197E80FF91FE0810196ED019F8332 |
:100280008E832A813B818217930720F0821B930B78 |
:100290009F838E83ED018C819D8101979D838C834B |
:1002A0004FBF8E2F9927DF91CF910895FC014FB753 |
:1002B000F8948481958168177907B0F486819781D5 |
:1002C000860F971F97838683228133818217930736 |
:1002D00020F0821B930B9783868384819581861BF4 |
:1002E000970B9583848302C0158214824FBF0895B3 |
:1002F000FC01CB014FB7F89426813781628173816D |
:10030000820F931FCDD60190F081E02DE80FF91FE9 |
:1003100080814FBF992708951F93CF93DF93EC01FE |
:10032000162F4FB7F8942C813D816A817B81261767 |
:10033000370798F48E819F81820F931FB1D6E88191 |
:10034000F981E80FF91F10838C819D8101969D83AF |
:100350008C834FBF8FEF90E003C04FBF80E090E0F1 |
:10036000DF91CF911F910895FC018FB7F8948FBF53 |
:100370008281938124813581821B930B0895FC0136 |
:100380008FB7F894158214828FBF089590936300FD |
:100390008093620008951F93182F8A3031F4E09102 |
:1003A0006200F09163008DE00995E0916200F091A8 |
:1003B0006300812F09951F910895CF93DF93EC017E |
:1003C000892B19F405C02196E6DF88818823D9F7A7 |
:1003D000DF91CF910895EF92FF920F931F93CF93E8 |
:1003E000DF937A010097C1F0EC01680F791FC617FF |
:1003F000D70719F089918823D1F700E010E009C0F0 |
:100400008881882311F0219601C080E2C4DF0F5F4C |
:100410001F4F0E151F05A1F7DF91CF911F910F916F |
:10042000FF90EF900895CF93DF93EC01892B11F4A7 |
:1004300006C0B1DFFE01219684918823D1F7DF91B8 |
:10044000CF9108958AE0A7DF0895E82FFF27EF7086 |
:10045000F070EA5DFF4FE4918E2F9DDF08951F93AA |
:10046000182F82958F70F1DF812FEFDF1F91089594 |
:100470000F931F938C01812F9927F1DF802FEFDFDE |
:100480001F910F910895EF92FF920F931F937B019D |
:100490008C01C801AA27BB27EBDFC701E9DF1F9149 |
:1004A0000F91FF90EF9008952F923F924F925F929D |
:1004B0006F927F928F929F92AF92BF92CF92DF9274 |
:1004C000EF92FF920F931F93CF93DF93CDB7DEB7D9 |
:1004D000A4970FB6F894DEBF0FBECDBF4BA32CA3DD |
:1004E00027013801442351F017FF08C0EE24FF24F0 |
:1004F0008701E418F5080609170902C08301720193 |
:1005000069A390E02BA1211191E0E9A1E91BE15041 |
:10051000EAA318A2882E992487FC9094A92CB92CC0 |
:10052000C801B701A5019401CFD5FB01EF70F070B0 |
:10053000EA5DFF4F64916F8FC801B701A501940177 |
:10054000C3D569017A012EE1222E312C2C0E3D1EDD |
:1005500020C0C114D104E104F104A9F0C701B6011F |
:10056000A5019401B1D5FB01EF70F070EA5DFF4F7A |
:100570006491F1016083C701B601A5019401A4D57E |
:1005800069017A0103C02CA1F1012083089421089C |
:10059000310881010F5F1F4F8AA181508AA38F3FCD |
:1005A000C1F69BA19923B1F077FE03C081018DE2D2 |
:1005B0000AC0411451046104710419F081018BE2F5 |
:1005C00002C0810180E2F801808304C0F8018191BA |
:1005D0008F01E1DEF9A1F150F9A3FF3FB9F7A4962D |
:1005E0000FB6F894DEBF0FBECDBFDF91CF911F9144 |
:1005F0000F91FF90EF90DF90CF90BF90AF909F90C2 |
:100600008F907F906F905F904F903F902F900895C4 |
:100610009F92AF92BF92CF92DF92EF92FF920F9391 |
:100620001F93CF93DF93CDB7DEB722970FB6F89421 |
:10063000DEBF0FBECDBF9888C988DA88CE01439649 |
:100640009A83898304C0882309F465C0A4DE9601D7 |
:100650002F5F3F4F992021F0F6016901849103C07B |
:10066000F60180816901853271F72F5F3F4F992034 |
:1006700021F0F6016901849103C0F60180816901CE |
:100680008436A1F0883719F0833601F707C0E12CD2 |
:1006900060E1F62E50E1A52EB12C0FC0E981FA8160 |
:1006A0003296FA83E98332978081D0CF40E1E42EFD |
:1006B00047E2F42E3AE0A32EB12CE981FA8132967A |
:1006C000FA83E983129102918436A1F417FF0BC0DB |
:1006D000109501951F4F8DE25EDE05C0C7016AE0EF |
:1006E00070E0DED47B01F2E0EF16F10418F00E1595 |
:1006F0001F05A0F3C801B701D3D4CB01A6DEC80102 |
:10070000B701CED48C01C701B501CAD47B01672BD8 |
:1007100009F49DCFEFCF80E090E022960FB6F894D9 |
:10072000DEBF0FBECDBFDF91CF911F910F91FF9024 |
:10073000EF90DF90CF90BF90AF909F900895089575 |
:1007400083B7887F826083BF12BE89B7816089BF0B |
:100750001092B4011092B5011092B6011092B70137 |
:1007600008958EB5887F83608EBD1DBC1CBC89B783 |
:10077000846089BF089585B5887F846085BD14BC79 |
:1007800089B7806489BF1092BC011092BD0110929C |
:10079000BE011092BF01089593B7987F982B93BF25 |
:1007A00008959EB5987F982B9EBD089595B5987F26 |
:1007B000982B95BD0895E3B7FF27E770F070EE0F13 |
:1007C000FF1FE95CFF4F859194910895EEB5FF27D7 |
:1007D000E770F070EE0FFF1FE95CFF4F8591949179 |
:1007E0000895E5B5FF27E770F070EE0FFF1FED5B92 |
:1007F000FF4F859194910895873040F4E82FFF27AB |
:10080000EE0FFF1FEC59FF4F71836083089587300F |
:1008100040F4E82FFF27EE0FFF1FEC59FF4F118226 |
:1008200010820895EF92FF920F931F93CF93DF935F |
:10083000EC0112B71092B8011092B9011092BA01EE |
:100840001092BB01B8DF9C014427552760E072E19C |
:100850008AE790E05BD4CA01B901693B2DE87207D1 |
:1008600026E0820720E0920770F427E2C131D20728 |
:1008700050F49E0144275527F4D328EE33E040E09E |
:1008800050E022D421C028EE33E040E050E01CD4F8 |
:10089000CA01B9019E0144275527E3D39B01AC014E |
:1008A00013C08091B8019091B901A091BA01B091A3 |
:1008B000BB0185B78F7885BF85B7806885BF889570 |
:1008C00085B78F7785BF06C0210F311D411D511D92 |
:1008D00079018A012091B8013091B9014091BA01A2 |
:1008E0005091BB0182B79927AA27BB27542F432FCA |
:1008F000322F2227822B932BA42BB52B8E159F05ED |
:10090000A007B10770F2DF91CF911F910F91FF9077 |
:10091000EF9008951092B4011092B5011092B601B3 |
:100920001092B70108956091B4017091B501809162 |
:10093000B6019091B70108951092BC011092BD01CB |
:100940001092BE011092BF0108956091BC01709198 |
:10095000BD018091BE019091BF010895893031F4AD |
:100960008FB582608FBD8FB58E7F0AC08A3019F433 |
:100970008FB5826002C08FB58D7F8FBD8FB58160CE |
:100980008FBD1BBC1ABC19BC18BC08952FB52E7F97 |
:100990002FBD2FB522602FBD2EB528602EBD2EB5E0 |
:1009A00020612EBD97BD86BD1BBC1ABC19BC18BCEE |
:1009B00008958FB580688FBD8FB58F7B8FBD0895EB |
:1009C0008FB580628FBD8FB58F7E8FBD08958FB537 |
:1009D0008F778FBD8FB58F7B8FBD08958FB58F7D3E |
:1009E0008FBD8FB58F7E8FBD08959BBD8ABD089545 |
:1009F00099BD88BD08951F920F920FB60F921124D2 |
:100A00002F933F934F935F936F937F938F939F9316 |
:100A1000AF93BF93EF93FF938091B4019091B50191 |
:100A2000A091B601B091B7010196A11DB11D8093AF |
:100A3000B4019093B501A093B601B093B701809132 |
:100A4000B8019091B901A091BA01B091BB01019692 |
:100A5000A11DB11D8093B8019093B901A093BA0173 |
:100A6000B093BB018091640090916500892B29F0BF |
:100A7000E0916400F09165000995FF91EF91BF91BD |
:100A8000AF919F918F917F916F915F914F913F9126 |
:100A90002F910F900FBE0F901F9018951F920F92DD |
:100AA0000FB60F9211242F933F934F935F936F9341 |
:100AB0007F938F939F93AF93BF93EF93FF93809117 |
:100AC000660090916700892B29F0E0916600F09113 |
:100AD00067000995FF91EF91BF91AF919F918F9121 |
:100AE0007F916F915F914F913F912F910F900FBE2A |
:100AF0000F901F9018951F920F920FB60F9211240E |
:100B00002F933F934F935F936F937F938F939F9315 |
:100B1000AF93BF93EF93FF938091BC019091BD0180 |
:100B2000A091BE01B091BF010196A11DB11D80939E |
:100B3000BC019093BD01A093BE01B093BF01809111 |
:100B40006E0090916F00892B29F0E0916E00F0917A |
:100B50006F000995FF91EF91BF91AF919F918F9198 |
:100B60007F916F915F914F913F912F910F900FBEA9 |
:100B70000F901F9018951F920F920FB60F9211248D |
:100B80002F933F934F935F936F937F938F939F9395 |
:100B9000AF93BF93EF93FF938091680090916900AA |
:100BA000892B29F0E0916800F09169000995FF9187 |
:100BB000EF91BF91AF919F918F917F916F915F91D5 |
:100BC0004F913F912F910F900FBE0F901F9018954E |
:100BD0001F920F920FB60F9211242F933F934F93B2 |
:100BE0005F936F937F938F939F93AF93BF93EF9395 |
:100BF000FF9380916A0090916B00892B29F0E0911E |
:100C00006A00F0916B000995FF91EF91BF91AF9150 |
:100C10009F918F917F916F915F914F913F912F9114 |
:100C20000F900FBE0F901F9018951F920F920FB646 |
:100C30000F9211242F933F934F935F936F937F9362 |
:100C40008F939F93AF93BF93EF93FF9380916C002B |
:100C500090916D00892B29F0E0916C00F0916D006E |
:100C60000995FF91EF91BF91AF919F918F917F91E6 |
:100C70006F915F914F913F912F910F900FBE0F9009 |
:100C80001F9018951F920F920FB60F9211242F9359 |
:100C90003F934F935F936F937F938F939F93AF9304 |
:100CA000BF93EF93FF938091700090917100892B17 |
:100CB00029F0E0917000F09171000995FF91EF919A |
:100CC000BF91AF919F918F917F916F915F914F9164 |
:100CD0003F912F910F900FBE0F901F90189580E0BD |
:100CE00090E0FC01EE0FFF1FEC59FF4F11821082C4 |
:100CF000019687309105A9F723DD33DD3CDD78943B |
:100D000008958FB58D7F8FBD8FB58E7F8FBD8FB5C9 |
:100D10008F778FBD8FB58F7B8FBD8FB58F7D8FBD4B |
:100D20008FB58F7E8FBD08959093B2018093B101EE |
:100D30000895F3E0660F771F881F991FFA95D1F782 |
:100D40009B01AC01220F331F441F551F60507E4E84 |
:100D500085489F4FB9D12150304029B9232F3327DF |
:100D600020BD089581EC91E008958AEC91E008950A |
:100D7000982F8091C0018823E1F39CB91092C001A3 |
:100D800008951092C6011092C50108958091C50181 |
:100D90009091C601892B19F48FEF90E0089580E0BF |
:100DA00090E008951F920F920FB60F9211242F9387 |
:100DB0003F934F935F936F937F938F939F93AF93E3 |
:100DC000BF93EF93FF936CB18091B1019091B20109 |
:100DD000892B39F0E091B101F091B201862F09958C |
:100DE0000EC081EC91E098DA882349F48091D20119 |
:100DF0009091D30101969093D3018093D201FF91FA |
:100E0000EF91BF91AF919F918F917F916F915F9182 |
:100E10004F913F912F910F900FBE0F901F901895FB |
:100E2000682F8AEC91E078DA992708951F920F9243 |
:100E30000FB60F9211242F933F934F935F936F93AD |
:100E40007F938F939F93AF93BF93EF93FF93809183 |
:100E5000C901882369F08091CE019091CF01892B3F |
:100E600029F08AEC91E0F4D98CB905C01092C9013F |
:100E70008FEF8093C001FF91EF91BF91AF919F9150 |
:100E80008F917F916F915F914F913F912F910F9033 |
:100E90000FBE0F901F901895CF93DF93EC018091B8 |
:100EA000C3019091C401892B69F08091C501909193 |
:100EB000C601892B39F081EC91E0CAD988838FEF84 |
:100EC00090E002C080E090E0DF91CF910895CF9351 |
:100ED000DF93CDB7DEB721970FB6F894DEBF0FBE14 |
:100EE000CDBFCE010196D8DF882319F48FEF9FEF95 |
:100EF00002C08981992721960FB6F894DEBF0FBEF4 |
:100F0000CDBFDF91CF9108954FEF50E062E770E0E1 |
:100F100081EC91E090D940E450E061E771E08AEC27 |
:100F200091E089D90895F0DF1092B2011092B101D9 |
:100F300088ED8AB960E875E280E090E0FADE8FEF34 |
:100F40008093C0011092C9011092D3011092D20176 |
:100F5000789408958FEF8093C9018AEC91E078D955 |
:100F6000982F8091C0018823E1F39CB91092C001B1 |
:100F7000089577277F936F9399279F938F9383E5A6 |
:100F800090E09F938F9381E08F9342DB8DB79EB764 |
:100F900007960FB6F8949EBF0FBE8DBF08958823A5 |
:100FA00019F083E690E002C08CE590E09F938F9368 |
:100FB00081E08F932DDB0F900F900F90089599276C |
:100FC0009F938F938AE690E09F938F9381E08F9316 |
:100FD0001FDB0F900F900F900F900F90089580E7F8 |
:100FE00090E021DA089585E790E01DDA0895FB018D |
:100FF000DC010D900020E9F7119701900D9200207F |
:10100000E1F70895FB019F01E8944230BCF04532BE |
:10101000ACF44A3029F497FB1EF4909581959F4FCC |
:10102000642F77273DD0805D8A330CF0895D8193F2 |
:10103000CB010097A9F716F45DE251931082C90124 |
:1010400000C0DC01FC01672F71917723E1F7329733 |
:1010500004C07C916D9370836291AE17BF07C8F393 |
:101060000895629FD001739FF001829FE00DF11DF2 |
:10107000649FE00DF11D929FF00D839FF00D749F12 |
:10108000F00D659FF00D9927729FB00DE11DF91FBE |
:10109000639FB00DE11DF91FBD01CF01112408951B |
:1010A000AA1BBB1B51E107C0AA1FBB1FA617B7078E |
:1010B00010F0A61BB70B881F991F5A95A9F78095AA |
:1010C0009095BC01CD010895A1E21A2EAA1BBB1B6D |
:1010D000FD010DC0AA1FBB1FEE1FFF1FA217B30704 |
:1010E000E407F50720F0A21BB30BE40BF50B661F1A |
:1010F000771F881F991F1A9469F7609570958095DE |
:1011000090959B01AC01BD01CF01089597FB092E7D |
:1011100005260ED057FD04D0D7DF0AD0001C38F4C6 |
:1011200050954095309521953F4F4F4F5F4F089513 |
:10113000F6F790958095709561957F4F8F4F9F4FF3 |
:041140000895FFCF40 |
:021144000D009C |
:00000001FF |
/Designs/Data_loggers/GPSRL02A/SW/buffer/gpsrl.map |
---|
0,0 → 1,540 |
Archive member included because of file (symbol) |
/usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_mulsi3.o) |
timer.o (__mulsi3) |
/usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_udivmodhi4.o) |
buffer.o (__udivmodhi4) |
/usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_udivmodsi4.o) |
rprintf.o (__udivmodsi4) |
/usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_divmodsi4.o) |
timer.o (__divmodsi4) |
/usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_exit.o) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/crtm8.o (exit) |
/usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_copy_data.o) |
a2d.o (__do_copy_data) |
/usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_clear_bss.o) |
a2d.o (__do_clear_bss) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(strcat.o) |
a2dtest.o (strcat) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(itoa.o) |
a2dtest.o (itoa) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(strrev.o) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(itoa.o) (strrev) |
Allocating common symbols |
Common symbol size file |
uartReadyTx 0x1 uart.o |
Timer0Reg0 0x4 timer.o |
uartRxBuffer 0x8 uart.o |
TimerPauseReg 0x4 timer.o |
Timer2Reg0 0x4 timer.o |
uartBufferedTx 0x1 uart.o |
a2dCompleteFlag 0x1 a2d.o |
uartTxBuffer 0x8 uart.o |
uartRxOverflow 0x2 uart.o |
Memory Configuration |
Name Origin Length Attributes |
text 0x00000000 0x00002000 xr |
data 0x00800060 0x0000ffa0 rw !x |
eeprom 0x00810000 0x00010000 rw !x |
fuse 0x00820000 0x00000400 rw !x |
lock 0x00830000 0x00000400 rw !x |
signature 0x00840000 0x00000400 rw !x |
*default* 0x00000000 0xffffffff |
Linker script and memory map |
LOAD /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/crtm8.o |
LOAD a2d.o |
LOAD a2dtest.o |
LOAD buffer.o |
LOAD rprintf.o |
LOAD timer.o |
LOAD uart.o |
LOAD vt100.o |
LOAD /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a |
LOAD /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a |
LOAD /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a |
.hash |
*(.hash) |
.dynsym |
*(.dynsym) |
.dynstr |
*(.dynstr) |
.gnu.version |
*(.gnu.version) |
.gnu.version_d |
*(.gnu.version_d) |
.gnu.version_r |
*(.gnu.version_r) |
.rel.init |
*(.rel.init) |
.rela.init |
*(.rela.init) |
.rel.text |
*(.rel.text) |
*(.rel.text.*) |
*(.rel.gnu.linkonce.t*) |
.rela.text |
*(.rela.text) |
*(.rela.text.*) |
*(.rela.gnu.linkonce.t*) |
.rel.fini |
*(.rel.fini) |
.rela.fini |
*(.rela.fini) |
.rel.rodata |
*(.rel.rodata) |
*(.rel.rodata.*) |
*(.rel.gnu.linkonce.r*) |
.rela.rodata |
*(.rela.rodata) |
*(.rela.rodata.*) |
*(.rela.gnu.linkonce.r*) |
.rel.data |
*(.rel.data) |
*(.rel.data.*) |
*(.rel.gnu.linkonce.d*) |
.rela.data |
*(.rela.data) |
*(.rela.data.*) |
*(.rela.gnu.linkonce.d*) |
.rel.ctors |
*(.rel.ctors) |
.rela.ctors |
*(.rela.ctors) |
.rel.dtors |
*(.rel.dtors) |
.rela.dtors |
*(.rela.dtors) |
.rel.got |
*(.rel.got) |
.rela.got |
*(.rela.got) |
.rel.bss |
*(.rel.bss) |
.rela.bss |
*(.rela.bss) |
.rel.plt |
*(.rel.plt) |
.rela.plt |
*(.rela.plt) |
.text 0x00000000 0x1144 |
*(.vectors) |
.vectors 0x00000000 0x26 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/crtm8.o |
0x00000000 __vectors |
0x00000000 __vector_default |
*(.vectors) |
*(.progmem.gcc*) |
*(.progmem*) |
.progmem.data 0x00000026 0x11 rprintf.o |
.progmem.data 0x00000037 0x1c timer.o |
0x00000043 TimerRTCPrescaleFactor |
0x00000037 TimerPrescaleFactor |
.progmem.data 0x00000053 0x25 vt100.o |
0x00000078 . = ALIGN (0x2) |
0x00000078 __trampolines_start = . |
*(.trampolines) |
.trampolines 0x00000078 0x0 linker stubs |
*(.trampolines*) |
0x00000078 __trampolines_end = . |
*(.jumptables) |
*(.jumptables*) |
*(.lowtext) |
*(.lowtext*) |
0x00000078 __ctors_start = . |
*(.ctors) |
0x00000078 __ctors_end = . |
0x00000078 __dtors_start = . |
*(.dtors) |
0x00000078 __dtors_end = . |
SORT(*)(.ctors) |
SORT(*)(.dtors) |
*(.init0) |
.init0 0x00000078 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/crtm8.o |
0x00000078 __init |
*(.init0) |
*(.init1) |
*(.init1) |
*(.init2) |
.init2 0x00000078 0xc /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/crtm8.o |
*(.init2) |
*(.init3) |
*(.init3) |
*(.init4) |
.init4 0x00000084 0x16 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_copy_data.o) |
0x00000084 __do_copy_data |
.init4 0x0000009a 0x10 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_clear_bss.o) |
0x0000009a __do_clear_bss |
*(.init4) |
*(.init5) |
*(.init5) |
*(.init6) |
*(.init6) |
*(.init7) |
*(.init7) |
*(.init8) |
*(.init8) |
*(.init9) |
.init9 0x000000aa 0x4 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/crtm8.o |
*(.init9) |
*(.text) |
.text 0x000000ae 0x2 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/crtm8.o |
0x000000ae __vector_1 |
0x000000ae __vector_12 |
0x000000ae __bad_interrupt |
0x000000ae __vector_17 |
0x000000ae __vector_2 |
0x000000ae __vector_15 |
0x000000ae __vector_10 |
0x000000ae __vector_16 |
0x000000ae __vector_18 |
.text 0x000000b0 0xae a2d.o |
0x000000e4 a2dIsComplete |
0x00000116 a2dConvert8bit |
0x000000b0 a2dOff |
0x000000b6 a2dSetPrescaler |
0x000000ee a2dConvert10bit |
0x00000142 a2dInit |
0x000000c0 a2dSetReference |
0x00000124 __vector_14 |
0x000000d2 a2dSetChannel |
0x000000de a2dStartConvert |
.text 0x0000015e 0xd8 a2dtest.o |
0x0000015e main |
.text 0x00000236 0x156 buffer.o |
0x00000368 bufferIsNotFull |
0x00000250 bufferGetFromFront |
0x000002f0 bufferGetAtIndex |
0x000002ac bufferDumpFromFront |
0x00000236 bufferInit |
0x00000318 bufferAddToEnd |
0x0000037e bufferFlush |
.text 0x0000038c 0x3b2 rprintf.o |
0x00000610 rprintf1RamRom |
0x0000045e rprintfu08 |
0x00000486 rprintfu32 |
0x000003ba rprintfStr |
0x000003d6 rprintfStrLen |
0x00000426 rprintfProgStr |
0x00000470 rprintfu16 |
0x0000038c rprintfInit |
0x00000396 rprintfChar |
0x00000444 rprintfCRLF |
0x0000044a rprintfu04 |
0x000004a8 rprintfNum |
.text 0x0000073e 0x5ea timer.o |
0x0000094a timer2GetOverflowCount |
0x0000080e timerDetach |
0x000007a2 timer1SetPrescaler |
0x000009dc timer1PWMBOff |
0x000007e2 timer2GetPrescaler |
0x00000b76 __vector_6 |
0x00000740 timer0Init |
0x000009ce timer1PWMAOff |
0x000009f0 timer1PWMBSet |
0x00000c84 __vector_3 |
0x0000098c timer1PWMInitICR |
0x000007b6 timer0GetPrescaler |
0x00000bd0 __vector_7 |
0x00000926 timer0GetOverflowCount |
0x00000c2a __vector_5 |
0x00000cde timerInit |
0x000007ac timer2SetPrescaler |
0x000009b2 timer1PWMAOn |
0x00000798 timer0SetPrescaler |
0x0000073e delay_us |
0x00000af6 __vector_4 |
0x00000914 timer0ClearOverflowCount |
0x000009f6 __vector_9 |
0x00000762 timer1Init |
0x0000095c timer1PWMInit |
0x000009c0 timer1PWMBOn |
0x00000776 timer2Init |
0x00000a9c __vector_8 |
0x000009ea timer1PWMASet |
0x000007f8 timerAttach |
0x00000d02 timer1PWMOff |
0x000007cc timer1GetPrescaler |
0x00000938 timer2ClearOverflowCount |
0x00000824 timerPause |
.text 0x00000d28 0x24a uart.o |
0x00000f54 uartSendTxBuffer |
0x00000d70 uartSendByte |
0x00000f08 uartInitBuffers |
0x00000e98 uartReceiveByte |
0x00000e20 uartAddToTxBuffer |
0x00000da4 __vector_11 |
0x00000d28 uartSetRxHandler |
0x00000e2c __vector_13 |
0x00000d82 uartFlushReceiveBuffer |
0x00000f26 uartInit |
0x00000d8c uartReceiveBufferIsEmpty |
0x00000d32 uartSetBaudRate |
0x00000d6a uartGetTxBuffer |
0x00000ece uartGetByte |
0x00000d64 uartGetRxBuffer |
.text 0x00000f72 0x7c vt100.o |
0x00000fe6 vt100Init |
0x00000fbe vt100SetAttr |
0x00000f9e vt100SetCursorMode |
0x00000f72 vt100SetCursorPos |
0x00000fde vt100ClearScreen |
.text 0x00000fee 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_mulsi3.o) |
.text 0x00000fee 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_udivmodhi4.o) |
.text 0x00000fee 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_udivmodsi4.o) |
.text 0x00000fee 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_divmodsi4.o) |
.text 0x00000fee 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_exit.o) |
.text 0x00000fee 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_copy_data.o) |
.text 0x00000fee 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_clear_bss.o) |
.text 0x00000fee 0x16 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(strcat.o) |
0x00000fee strcat |
.text 0x00001004 0x3e /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(itoa.o) |
0x00001004 itoa |
.text 0x00001042 0x20 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(strrev.o) |
0x00001042 strrev |
0x00001062 . = ALIGN (0x2) |
*(.text.*) |
.text.libgcc 0x00001062 0x3e /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_mulsi3.o) |
0x00001062 __mulsi3 |
.text.libgcc 0x000010a0 0x28 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_udivmodhi4.o) |
0x000010a0 __udivmodhi4 |
.text.libgcc 0x000010c8 0x44 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_udivmodsi4.o) |
0x000010c8 __udivmodsi4 |
.text.libgcc 0x0000110c 0x36 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_divmodsi4.o) |
0x0000110c __divmodsi4 |
.text.libgcc 0x00001142 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_exit.o) |
.text.libgcc 0x00001142 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_copy_data.o) |
.text.libgcc 0x00001142 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_clear_bss.o) |
0x00001142 . = ALIGN (0x2) |
*(.fini9) |
.fini9 0x00001142 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_exit.o) |
0x00001142 exit |
0x00001142 _exit |
*(.fini9) |
*(.fini8) |
*(.fini8) |
*(.fini7) |
*(.fini7) |
*(.fini6) |
*(.fini6) |
*(.fini5) |
*(.fini5) |
*(.fini4) |
*(.fini4) |
*(.fini3) |
*(.fini3) |
*(.fini2) |
*(.fini2) |
*(.fini1) |
*(.fini1) |
*(.fini0) |
.fini0 0x00001142 0x2 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_exit.o) |
*(.fini0) |
0x00001144 _etext = . |
.data 0x00800060 0x2 load address 0x00001144 |
0x00800060 PROVIDE (__data_start, .) |
*(.data) |
.data 0x00800060 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/crtm8.o |
.data 0x00800060 0x0 a2d.o |
.data 0x00800060 0x2 a2dtest.o |
.data 0x00800062 0x0 buffer.o |
.data 0x00800062 0x0 rprintf.o |
.data 0x00800062 0x0 timer.o |
.data 0x00800062 0x0 uart.o |
.data 0x00800062 0x0 vt100.o |
.data 0x00800062 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_mulsi3.o) |
.data 0x00800062 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_udivmodhi4.o) |
.data 0x00800062 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_udivmodsi4.o) |
.data 0x00800062 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_divmodsi4.o) |
.data 0x00800062 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_exit.o) |
.data 0x00800062 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_copy_data.o) |
.data 0x00800062 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_clear_bss.o) |
.data 0x00800062 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(strcat.o) |
.data 0x00800062 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(itoa.o) |
.data 0x00800062 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(strrev.o) |
*(.data*) |
*(.rodata) |
*(.rodata*) |
*(.gnu.linkonce.d*) |
0x00800062 . = ALIGN (0x2) |
0x00800062 _edata = . |
0x00800062 PROVIDE (__data_end, .) |
.bss 0x00800062 0x172 load address 0x00001146 |
0x00800062 PROVIDE (__bss_start, .) |
*(.bss) |
.bss 0x00800062 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/crtm8.o |
.bss 0x00800062 0x0 a2d.o |
.bss 0x00800062 0x0 a2dtest.o |
.bss 0x00800062 0x0 buffer.o |
.bss 0x00800062 0x2 rprintf.o |
.bss 0x00800064 0xe timer.o |
.bss 0x00800072 0x141 uart.o |
.bss 0x008001b3 0x0 vt100.o |
.bss 0x008001b3 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_mulsi3.o) |
.bss 0x008001b3 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_udivmodhi4.o) |
.bss 0x008001b3 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_udivmodsi4.o) |
.bss 0x008001b3 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_divmodsi4.o) |
.bss 0x008001b3 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_exit.o) |
.bss 0x008001b3 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_copy_data.o) |
.bss 0x008001b3 0x0 /usr/lib/gcc/avr/4.2.2/avr4/libgcc.a(_clear_bss.o) |
.bss 0x008001b3 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(strcat.o) |
.bss 0x008001b3 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(itoa.o) |
.bss 0x008001b3 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(strrev.o) |
*(.bss*) |
*(COMMON) |
COMMON 0x008001b3 0x1 a2d.o |
0x008001b3 a2dCompleteFlag |
COMMON 0x008001b4 0xc timer.o |
0x008001b4 Timer0Reg0 |
0x008001b8 TimerPauseReg |
0x008001bc Timer2Reg0 |
COMMON 0x008001c0 0x14 uart.o |
0x008001c0 uartReadyTx |
0x008001c1 uartRxBuffer |
0x008001c9 uartBufferedTx |
0x008001ca uartTxBuffer |
0x008001d2 uartRxOverflow |
0x008001d4 PROVIDE (__bss_end, .) |
0x00001144 __data_load_start = LOADADDR (.data) |
0x00001146 __data_load_end = (__data_load_start + SIZEOF (.data)) |
.noinit 0x008001d4 0x0 |
0x008001d4 PROVIDE (__noinit_start, .) |
*(.noinit*) |
0x008001d4 PROVIDE (__noinit_end, .) |
0x008001d4 _end = . |
0x008001d4 PROVIDE (__heap_start, .) |
.eeprom 0x00810000 0x0 |
*(.eeprom*) |
0x00810000 __eeprom_end = . |
.fuse |
*(.fuse) |
*(.lfuse) |
*(.hfuse) |
*(.efuse) |
.lock |
*(.lock*) |
.signature |
*(.signature*) |
.stab 0x00000000 0x3db0 |
*(.stab) |
.stab 0x00000000 0x378 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/crtm8.o |
.stab 0x00000378 0x7a4 a2d.o |
0x7b0 (size before relaxing) |
.stab 0x00000b1c 0x48c a2dtest.o |
0x72c (size before relaxing) |
.stab 0x00000fa8 0x660 buffer.o |
0x924 (size before relaxing) |
.stab 0x00001608 0x9c0 rprintf.o |
0xcf0 (size before relaxing) |
.stab 0x00001fc8 0xf54 timer.o |
0x129c (size before relaxing) |
.stab 0x00002f1c 0x834 uart.o |
0xb04 (size before relaxing) |
.stab 0x00003750 0x33c vt100.o |
0x684 (size before relaxing) |
.stab 0x00003a8c 0x9c /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(strcat.o) |
0xa8 (size before relaxing) |
.stab 0x00003b28 0x1b0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(itoa.o) |
0x1bc (size before relaxing) |
.stab 0x00003cd8 0xd8 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/libc.a(strrev.o) |
0xe4 (size before relaxing) |
.stabstr 0x00000000 0x1b97 |
*(.stabstr) |
.stabstr 0x00000000 0x1b97 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr4/crtm8.o |
.stab.excl |
*(.stab.excl) |
.stab.exclstr |
*(.stab.exclstr) |
.stab.index |
*(.stab.index) |
.stab.indexstr |
*(.stab.indexstr) |
.comment |
*(.comment) |
.debug |
*(.debug) |
.line |
*(.line) |
.debug_srcinfo |
*(.debug_srcinfo) |
.debug_sfnames |
*(.debug_sfnames) |
.debug_aranges |
*(.debug_aranges) |
.debug_pubnames |
*(.debug_pubnames) |
.debug_info |
*(.debug_info) |
*(.gnu.linkonce.wi.*) |
.debug_abbrev |
*(.debug_abbrev) |
.debug_line |
*(.debug_line) |
.debug_frame |
*(.debug_frame) |
.debug_str |
*(.debug_str) |
.debug_loc |
*(.debug_loc) |
.debug_macinfo |
*(.debug_macinfo) |
OUTPUT(gpsrl.out elf32-avr) |
LOAD linker stubs |
/Designs/Data_loggers/GPSRL02A/SW/buffer/gpsrl.out |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/Makefile |
---|
0,0 → 1,51 |
NAME := gpsrl |
HEX := $(NAME).hex |
OUT := $(NAME).out |
MAP := $(NAME).map |
SOURCES := $(wildcard *.c) |
HEADERS := $(wildcard *.h) |
OBJECTS := $(patsubst %.c,%.o,$(SOURCES)) |
MCU := atmega8 |
MCU_AVRDUDE := m8 |
CC := avr-gcc |
OBJCOPY := avr-objcopy |
SIZE := avr-size -A |
DOXYGEN := doxygen |
CFLAGS := -Wall -pedantic -mmcu=$(MCU) -std=c99 -g -Os |
all: $(HEX) |
clean: |
rm -f $(HEX) $(OUT) $(MAP) $(OBJECTS) |
rm -rf doc/html |
flash: $(HEX) |
avrdude -y -p $(MCU_AVRDUDE) -P /dev/ttyUSB0 -c stk500v2 -U flash:w:$(HEX) |
$(HEX): $(OUT) |
$(OBJCOPY) -R .eeprom -O ihex $< $@ |
$(OUT): $(OBJECTS) |
$(CC) $(CFLAGS) -o $@ -Wl,-Map,$(MAP) $^ |
@echo |
@$(SIZE) $@ |
@echo |
%.o: %.c $(HEADERS) |
$(CC) $(CFLAGS) -c -o $@ $< |
%.pp: %.c |
$(CC) $(CFLAGS) -E -o $@ $< |
%.ppo: %.c |
$(CC) $(CFLAGS) -E $< |
doc: $(HEADERS) $(SOURCES) Doxyfile |
$(DOXYGEN) Doxyfile |
.PHONY: all clean flash doc |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/a2d.c |
---|
0,0 → 1,115 |
/*! \file a2d.c \brief Analog-to-Digital converter function library. */ |
//***************************************************************************** |
// |
// File Name : 'a2d.c' |
// Title : Analog-to-digital converter functions |
// Author : Pascal Stang - Copyright (C) 2002 |
// Created : 2002-04-08 |
// Revised : 2002-09-30 |
// Version : 1.1 |
// Target MCU : Atmel AVR series |
// Editor Tabs : 4 |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
//***************************************************************************** |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include "global.h" |
#include "a2d.h" |
// global variables |
//! Software flag used to indicate when |
/// the a2d conversion is complete. |
volatile unsigned char a2dCompleteFlag; |
// functions |
// initialize a2d converter |
void a2dInit(void) |
{ |
sbi(ADCSR, ADEN); // enable ADC (turn on ADC power) |
cbi(ADCSR, ADFR); // default to single sample convert mode |
a2dSetPrescaler(ADC_PRESCALE); // set default prescaler |
a2dSetReference(ADC_REFERENCE); // set default reference |
cbi(ADMUX, ADLAR); // set to right-adjusted result |
sbi(ADCSR, ADIE); // enable ADC interrupts |
a2dCompleteFlag = FALSE; // clear conversion complete flag |
sei(); // turn on interrupts (if not already on) |
} |
// turn off a2d converter |
void a2dOff(void) |
{ |
cbi(ADCSR, ADIE); // disable ADC interrupts |
cbi(ADCSR, ADEN); // disable ADC (turn off ADC power) |
} |
// configure A2D converter clock division (prescaling) |
void a2dSetPrescaler(unsigned char prescale) |
{ |
outb(ADCSR, ((inb(ADCSR) & ~ADC_PRESCALE_MASK) | prescale)); |
} |
// configure A2D converter voltage reference |
void a2dSetReference(unsigned char ref) |
{ |
outb(ADMUX, ((inb(ADMUX) & ~ADC_REFERENCE_MASK) | (ref<<6))); |
} |
// sets the a2d input channel |
void a2dSetChannel(unsigned char ch) |
{ |
outb(ADMUX, (inb(ADMUX) & ~ADC_MUX_MASK) | (ch & ADC_MUX_MASK)); // set channel |
} |
// start a conversion on the current a2d input channel |
void a2dStartConvert(void) |
{ |
sbi(ADCSR, ADIF); // clear hardware "conversion complete" flag |
sbi(ADCSR, ADSC); // start conversion |
} |
// return TRUE if conversion is complete |
u08 a2dIsComplete(void) |
{ |
return bit_is_set(ADCSR, ADSC); |
} |
// Perform a 10-bit conversion |
// starts conversion, waits until conversion is done, and returns result |
unsigned short a2dConvert10bit(unsigned char ch) |
{ |
a2dCompleteFlag = FALSE; // clear conversion complete flag |
outb(ADMUX, (inb(ADMUX) & ~ADC_MUX_MASK) | (ch & ADC_MUX_MASK)); // set channel |
sbi(ADCSR, ADIF); // clear hardware "conversion complete" flag |
sbi(ADCSR, ADSC); // start conversion |
//while(!a2dCompleteFlag); // wait until conversion complete |
//while( bit_is_clear(ADCSR, ADIF) ); // wait until conversion complete |
while( bit_is_set(ADCSR, ADSC) ); // wait until conversion complete |
// CAUTION: MUST READ ADCL BEFORE ADCH!!! |
return (inb(ADCL) | (inb(ADCH)<<8)); // read ADC (full 10 bits); |
} |
// Perform a 8-bit conversion. |
// starts conversion, waits until conversion is done, and returns result |
unsigned char a2dConvert8bit(unsigned char ch) |
{ |
// do 10-bit conversion and return highest 8 bits |
return a2dConvert10bit(ch)>>2; // return ADC MSB byte |
} |
//! Interrupt handler for ADC complete interrupt. |
SIGNAL(SIG_ADC) |
{ |
// set the a2d conversion flag to indicate "complete" |
a2dCompleteFlag = TRUE; |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/a2d.h |
---|
0,0 → 1,151 |
/*! \file a2d.h \brief Analog-to-Digital converter function library. */ |
//***************************************************************************** |
// |
// File Name : 'a2d.h' |
// Title : Analog-to-digital converter functions |
// Author : Pascal Stang - Copyright (C) 2002 |
// Created : 4/08/2002 |
// Revised : 4/30/2002 |
// Version : 1.1 |
// Target MCU : Atmel AVR series |
// Editor Tabs : 4 |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
/// \ingroup driver_avr |
/// \defgroup a2d A/D Converter Function Library (a2d.c) |
/// \code #include "a2d.h" \endcode |
/// \par Overview |
/// This library provides an easy interface to the analog-to-digital |
/// converter available on many AVR processors. Updated to support |
/// the ATmega128. |
// |
//**************************************************************************** |
//@{ |
#ifndef A2D_H |
#define A2D_H |
// defines |
// A2D clock prescaler select |
// *selects how much the CPU clock frequency is divided |
// to create the A2D clock frequency |
// *lower division ratios make conversion go faster |
// *higher division ratios make conversions more accurate |
#define ADC_PRESCALE_DIV2 0x00 ///< 0x01,0x00 -> CPU clk/2 |
#define ADC_PRESCALE_DIV4 0x02 ///< 0x02 -> CPU clk/4 |
#define ADC_PRESCALE_DIV8 0x03 ///< 0x03 -> CPU clk/8 |
#define ADC_PRESCALE_DIV16 0x04 ///< 0x04 -> CPU clk/16 |
#define ADC_PRESCALE_DIV32 0x05 ///< 0x05 -> CPU clk/32 |
#define ADC_PRESCALE_DIV64 0x06 ///< 0x06 -> CPU clk/64 |
#define ADC_PRESCALE_DIV128 0x07 ///< 0x07 -> CPU clk/128 |
// default value |
#define ADC_PRESCALE ADC_PRESCALE_DIV64 |
// do not change the mask value |
#define ADC_PRESCALE_MASK 0x07 |
// A2D voltage reference select |
// *this determines what is used as the |
// full-scale voltage point for A2D conversions |
#define ADC_REFERENCE_AREF 0x00 ///< 0x00 -> AREF pin, internal VREF turned off |
#define ADC_REFERENCE_AVCC 0x01 ///< 0x01 -> AVCC pin, internal VREF turned off |
#define ADC_REFERENCE_RSVD 0x02 ///< 0x02 -> Reserved |
#define ADC_REFERENCE_256V 0x03 ///< 0x03 -> Internal 2.56V VREF |
// default value |
#define ADC_REFERENCE ADC_REFERENCE_AVCC |
// do not change the mask value |
#define ADC_REFERENCE_MASK 0xC0 |
// bit mask for A2D channel multiplexer |
#define ADC_MUX_MASK 0x1F |
// channel defines (for reference and use in code) |
// these channels supported by all AVRs with A2D |
#define ADC_CH_ADC0 0x00 |
#define ADC_CH_ADC1 0x01 |
#define ADC_CH_ADC2 0x02 |
#define ADC_CH_ADC3 0x03 |
#define ADC_CH_ADC4 0x04 |
#define ADC_CH_ADC5 0x05 |
#define ADC_CH_ADC6 0x06 |
#define ADC_CH_ADC7 0x07 |
#define ADC_CH_122V 0x1E ///< 1.22V voltage reference |
#define ADC_CH_AGND 0x1F ///< AGND |
// these channels supported only in ATmega128 |
// differential with gain |
#define ADC_CH_0_0_DIFF10X 0x08 |
#define ADC_CH_1_0_DIFF10X 0x09 |
#define ADC_CH_0_0_DIFF200X 0x0A |
#define ADC_CH_1_0_DIFF200X 0x0B |
#define ADC_CH_2_2_DIFF10X 0x0C |
#define ADC_CH_3_2_DIFF10X 0x0D |
#define ADC_CH_2_2_DIFF200X 0x0E |
#define ADC_CH_3_2_DIFF200X 0x0F |
// differential |
#define ADC_CH_0_1_DIFF1X 0x10 |
#define ADC_CH_1_1_DIFF1X 0x11 |
#define ADC_CH_2_1_DIFF1X 0x12 |
#define ADC_CH_3_1_DIFF1X 0x13 |
#define ADC_CH_4_1_DIFF1X 0x14 |
#define ADC_CH_5_1_DIFF1X 0x15 |
#define ADC_CH_6_1_DIFF1X 0x16 |
#define ADC_CH_7_1_DIFF1X 0x17 |
#define ADC_CH_0_2_DIFF1X 0x18 |
#define ADC_CH_1_2_DIFF1X 0x19 |
#define ADC_CH_2_2_DIFF1X 0x1A |
#define ADC_CH_3_2_DIFF1X 0x1B |
#define ADC_CH_4_2_DIFF1X 0x1C |
#define ADC_CH_5_2_DIFF1X 0x1D |
// compatibility for new Mega processors |
// ADCSR hack apparently no longer necessary in new AVR-GCC |
#ifdef ADCSRA |
#ifndef ADCSR |
#define ADCSR ADCSRA |
#endif |
#endif |
#ifdef ADATE |
#define ADFR ADATE |
#endif |
// function prototypes |
//! Initializes the A/D converter. |
/// Turns ADC on and prepares it for use. |
void a2dInit(void); |
//! Turn off A/D converter |
void a2dOff(void); |
//! Sets the division ratio of the A/D converter clock. |
/// This function is automatically called from a2dInit() |
/// with a default value. |
void a2dSetPrescaler(unsigned char prescale); |
//! Configures which voltage reference the A/D converter uses. |
/// This function is automatically called from a2dInit() |
/// with a default value. |
void a2dSetReference(unsigned char ref); |
//! sets the a2d input channel |
void a2dSetChannel(unsigned char ch); |
//! start a conversion on the current a2d input channel |
void a2dStartConvert(void); |
//! return TRUE if conversion is complete |
u08 a2dIsComplete(void); |
//! Starts a conversion on A/D channel# ch, |
/// returns the 10-bit value of the conversion when it is finished. |
unsigned short a2dConvert10bit(unsigned char ch); |
//! Starts a conversion on A/D channel# ch, |
/// returns the 8-bit value of the conversion when it is finished. |
unsigned char a2dConvert8bit(unsigned char ch); |
#endif |
//@} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/avrlibdefs.h |
---|
0,0 → 1,83 |
/*! \file avrlibdefs.h \brief AVRlib global defines and macros. */ |
//***************************************************************************** |
// |
// File Name : 'avrlibdefs.h' |
// Title : AVRlib global defines and macros include file |
// Author : Pascal Stang |
// Created : 7/12/2001 |
// Revised : 9/30/2002 |
// Version : 1.1 |
// Target MCU : Atmel AVR series |
// Editor Tabs : 4 |
// |
// Description : This include file is designed to contain items useful to all |
// code files and projects, regardless of specific implementation. |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
//***************************************************************************** |
#ifndef AVRLIBDEFS_H |
#define AVRLIBDEFS_H |
// Code compatibility to new AVR-libc |
// outb(), inb(), inw(), outw(), BV(), sbi(), cbi(), sei(), cli() |
#ifndef outb |
#define outb(addr, data) addr = (data) |
#endif |
#ifndef inb |
#define inb(addr) (addr) |
#endif |
#ifndef outw |
#define outw(addr, data) addr = (data) |
#endif |
#ifndef inw |
#define inw(addr) (addr) |
#endif |
#ifndef BV |
#define BV(bit) (1<<(bit)) |
#endif |
#ifndef cbi |
#define cbi(reg,bit) reg &= ~(BV(bit)) |
#endif |
#ifndef sbi |
#define sbi(reg,bit) reg |= (BV(bit)) |
#endif |
#ifndef cli |
#define cli() __asm__ __volatile__ ("cli" ::) |
#endif |
#ifndef sei |
#define sei() __asm__ __volatile__ ("sei" ::) |
#endif |
// support for individual port pin naming in the mega128 |
// see port128.h for details |
#ifdef __AVR_ATmega128__ |
// not currently necessary due to inclusion |
// of these defines in newest AVR-GCC |
// do a quick test to see if include is needed |
#ifndef PD0 |
#include "port128.h" |
#endif |
#endif |
// use this for packed structures |
// (this is seldom necessary on an 8-bit architecture like AVR, |
// but can assist in code portability to AVR) |
#define GNUC_PACKED __attribute__((packed)) |
// port address helpers |
#define DDR(x) ((x)-1) // address of data direction register of port x |
#define PIN(x) ((x)-2) // address of input register of port x |
// MIN/MAX/ABS macros |
#define MIN(a,b) ((a<b)?(a):(b)) |
#define MAX(a,b) ((a>b)?(a):(b)) |
#define ABS(x) ((x>0)?(x):(-x)) |
// constants |
#define PI 3.14159265359 |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/avrlibtypes.h |
---|
0,0 → 1,84 |
/*! \file avrlibtypes.h \brief AVRlib global types and typedefines. */ |
//***************************************************************************** |
// |
// File Name : 'avrlibtypes.h' |
// Title : AVRlib global types and typedefines include file |
// Author : Pascal Stang |
// Created : 7/12/2001 |
// Revised : 9/30/2002 |
// Version : 1.0 |
// Target MCU : Atmel AVR series |
// Editor Tabs : 4 |
// |
// Description : Type-defines required and used by AVRlib. Most types are also |
// generally useful. |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
//***************************************************************************** |
#ifndef AVRLIBTYPES_H |
#define AVRLIBTYPES_H |
#ifndef WIN32 |
// true/false defines |
#define FALSE 0 |
#define TRUE -1 |
#endif |
// datatype definitions macros |
typedef unsigned char u08; |
typedef signed char s08; |
typedef unsigned short u16; |
typedef signed short s16; |
typedef unsigned long u32; |
typedef signed long s32; |
typedef unsigned long long u64; |
typedef signed long long s64; |
/* use inttypes.h instead |
// C99 standard integer type definitions |
typedef unsigned char uint8_t; |
typedef signed char int8_t; |
typedef unsigned short uint16_t; |
typedef signed short int16_t; |
typedef unsigned long uint32_t; |
typedef signed long int32_t; |
typedef unsigned long uint64_t; |
typedef signed long int64_t; |
*/ |
// maximum value that can be held |
// by unsigned data types (8,16,32bits) |
#define MAX_U08 255 |
#define MAX_U16 65535 |
#define MAX_U32 4294967295 |
// maximum values that can be held |
// by signed data types (8,16,32bits) |
#define MIN_S08 -128 |
#define MAX_S08 127 |
#define MIN_S16 -32768 |
#define MAX_S16 32767 |
#define MIN_S32 -2147483648 |
#define MAX_S32 2147483647 |
#ifndef WIN32 |
// more type redefinitions |
typedef unsigned char BOOL; |
typedef unsigned char BYTE; |
typedef unsigned int WORD; |
typedef unsigned long DWORD; |
typedef unsigned char UCHAR; |
typedef unsigned int UINT; |
typedef unsigned short USHORT; |
typedef unsigned long ULONG; |
typedef char CHAR; |
typedef int INT; |
typedef long LONG; |
#endif |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/buffer.c |
---|
0,0 → 1,149 |
/*! \file buffer.c \brief Multipurpose byte buffer structure and methods. */ |
//***************************************************************************** |
// |
// File Name : 'buffer.c' |
// Title : Multipurpose byte buffer structure and methods |
// Author : Pascal Stang - Copyright (C) 2001-2002 |
// Created : 9/23/2001 |
// Revised : 9/23/2001 |
// Version : 1.0 |
// Target MCU : any |
// Editor Tabs : 4 |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
//***************************************************************************** |
#include "buffer.h" |
#include "global.h" |
#include "avr/io.h" |
#ifndef CRITICAL_SECTION_START |
#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli() |
#define CRITICAL_SECTION_END SREG = _sreg |
#endif |
// global variables |
// initialization |
void bufferInit(cBuffer* buffer, unsigned char *start, unsigned short size) |
{ |
// begin critical section |
CRITICAL_SECTION_START; |
// set start pointer of the buffer |
buffer->dataptr = start; |
buffer->size = size; |
// initialize index and length |
buffer->dataindex = 0; |
buffer->datalength = 0; |
// end critical section |
CRITICAL_SECTION_END; |
} |
// access routines |
unsigned char bufferGetFromFront(cBuffer* buffer) |
{ |
unsigned char data = 0; |
// begin critical section |
CRITICAL_SECTION_START; |
// check to see if there's data in the buffer |
if(buffer->datalength) |
{ |
// get the first character from buffer |
data = buffer->dataptr[buffer->dataindex]; |
// move index down and decrement length |
buffer->dataindex++; |
if(buffer->dataindex >= buffer->size) |
{ |
buffer->dataindex -= buffer->size; |
} |
buffer->datalength--; |
} |
// end critical section |
CRITICAL_SECTION_END; |
// return |
return data; |
} |
void bufferDumpFromFront(cBuffer* buffer, unsigned short numbytes) |
{ |
// begin critical section |
CRITICAL_SECTION_START; |
// dump numbytes from the front of the buffer |
// are we dumping less than the entire buffer? |
if(numbytes < buffer->datalength) |
{ |
// move index down by numbytes and decrement length by numbytes |
buffer->dataindex += numbytes; |
if(buffer->dataindex >= buffer->size) |
{ |
buffer->dataindex -= buffer->size; |
} |
buffer->datalength -= numbytes; |
} |
else |
{ |
// flush the whole buffer |
buffer->datalength = 0; |
} |
// end critical section |
CRITICAL_SECTION_END; |
} |
unsigned char bufferGetAtIndex(cBuffer* buffer, unsigned short index) |
{ |
// begin critical section |
CRITICAL_SECTION_START; |
// return character at index in buffer |
unsigned char data = buffer->dataptr[(buffer->dataindex+index)%(buffer->size)]; |
// end critical section |
CRITICAL_SECTION_END; |
return data; |
} |
unsigned char bufferAddToEnd(cBuffer* buffer, unsigned char data) |
{ |
// begin critical section |
CRITICAL_SECTION_START; |
// make sure the buffer has room |
if(buffer->datalength < buffer->size) |
{ |
// save data byte at end of buffer |
buffer->dataptr[(buffer->dataindex + buffer->datalength) % buffer->size] = data; |
// increment the length |
buffer->datalength++; |
// end critical section |
CRITICAL_SECTION_END; |
// return success |
return -1; |
} |
// end critical section |
CRITICAL_SECTION_END; |
// return failure |
return 0; |
} |
unsigned short bufferIsNotFull(cBuffer* buffer) |
{ |
// begin critical section |
CRITICAL_SECTION_START; |
// check to see if the buffer has room |
// return true if there is room |
unsigned short bytesleft = (buffer->size - buffer->datalength); |
// end critical section |
CRITICAL_SECTION_END; |
return bytesleft; |
} |
void bufferFlush(cBuffer* buffer) |
{ |
// begin critical section |
CRITICAL_SECTION_START; |
// flush contents of the buffer |
buffer->datalength = 0; |
// end critical section |
CRITICAL_SECTION_END; |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/buffer.h |
---|
0,0 → 1,74 |
/*! \file buffer.h \brief Multipurpose byte buffer structure and methods. */ |
//***************************************************************************** |
// |
// File Name : 'buffer.h' |
// Title : Multipurpose byte buffer structure and methods |
// Author : Pascal Stang - Copyright (C) 2001-2002 |
// Created : 9/23/2001 |
// Revised : 11/16/2002 |
// Version : 1.1 |
// Target MCU : any |
// Editor Tabs : 4 |
// |
/// \ingroup general |
/// \defgroup buffer Circular Byte-Buffer Structure and Function Library (buffer.c) |
/// \code #include "buffer.h" \endcode |
/// \par Overview |
/// This byte-buffer structure provides an easy and efficient way to store |
/// and process a stream of bytes. You can create as many buffers as you |
/// like (within memory limits), and then use this common set of functions to |
/// access each buffer. The buffers are designed for FIFO operation (first |
/// in, first out). This means that the first byte you put in the buffer |
/// will be the first one you get when you read out the buffer. Supported |
/// functions include buffer initialize, get byte from front of buffer, add |
/// byte to end of buffer, check if buffer is full, and flush buffer. The |
/// buffer uses a circular design so no copying of data is ever necessary. |
/// This buffer is not dynamically allocated, it has a user-defined fixed |
/// maximum size. This buffer is used in many places in the avrlib code. |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
//***************************************************************************** |
//@{ |
#ifndef BUFFER_H |
#define BUFFER_H |
// structure/typdefs |
//! cBuffer structure |
typedef struct struct_cBuffer |
{ |
unsigned char *dataptr; ///< the physical memory address where the buffer is stored |
unsigned short size; ///< the allocated size of the buffer |
unsigned short datalength; ///< the length of the data currently in the buffer |
unsigned short dataindex; ///< the index into the buffer where the data starts |
} cBuffer; |
// function prototypes |
//! initialize a buffer to start at a given address and have given size |
void bufferInit(cBuffer* buffer, unsigned char *start, unsigned short size); |
//! get the first byte from the front of the buffer |
unsigned char bufferGetFromFront(cBuffer* buffer); |
//! dump (discard) the first numbytes from the front of the buffer |
void bufferDumpFromFront(cBuffer* buffer, unsigned short numbytes); |
//! get a byte at the specified index in the buffer (kind of like array access) |
// ** note: this does not remove the byte that was read from the buffer |
unsigned char bufferGetAtIndex(cBuffer* buffer, unsigned short index); |
//! add a byte to the end of the buffer |
unsigned char bufferAddToEnd(cBuffer* buffer, unsigned char data); |
//! check if the buffer is full/not full (returns zero value if full) |
unsigned short bufferIsNotFull(cBuffer* buffer); |
//! flush (clear) the contents of the buffer |
void bufferFlush(cBuffer* buffer); |
#endif |
//@} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/global.h |
---|
0,0 → 1,42 |
//***************************************************************************** |
// |
// File Name : 'global.h' |
// Title : AVR project global include |
// Author : Pascal Stang |
// Created : 7/12/2001 |
// Revised : 9/30/2002 |
// Version : 1.1 |
// Target MCU : Atmel AVR series |
// Editor Tabs : 4 |
// |
// Description : This include file is designed to contain items useful to all |
// code files and projects. |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
//***************************************************************************** |
#ifndef GLOBAL_H |
#define GLOBAL_H |
// global AVRLIB defines |
#include "avrlibdefs.h" |
// global AVRLIB types definitions |
#include "avrlibtypes.h" |
// project/system dependent defines |
#define UART_RX_BUFFER_SIZE 0x00FF |
// CPU clock speed |
//#define F_CPU 16000000 // 16MHz processor |
//#define F_CPU 14745000 // 14.745MHz processor |
#define F_CPU 8000000 // 8MHz processor |
//#define F_CPU 7372800 // 7.37MHz processor |
//#define F_CPU 4000000 // 4MHz processor |
//#define F_CPU 3686400 // 3.69MHz processor |
#define CYCLES_PER_US ((F_CPU+500000)/1000000) // cpu cycles per microsecond |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/rprintf.c |
---|
0,0 → 1,782 |
/*! \file rprintf.c \brief printf routine and associated routines. */ |
//***************************************************************************** |
// |
// File Name : 'rprintf.c' |
// Title : printf routine and associated routines |
// Author : Pascal Stang - Copyright (C) 2000-2002 |
// Created : 2000.12.26 |
// Revised : 2003.5.1 |
// Version : 1.0 |
// Target MCU : Atmel AVR series and other targets |
// Editor Tabs : 4 |
// |
// NOTE: This code is currently below version 1.0, and therefore is considered |
// to be lacking in some functionality or documentation, or may not be fully |
// tested. Nonetheless, you can expect most functions to work. |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
//***************************************************************************** |
#include <avr/pgmspace.h> |
//#include <string-avr.h> |
//#include <stdlib.h> |
#include <stdarg.h> |
#include "global.h" |
#include "rprintf.h" |
#ifndef TRUE |
#define TRUE -1 |
#define FALSE 0 |
#endif |
#define INF 32766 // maximum field size to print |
#define READMEMBYTE(a,char_ptr) ((a)?(pgm_read_byte(char_ptr)):(*char_ptr)) |
#ifdef RPRINTF_COMPLEX |
static unsigned char buf[128]; |
#endif |
// use this to store hex conversion in RAM |
//static char HexChars[] = "0123456789ABCDEF"; |
// use this to store hex conversion in program memory |
//static prog_char HexChars[] = "0123456789ABCDEF"; |
static char __attribute__ ((progmem)) HexChars[] = "0123456789ABCDEF"; |
#define hexchar(x) pgm_read_byte( HexChars+((x)&0x0f) ) |
//#define hexchar(x) ((((x)&0x0F)>9)?((x)+'A'-10):((x)+'0')) |
// function pointer to single character output routine |
static void (*rputchar)(unsigned char c); |
// *** rprintf initialization *** |
// you must call this function once and supply the character output |
// routine before using other functions in this library |
void rprintfInit(void (*putchar_func)(unsigned char c)) |
{ |
rputchar = putchar_func; |
} |
// *** rprintfChar *** |
// send a character/byte to the current output device |
void rprintfChar(unsigned char c) |
{ |
// do LF -> CR/LF translation |
if(c == '\n') |
rputchar('\r'); |
// send character |
rputchar(c); |
} |
// *** rprintfStr *** |
// prints a null-terminated string stored in RAM |
void rprintfStr(char str[]) |
{ |
// send a string stored in RAM |
// check to make sure we have a good pointer |
if (!str) return; |
// print the string until a null-terminator |
while (*str) |
rprintfChar(*str++); |
} |
// *** rprintfStrLen *** |
// prints a section of a string stored in RAM |
// begins printing at position indicated by <start> |
// prints number of characters indicated by <len> |
void rprintfStrLen(char str[], unsigned int start, unsigned int len) |
{ |
register int i=0; |
// check to make sure we have a good pointer |
if (!str) return; |
// spin through characters up to requested start |
// keep going as long as there's no null |
while((i++<start) && (*str++)); |
// for(i=0; i<start; i++) |
// { |
// // keep steping through string as long as there's no null |
// if(*str) str++; |
// } |
// then print exactly len characters |
for(i=0; i<len; i++) |
{ |
// print data out of the string as long as we haven't reached a null yet |
// at the null, start printing spaces |
if(*str) |
rprintfChar(*str++); |
else |
rprintfChar(' '); |
} |
} |
// *** rprintfProgStr *** |
// prints a null-terminated string stored in program ROM |
void rprintfProgStr(const prog_char str[]) |
{ |
// print a string stored in program memory |
register char c; |
// check to make sure we have a good pointer |
if (!str) return; |
// print the string until the null-terminator |
while((c = pgm_read_byte(str++))) |
rprintfChar(c); |
} |
// *** rprintfCRLF *** |
// prints carriage return and line feed |
void rprintfCRLF(void) |
{ |
// print CR/LF |
//rprintfChar('\r'); |
// LF -> CR/LF translation built-in to rprintfChar() |
rprintfChar('\n'); |
} |
// *** rprintfu04 *** |
// prints an unsigned 4-bit number in hex (1 digit) |
void rprintfu04(unsigned char data) |
{ |
// print 4-bit hex value |
// char Character = data&0x0f; |
// if (Character>9) |
// Character+='A'-10; |
// else |
// Character+='0'; |
rprintfChar(hexchar(data)); |
} |
// *** rprintfu08 *** |
// prints an unsigned 8-bit number in hex (2 digits) |
void rprintfu08(unsigned char data) |
{ |
// print 8-bit hex value |
rprintfu04(data>>4); |
rprintfu04(data); |
} |
// *** rprintfu16 *** |
// prints an unsigned 16-bit number in hex (4 digits) |
void rprintfu16(unsigned short data) |
{ |
// print 16-bit hex value |
rprintfu08(data>>8); |
rprintfu08(data); |
} |
// *** rprintfu32 *** |
// prints an unsigned 32-bit number in hex (8 digits) |
void rprintfu32(unsigned long data) |
{ |
// print 32-bit hex value |
rprintfu16(data>>16); |
rprintfu16(data); |
} |
// *** rprintfNum *** |
// special printf for numbers only |
// see formatting information below |
// Print the number "n" in the given "base" |
// using exactly "numDigits" |
// print +/- if signed flag "isSigned" is TRUE |
// use the character specified in "padchar" to pad extra characters |
// |
// Examples: |
// uartPrintfNum(10, 6, TRUE, ' ', 1234); --> " +1234" |
// uartPrintfNum(10, 6, FALSE, '0', 1234); --> "001234" |
// uartPrintfNum(16, 6, FALSE, '.', 0x5AA5); --> "..5AA5" |
void rprintfNum(char base, char numDigits, char isSigned, char padchar, long n) |
{ |
// define a global HexChars or use line below |
//static char HexChars[16] = "0123456789ABCDEF"; |
char *p, buf[32]; |
unsigned long x; |
unsigned char count; |
// prepare negative number |
if( isSigned && (n < 0) ) |
{ |
x = -n; |
} |
else |
{ |
x = n; |
} |
// setup little string buffer |
count = (numDigits-1)-(isSigned?1:0); |
p = buf + sizeof (buf); |
*--p = '\0'; |
// force calculation of first digit |
// (to prevent zero from not printing at all!!!) |
*--p = hexchar(x%base); x /= base; |
// calculate remaining digits |
while(count--) |
{ |
if(x != 0) |
{ |
// calculate next digit |
*--p = hexchar(x%base); x /= base; |
} |
else |
{ |
// no more digits left, pad out to desired length |
*--p = padchar; |
} |
} |
// apply signed notation if requested |
if( isSigned ) |
{ |
if(n < 0) |
{ |
*--p = '-'; |
} |
else if(n > 0) |
{ |
*--p = '+'; |
} |
else |
{ |
*--p = ' '; |
} |
} |
// print the string right-justified |
count = numDigits; |
while(count--) |
{ |
rprintfChar(*p++); |
} |
} |
#ifdef RPRINTF_FLOAT |
// *** rprintfFloat *** |
// floating-point print |
void rprintfFloat(char numDigits, double x) |
{ |
unsigned char firstplace = FALSE; |
unsigned char negative; |
unsigned char i, digit; |
double place = 1.0; |
// save sign |
negative = (x<0); |
// convert to absolute value |
x = (x>0)?(x):(-x); |
// find starting digit place |
for(i=0; i<15; i++) |
{ |
if((x/place) < 10.0) |
break; |
else |
place *= 10.0; |
} |
// print polarity character |
if(negative) |
rprintfChar('-'); |
else |
rprintfChar('+'); |
// print digits |
for(i=0; i<numDigits; i++) |
{ |
digit = (x/place); |
if(digit | firstplace | (place == 1.0)) |
{ |
firstplace = TRUE; |
rprintfChar(digit+0x30); |
} |
else |
rprintfChar(' '); |
if(place == 1.0) |
{ |
rprintfChar('.'); |
} |
x -= (digit*place); |
place /= 10.0; |
} |
} |
#endif |
#ifdef RPRINTF_SIMPLE |
// *** rprintf1RamRom *** |
// called by rprintf() - does a simple printf (supports %d, %x, %c) |
// Supports: |
// %d - decimal |
// %x - hex |
// %c - character |
int rprintf1RamRom(unsigned char stringInRom, const char *format, ...) |
{ |
// simple printf routine |
// define a global HexChars or use line below |
//static char HexChars[16] = "0123456789ABCDEF"; |
char format_flag; |
unsigned int u_val, div_val, base; |
va_list ap; |
va_start(ap, format); |
for (;;) |
{ |
while ((format_flag = READMEMBYTE(stringInRom,format++) ) != '%') |
{ // Until '%' or '\0' |
if (!format_flag) |
{ |
va_end(ap); |
return(0); |
} |
rprintfChar(format_flag); |
} |
switch (format_flag = READMEMBYTE(stringInRom,format++) ) |
{ |
case 'c': format_flag = va_arg(ap,int); |
default: rprintfChar(format_flag); continue; |
case 'd': base = 10; div_val = 10000; goto CONVERSION_LOOP; |
// case 'x': base = 16; div_val = 0x10; |
case 'x': base = 16; div_val = 0x1000; |
CONVERSION_LOOP: |
u_val = va_arg(ap,int); |
if (format_flag == 'd') |
{ |
if (((int)u_val) < 0) |
{ |
u_val = - u_val; |
rprintfChar('-'); |
} |
while (div_val > 1 && div_val > u_val) div_val /= 10; |
} |
do |
{ |
//rprintfChar(pgm_read_byte(HexChars+(u_val/div_val))); |
rprintfu04(u_val/div_val); |
u_val %= div_val; |
div_val /= base; |
} while (div_val); |
} |
} |
va_end(ap); |
} |
#endif |
#ifdef RPRINTF_COMPLEX |
// *** rprintf2RamRom *** |
// called by rprintf() - does a more powerful printf (supports %d, %u, %o, %x, %c, %s) |
// Supports: |
// %d - decimal |
// %u - unsigned decimal |
// %o - octal |
// %x - hex |
// %c - character |
// %s - strings |
// and the width,precision,padding modifiers |
// **this printf does not support floating point numbers |
int rprintf2RamRom(unsigned char stringInRom, const char *sfmt, ...) |
{ |
register unsigned char *f, *bp; |
register long l; |
register unsigned long u; |
register int i; |
register int fmt; |
register unsigned char pad = ' '; |
int flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; |
int sign = 0; |
va_list ap; |
va_start(ap, sfmt); |
f = (unsigned char *) sfmt; |
for (; READMEMBYTE(stringInRom,f); f++) |
{ |
if (READMEMBYTE(stringInRom,f) != '%') |
{ // not a format character |
// then just output the char |
rprintfChar(READMEMBYTE(stringInRom,f)); |
} |
else |
{ |
f++; // if we have a "%" then skip it |
if (READMEMBYTE(stringInRom,f) == '-') |
{ |
flush_left = 1; // minus: flush left |
f++; |
} |
if (READMEMBYTE(stringInRom,f) == '0' |
|| READMEMBYTE(stringInRom,f) == '.') |
{ |
// padding with 0 rather than blank |
pad = '0'; |
f++; |
} |
if (READMEMBYTE(stringInRom,f) == '*') |
{ // field width |
f_width = va_arg(ap, int); |
f++; |
} |
else if (Isdigit(READMEMBYTE(stringInRom,f))) |
{ |
f_width = atoiRamRom(stringInRom, (char *) f); |
while (Isdigit(READMEMBYTE(stringInRom,f))) |
f++; // skip the digits |
} |
if (READMEMBYTE(stringInRom,f) == '.') |
{ // precision |
f++; |
if (READMEMBYTE(stringInRom,f) == '*') |
{ |
prec = va_arg(ap, int); |
f++; |
} |
else if (Isdigit(READMEMBYTE(stringInRom,f))) |
{ |
prec = atoiRamRom(stringInRom, (char *) f); |
while (Isdigit(READMEMBYTE(stringInRom,f))) |
f++; // skip the digits |
} |
} |
if (READMEMBYTE(stringInRom,f) == '#') |
{ // alternate form |
hash = 1; |
f++; |
} |
if (READMEMBYTE(stringInRom,f) == 'l') |
{ // long format |
do_long = 1; |
f++; |
} |
fmt = READMEMBYTE(stringInRom,f); |
bp = buf; |
switch (fmt) { // do the formatting |
case 'd': // 'd' signed decimal |
if (do_long) |
l = va_arg(ap, long); |
else |
l = (long) (va_arg(ap, int)); |
if (l < 0) |
{ |
sign = 1; |
l = -l; |
} |
do { |
*bp++ = l % 10 + '0'; |
} while ((l /= 10) > 0); |
if (sign) |
*bp++ = '-'; |
f_width = f_width - (bp - buf); |
if (!flush_left) |
while (f_width-- > 0) |
rprintfChar(pad); |
for (bp--; bp >= buf; bp--) |
rprintfChar(*bp); |
if (flush_left) |
while (f_width-- > 0) |
rprintfChar(' '); |
break; |
case 'o': // 'o' octal number |
case 'x': // 'x' hex number |
case 'u': // 'u' unsigned decimal |
if (do_long) |
u = va_arg(ap, unsigned long); |
else |
u = (unsigned long) (va_arg(ap, unsigned)); |
if (fmt == 'u') |
{ // unsigned decimal |
do { |
*bp++ = u % 10 + '0'; |
} while ((u /= 10) > 0); |
} |
else if (fmt == 'o') |
{ // octal |
do { |
*bp++ = u % 8 + '0'; |
} while ((u /= 8) > 0); |
if (hash) |
*bp++ = '0'; |
} |
else if (fmt == 'x') |
{ // hex |
do { |
i = u % 16; |
if (i < 10) |
*bp++ = i + '0'; |
else |
*bp++ = i - 10 + 'a'; |
} while ((u /= 16) > 0); |
if (hash) |
{ |
*bp++ = 'x'; |
*bp++ = '0'; |
} |
} |
i = f_width - (bp - buf); |
if (!flush_left) |
while (i-- > 0) |
rprintfChar(pad); |
for (bp--; bp >= buf; bp--) |
rprintfChar((int) (*bp)); |
if (flush_left) |
while (i-- > 0) |
rprintfChar(' '); |
break; |
case 'c': // 'c' character |
i = va_arg(ap, int); |
rprintfChar((int) (i)); |
break; |
case 's': // 's' string |
bp = va_arg(ap, unsigned char *); |
if (!bp) |
bp = (unsigned char *) "(nil)"; |
f_width = f_width - strlen((char *) bp); |
if (!flush_left) |
while (f_width-- > 0) |
rprintfChar(pad); |
for (i = 0; *bp && i < prec; i++) |
{ |
rprintfChar(*bp); |
bp++; |
} |
if (flush_left) |
while (f_width-- > 0) |
rprintfChar(' '); |
break; |
case '%': // '%' character |
rprintfChar('%'); |
break; |
} |
flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; |
sign = 0; |
pad = ' '; |
} |
} |
va_end(ap); |
return 0; |
} |
unsigned char Isdigit(char c) |
{ |
if((c >= 0x30) && (c <= 0x39)) |
return TRUE; |
else |
return FALSE; |
} |
int atoiRamRom(unsigned char stringInRom, char *str) |
{ |
int num = 0;; |
while(Isdigit(READMEMBYTE(stringInRom,str))) |
{ |
num *= 10; |
num += ((READMEMBYTE(stringInRom,str++)) - 0x30); |
} |
return num; |
} |
#endif |
//****************************************************************************** |
// code below this line is commented out and can be ignored |
//****************************************************************************** |
/* |
char* sprintf(const char *sfmt, ...) |
{ |
register unsigned char *f, *bp, *str; |
register long l; |
register unsigned long u; |
register int i; |
register int fmt; |
register unsigned char pad = ' '; |
int flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; |
int sign = 0; |
va_list ap; |
va_start(ap, sfmt); |
str = bufstring; |
f = (unsigned char *) sfmt; |
for (; *f; f++) |
{ |
if (*f != '%') |
{ // not a format character |
*str++ = (*f); // then just output the char |
} |
else |
{ |
f++; // if we have a "%" then skip it |
if (*f == '-') |
{ |
flush_left = 1; // minus: flush left |
f++; |
} |
if (*f == '0' || *f == '.') |
{ |
// padding with 0 rather than blank |
pad = '0'; |
f++; |
} |
if (*f == '*') |
{ // field width |
f_width = va_arg(ap, int); |
f++; |
} |
else if (Isdigit(*f)) |
{ |
f_width = atoi((char *) f); |
while (Isdigit(*f)) |
f++; // skip the digits |
} |
if (*f == '.') |
{ // precision |
f++; |
if (*f == '*') |
{ |
prec = va_arg(ap, int); |
f++; |
} |
else if (Isdigit(*f)) |
{ |
prec = atoi((char *) f); |
while (Isdigit(*f)) |
f++; // skip the digits |
} |
} |
if (*f == '#') |
{ // alternate form |
hash = 1; |
f++; |
} |
if (*f == 'l') |
{ // long format |
do_long = 1; |
f++; |
} |
fmt = *f; |
bp = buf; |
switch (fmt) { // do the formatting |
case 'd': // 'd' signed decimal |
if (do_long) |
l = va_arg(ap, long); |
else |
l = (long) (va_arg(ap, int)); |
if (l < 0) |
{ |
sign = 1; |
l = -l; |
} |
do { |
*bp++ = l % 10 + '0'; |
} while ((l /= 10) > 0); |
if (sign) |
*bp++ = '-'; |
f_width = f_width - (bp - buf); |
if (!flush_left) |
while (f_width-- > 0) |
*str++ = (pad); |
for (bp--; bp >= buf; bp--) |
*str++ = (*bp); |
if (flush_left) |
while (f_width-- > 0) |
*str++ = (' '); |
break; |
case 'o': // 'o' octal number |
case 'x': // 'x' hex number |
case 'u': // 'u' unsigned decimal |
if (do_long) |
u = va_arg(ap, unsigned long); |
else |
u = (unsigned long) (va_arg(ap, unsigned)); |
if (fmt == 'u') |
{ // unsigned decimal |
do { |
*bp++ = u % 10 + '0'; |
} while ((u /= 10) > 0); |
} |
else if (fmt == 'o') |
{ // octal |
do { |
*bp++ = u % 8 + '0'; |
} while ((u /= 8) > 0); |
if (hash) |
*bp++ = '0'; |
} |
else if (fmt == 'x') |
{ // hex |
do { |
i = u % 16; |
if (i < 10) |
*bp++ = i + '0'; |
else |
*bp++ = i - 10 + 'a'; |
} while ((u /= 16) > 0); |
if (hash) |
{ |
*bp++ = 'x'; |
*bp++ = '0'; |
} |
} |
i = f_width - (bp - buf); |
if (!flush_left) |
while (i-- > 0) |
*str++ = (pad); |
for (bp--; bp >= buf; bp--) |
*str++ = ((int) (*bp)); |
if (flush_left) |
while (i-- > 0) |
*str++ = (' '); |
break; |
case 'c': // 'c' character |
i = va_arg(ap, int); |
*str++ = ((int) (i)); |
break; |
case 's': // 's' string |
bp = va_arg(ap, unsigned char *); |
if (!bp) |
bp = (unsigned char *) "(nil)"; |
f_width = f_width - strlen((char *) bp); |
if (!flush_left) |
while (f_width-- > 0) |
*str++ = (pad); |
for (i = 0; *bp && i < prec; i++) |
{ |
*str++ = (*bp); |
bp++; |
} |
if (flush_left) |
while (f_width-- > 0) |
*str++ = (' '); |
break; |
case '%': // '%' character |
*str++ = ('%'); |
break; |
} |
flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; |
sign = 0; |
pad = ' '; |
} |
} |
va_end(ap); |
// terminate string with null |
*str++ = '\0'; |
return bufstring; |
} |
*/ |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/rprintf.h |
---|
0,0 → 1,191 |
/*! \file rprintf.h \brief printf routine and associated routines. */ |
//**************************************************************************** |
// |
// File Name : 'rprintf.h' |
// Title : printf routine and associated routines |
// Author : Pascal Stang - Copyright (C) 2000-2002 |
// Created : 2000.12.26 |
// Revised : 2003.5.1 |
// Version : 1.0 |
// Target MCU : Atmel AVR series and other targets |
// Editor Tabs : 4 |
// |
// NOTE: This code is currently below version 1.0, and therefore is considered |
// to be lacking in some functionality or documentation, or may not be fully |
// tested. Nonetheless, you can expect most functions to work. |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
/// \ingroup general |
/// \defgroup rprintf printf() Function Library (rprintf.c) |
/// \code #include "rprintf.h" \endcode |
/// \par Overview |
/// The rprintf function library provides a simplified (reduced) version of |
/// the common C printf() function. See the code files for details about |
/// which printf features are supported. Also in this library are a |
/// variety of functions for fast printing of certain common data types |
/// (variable types). Functions include print string from RAM, print |
/// string from ROM, print string snippet, print hex byte/short/long, and |
/// a custom-formatted number print, as well as an optional floating-point |
/// print routine. |
/// |
/// \note All output from the rprintf library can be directed to any device |
/// or software which accepts characters. This means that rprintf output |
/// can be sent to the UART (serial port) or can be used with the LCD |
/// display libraries to print formatted text on the screen. |
// |
//**************************************************************************** |
//@{ |
#ifndef RPRINTF_H |
#define RPRINTF_H |
// needed for use of PSTR below |
#include <avr/pgmspace.h> |
// configuration |
// defining RPRINTF_SIMPLE will compile a smaller, simpler, and faster printf() function |
// defining RPRINTF_COMPLEX will compile a larger, more capable, and slower printf() function |
#ifndef RPRINTF_COMPLEX |
#define RPRINTF_SIMPLE |
#endif |
// Define RPRINTF_FLOAT to enable the floating-point printf function: rprintfFloat() |
// (adds +4600bytes or 2.2Kwords of code) |
// defines/constants |
#define STRING_IN_RAM 0 |
#define STRING_IN_ROM 1 |
// make a putchar for those that are used to using it |
//#define putchar(c) rprintfChar(c); |
// functions |
//! Initializes the rprintf library for an output stream. |
/// You must call this initializer once before using any other rprintf function. |
/// The argument must be a character stream output function. |
void rprintfInit(void (*putchar_func)(unsigned char c)); |
//! prints a single character to the current output device |
void rprintfChar(unsigned char c); |
//! prints a null-terminated string stored in RAM |
void rprintfStr(char str[]); |
//! Prints a section of a string stored in RAM. |
/// Begins printing at position indicated by <start>, |
/// and prints number of characters indicated by <len>. |
void rprintfStrLen(char str[], unsigned int start, unsigned int len); |
//! prints a string stored in program rom |
/// \note This function does not actually store your string in |
/// program rom, but merely reads it assuming you stored it properly. |
void rprintfProgStr(const prog_char str[]); |
//! Using the function rprintfProgStrM(...) automatically causes |
/// your string to be stored in ROM, thereby not wasting precious RAM. |
/// Example usage: |
/// \code |
/// rprintfProgStrM("Hello, this string is stored in program rom"); |
/// \endcode |
#define rprintfProgStrM(string) (rprintfProgStr(PSTR(string))) |
//! Prints a carriage-return and line-feed. |
/// Useful when printing to serial ports/terminals. |
void rprintfCRLF(void); |
// Prints the number contained in "data" in hex format |
// u04,u08,u16,and u32 functions handle 4,8,16,or 32 bits respectively |
void rprintfu04(unsigned char data); ///< Print 4-bit hex number. Outputs a single hex character. |
void rprintfu08(unsigned char data); ///< Print 8-bit hex number. Outputs two hex characters. |
void rprintfu16(unsigned short data); ///< Print 16-bit hex number. Outputs four hex characters. |
void rprintfu32(unsigned long data); ///< Print 32-bit hex number. Outputs eight hex characters. |
//! A flexible integer-number printing routine. |
/// Print the number "n" in the given "base", using exactly "numDigits". |
/// Print +/- if signed flag "isSigned" is TRUE. |
/// The character specified in "padchar" will be used to pad extra characters. |
/// |
/// Examples: |
/// \code |
/// uartPrintfNum(10, 6, TRUE, ' ', 1234); --> " +1234" |
/// uartPrintfNum(10, 6, FALSE, '0', 1234); --> "001234" |
/// uartPrintfNum(16, 6, FALSE, '.', 0x5AA5); --> "..5AA5" |
/// \endcode |
void rprintfNum(char base, char numDigits, char isSigned, char padchar, long n); |
#ifdef RPRINTF_FLOAT |
//! floating-point print routine |
void rprintfFloat(char numDigits, double x); |
#endif |
// NOTE: Below you'll see the function prototypes of rprintf1RamRom and |
// rprintf2RamRom. rprintf1RamRom and rprintf2RamRom are both reduced versions |
// of the regular C printf() command. However, they are modified to be able |
// to read their text/format strings from RAM or ROM in the Atmel microprocessors. |
// Unless you really intend to, do not use the "RamRom" versions of the functions |
// directly. Instead use the #defined function versions: |
// |
// printfx("text/format",args) ...to keep your text/format string stored in RAM |
// - or - |
// printfxROM("text/format",args) ...to keep your text/format string stored in ROM |
// |
// where x is either 1 or 2 for the simple or more powerful version of printf() |
// |
// Since there is much more ROM than RAM available in the Atmel microprocessors, |
// and nearly all text/format strings are constant (never change in the course |
// of the program), you should try to use the ROM printf version exclusively. |
// This will ensure you leave as much RAM as possible for program variables and |
// data. |
//! \fn int rprintf(const char *format, ...); |
/// A reduced substitute for the usual C printf() function. |
/// This function actually points to either rprintf1RamRom or rprintf2RamRom |
/// depending on the user's selection. Rprintf1 is a simple small fast print |
/// routine while rprintf2 is larger and slower but more capable. To choose |
/// the routine you would like to use, define either RPRINTF_SIMPLE or |
/// RPRINTF_COMPLEX in global.h. |
#ifdef RPRINTF_SIMPLE |
//! A simple printf routine. |
/// Called by rprintf() - does a simple printf (supports %d, %x, %c). |
/// Supports: |
/// - %d - decimal |
/// - %x - hex |
/// - %c - character |
int rprintf1RamRom(unsigned char stringInRom, const char *format, ...); |
// #defines for RAM or ROM operation |
#define rprintf1(format, args...) rprintf1RamRom(STRING_IN_ROM, PSTR(format), ## args) |
#define rprintf1RAM(format, args...) rprintf1RamRom(STRING_IN_RAM, format, ## args) |
// *** Default rprintf(...) *** |
// this next line determines what the the basic rprintf() defaults to: |
#define rprintf(format, args...) rprintf1RamRom(STRING_IN_ROM, PSTR(format), ## args) |
#endif |
#ifdef RPRINTF_COMPLEX |
//! A more powerful printf routine. |
/// Called by rprintf() - does a more powerful printf (supports %d, %u, %o, %x, %c, %s). |
/// Supports: |
/// - %d - decimal |
/// - %u - unsigned decimal |
/// - %o - octal |
/// - %x - hex |
/// - %c - character |
/// - %s - strings |
/// - and the width,precision,padding modifiers |
/// \note This printf does not support floating point numbers. |
int rprintf2RamRom(unsigned char stringInRom, const char *sfmt, ...); |
// #defines for RAM or ROM operation |
#define rprintf2(format, args...) rprintf2RamRom(STRING_IN_ROM, format, ## args) |
#define rprintf2RAM(format, args...) rprintf2RamRom(STRING_IN_RAM, format, ## args) |
// *** Default rprintf(...) *** |
// this next line determines what the the basic rprintf() defaults to: |
#define rprintf(format, args...) rprintf2RamRom(STRING_IN_ROM, PSTR(format), ## args) |
#endif |
#endif |
//@} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/timer.c |
---|
0,0 → 1,469 |
/*! \file timer.c \brief System Timer function library. */ |
//***************************************************************************** |
// |
// File Name : 'timer.c' |
// Title : System Timer function library |
// Author : Pascal Stang - Copyright (C) 2000-2002 |
// Created : 11/22/2000 |
// Revised : 07/09/2003 |
// Version : 1.1 |
// Target MCU : Atmel AVR Series |
// Editor Tabs : 4 |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
//***************************************************************************** |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include <avr/pgmspace.h> |
#include <avr/sleep.h> |
#include "global.h" |
#include "timer.h" |
#include "rprintf.h" |
// Program ROM constants |
// the prescale division values stored in order of timer control register index |
// STOP, CLK, CLK/8, CLK/64, CLK/256, CLK/1024 |
unsigned short __attribute__ ((progmem)) TimerPrescaleFactor[] = {0,1,8,64,256,1024}; |
// the prescale division values stored in order of timer control register index |
// STOP, CLK, CLK/8, CLK/32, CLK/64, CLK/128, CLK/256, CLK/1024 |
unsigned short __attribute__ ((progmem)) TimerRTCPrescaleFactor[] = {0,1,8,32,64,128,256,1024}; |
// Global variables |
// time registers |
volatile unsigned long TimerPauseReg; |
volatile unsigned long Timer0Reg0; |
volatile unsigned long Timer2Reg0; |
typedef void (*voidFuncPtr)(void); |
volatile static voidFuncPtr TimerIntFunc[TIMER_NUM_INTERRUPTS]; |
// delay for a minimum of <us> microseconds |
// the time resolution is dependent on the time the loop takes |
// e.g. with 4Mhz and 5 cycles per loop, the resolution is 1.25 us |
void delay_us(unsigned short time_us) |
{ |
unsigned short delay_loops; |
register unsigned short i; |
delay_loops = (time_us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty) |
// one loop takes 5 cpu cycles |
for (i=0; i < delay_loops; i++) {}; |
} |
/* |
void delay_ms(unsigned char time_ms) |
{ |
unsigned short delay_count = F_CPU / 4000; |
unsigned short cnt; |
asm volatile ("\n" |
"L_dl1%=:\n\t" |
"mov %A0, %A2\n\t" |
"mov %B0, %B2\n" |
"L_dl2%=:\n\t" |
"sbiw %A0, 1\n\t" |
"brne L_dl2%=\n\t" |
"dec %1\n\t" "brne L_dl1%=\n\t":"=&w" (cnt) |
:"r"(time_ms), "r"((unsigned short) (delay_count)) |
); |
} |
*/ |
void timerInit(void) |
{ |
u08 intNum; |
// detach all user functions from interrupts |
for(intNum=0; intNum<TIMER_NUM_INTERRUPTS; intNum++) |
timerDetach(intNum); |
// initialize all timers |
timer0Init(); |
timer1Init(); |
#ifdef TCNT2 // support timer2 only if it exists |
timer2Init(); |
#endif |
// enable interrupts |
sei(); |
} |
void timer0Init() |
{ |
// initialize timer 0 |
timer0SetPrescaler( TIMER0PRESCALE ); // set prescaler |
outb(TCNT0, 0); // reset TCNT0 |
sbi(TIMSK, TOIE0); // enable TCNT0 overflow interrupt |
timer0ClearOverflowCount(); // initialize time registers |
} |
void timer1Init(void) |
{ |
// initialize timer 1 |
timer1SetPrescaler( TIMER1PRESCALE ); // set prescaler |
outb(TCNT1H, 0); // reset TCNT1 |
outb(TCNT1L, 0); |
sbi(TIMSK, TOIE1); // enable TCNT1 overflow |
} |
#ifdef TCNT2 // support timer2 only if it exists |
void timer2Init(void) |
{ |
// initialize timer 2 |
timer2SetPrescaler( TIMER2PRESCALE ); // set prescaler |
outb(TCNT2, 0); // reset TCNT2 |
sbi(TIMSK, TOIE2); // enable TCNT2 overflow |
timer2ClearOverflowCount(); // initialize time registers |
} |
#endif |
void timer0SetPrescaler(u08 prescale) |
{ |
// set prescaler on timer 0 |
outb(TCCR0, (inb(TCCR0) & ~TIMER_PRESCALE_MASK) | prescale); |
} |
void timer1SetPrescaler(u08 prescale) |
{ |
// set prescaler on timer 1 |
outb(TCCR1B, (inb(TCCR1B) & ~TIMER_PRESCALE_MASK) | prescale); |
} |
#ifdef TCNT2 // support timer2 only if it exists |
void timer2SetPrescaler(u08 prescale) |
{ |
// set prescaler on timer 2 |
outb(TCCR2, (inb(TCCR2) & ~TIMER_PRESCALE_MASK) | prescale); |
} |
#endif |
u16 timer0GetPrescaler(void) |
{ |
// get the current prescaler setting |
return (pgm_read_word(TimerPrescaleFactor+(inb(TCCR0) & TIMER_PRESCALE_MASK))); |
} |
u16 timer1GetPrescaler(void) |
{ |
// get the current prescaler setting |
return (pgm_read_word(TimerPrescaleFactor+(inb(TCCR1B) & TIMER_PRESCALE_MASK))); |
} |
#ifdef TCNT2 // support timer2 only if it exists |
u16 timer2GetPrescaler(void) |
{ |
//TODO: can we assume for all 3-timer AVR processors, |
// that timer2 is the RTC timer? |
// get the current prescaler setting |
return (pgm_read_word(TimerRTCPrescaleFactor+(inb(TCCR2) & TIMER_PRESCALE_MASK))); |
} |
#endif |
void timerAttach(u08 interruptNum, void (*userFunc)(void) ) |
{ |
// make sure the interrupt number is within bounds |
if(interruptNum < TIMER_NUM_INTERRUPTS) |
{ |
// set the interrupt function to run |
// the supplied user's function |
TimerIntFunc[interruptNum] = userFunc; |
} |
} |
void timerDetach(u08 interruptNum) |
{ |
// make sure the interrupt number is within bounds |
if(interruptNum < TIMER_NUM_INTERRUPTS) |
{ |
// set the interrupt function to run nothing |
TimerIntFunc[interruptNum] = 0; |
} |
} |
/* |
u32 timerMsToTics(u16 ms) |
{ |
// calculate the prescaler division rate |
u16 prescaleDiv = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0))); |
// calculate the number of timer tics in x milliseconds |
return (ms*(F_CPU/(prescaleDiv*256)))/1000; |
} |
u16 timerTicsToMs(u32 tics) |
{ |
// calculate the prescaler division rate |
u16 prescaleDiv = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0))); |
// calculate the number of milliseconds in x timer tics |
return (tics*1000*(prescaleDiv*256))/F_CPU; |
} |
*/ |
void timerPause(unsigned short pause_ms) |
{ |
// pauses for exactly <pause_ms> number of milliseconds |
u08 timerThres; |
u32 ticRateHz; |
u32 pause; |
// capture current pause timer value |
timerThres = inb(TCNT0); |
// reset pause timer overflow count |
TimerPauseReg = 0; |
// calculate delay for [pause_ms] milliseconds |
// prescaler division = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0))) |
ticRateHz = F_CPU/timer0GetPrescaler(); |
// precision management |
// prevent overflow and precision underflow |
// -could add more conditions to improve accuracy |
if( ((ticRateHz < 429497) && (pause_ms <= 10000)) ) |
pause = (pause_ms*ticRateHz)/1000; |
else |
pause = pause_ms*(ticRateHz/1000); |
// loop until time expires |
while( ((TimerPauseReg<<8) | inb(TCNT0)) < (pause+timerThres) ) |
{ |
if( TimerPauseReg < (pause>>8)); |
{ |
// save power by idling the processor |
set_sleep_mode(SLEEP_MODE_IDLE); |
sleep_mode(); |
} |
} |
/* old inaccurate code, for reference |
// calculate delay for [pause_ms] milliseconds |
u16 prescaleDiv = 1<<(pgm_read_byte(TimerPrescaleFactor+inb(TCCR0))); |
u32 pause = (pause_ms*(F_CPU/(prescaleDiv*256)))/1000; |
TimerPauseReg = 0; |
while(TimerPauseReg < pause); |
*/ |
} |
void timer0ClearOverflowCount(void) |
{ |
// clear the timer overflow counter registers |
Timer0Reg0 = 0; // initialize time registers |
} |
long timer0GetOverflowCount(void) |
{ |
// return the current timer overflow count |
// (this is since the last timer0ClearOverflowCount() command was called) |
return Timer0Reg0; |
} |
#ifdef TCNT2 // support timer2 only if it exists |
void timer2ClearOverflowCount(void) |
{ |
// clear the timer overflow counter registers |
Timer2Reg0 = 0; // initialize time registers |
} |
long timer2GetOverflowCount(void) |
{ |
// return the current timer overflow count |
// (this is since the last timer2ClearOverflowCount() command was called) |
return Timer2Reg0; |
} |
#endif |
void timer1PWMInit(u08 bitRes) |
{ |
// configures timer1 for use with PWM output |
// on OC1A and OC1B pins |
// enable timer1 as 8,9,10bit PWM |
if(bitRes == 9) |
{ // 9bit mode |
sbi(TCCR1A,PWM11); |
cbi(TCCR1A,PWM10); |
} |
else if( bitRes == 10 ) |
{ // 10bit mode |
sbi(TCCR1A,PWM11); |
sbi(TCCR1A,PWM10); |
} |
else |
{ // default 8bit mode |
cbi(TCCR1A,PWM11); |
sbi(TCCR1A,PWM10); |
} |
// clear output compare value A |
outb(OCR1AH, 0); |
outb(OCR1AL, 0); |
// clear output compare value B |
outb(OCR1BH, 0); |
outb(OCR1BL, 0); |
} |
#ifdef WGM10 |
// include support for arbitrary top-count PWM |
// on new AVR processors that support it |
void timer1PWMInitICR(u16 topcount) |
{ |
// set PWM mode with ICR top-count |
cbi(TCCR1A,WGM10); |
sbi(TCCR1A,WGM11); |
sbi(TCCR1B,WGM12); |
sbi(TCCR1B,WGM13); |
// set top count value |
ICR1 = topcount; |
// clear output compare value A |
OCR1A = 0; |
// clear output compare value B |
OCR1B = 0; |
} |
#endif |
void timer1PWMOff(void) |
{ |
// turn off timer1 PWM mode |
cbi(TCCR1A,PWM11); |
cbi(TCCR1A,PWM10); |
// set PWM1A/B (OutputCompare action) to none |
timer1PWMAOff(); |
timer1PWMBOff(); |
} |
void timer1PWMAOn(void) |
{ |
// turn on channel A (OC1A) PWM output |
// set OC1A as non-inverted PWM |
sbi(TCCR1A,COM1A1); |
cbi(TCCR1A,COM1A0); |
} |
void timer1PWMBOn(void) |
{ |
// turn on channel B (OC1B) PWM output |
// set OC1B as non-inverted PWM |
sbi(TCCR1A,COM1B1); |
cbi(TCCR1A,COM1B0); |
} |
void timer1PWMAOff(void) |
{ |
// turn off channel A (OC1A) PWM output |
// set OC1A (OutputCompare action) to none |
cbi(TCCR1A,COM1A1); |
cbi(TCCR1A,COM1A0); |
} |
void timer1PWMBOff(void) |
{ |
// turn off channel B (OC1B) PWM output |
// set OC1B (OutputCompare action) to none |
cbi(TCCR1A,COM1B1); |
cbi(TCCR1A,COM1B0); |
} |
void timer1PWMASet(u16 pwmDuty) |
{ |
// set PWM (output compare) duty for channel A |
// this PWM output is generated on OC1A pin |
// NOTE: pwmDuty should be in the range 0-255 for 8bit PWM |
// pwmDuty should be in the range 0-511 for 9bit PWM |
// pwmDuty should be in the range 0-1023 for 10bit PWM |
//outp( (pwmDuty>>8), OCR1AH); // set the high 8bits of OCR1A |
//outp( (pwmDuty&0x00FF), OCR1AL); // set the low 8bits of OCR1A |
OCR1A = pwmDuty; |
} |
void timer1PWMBSet(u16 pwmDuty) |
{ |
// set PWM (output compare) duty for channel B |
// this PWM output is generated on OC1B pin |
// NOTE: pwmDuty should be in the range 0-255 for 8bit PWM |
// pwmDuty should be in the range 0-511 for 9bit PWM |
// pwmDuty should be in the range 0-1023 for 10bit PWM |
//outp( (pwmDuty>>8), OCR1BH); // set the high 8bits of OCR1B |
//outp( (pwmDuty&0x00FF), OCR1BL); // set the low 8bits of OCR1B |
OCR1B = pwmDuty; |
} |
//! Interrupt handler for tcnt0 overflow interrupt |
TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW0) |
{ |
Timer0Reg0++; // increment low-order counter |
// increment pause counter |
TimerPauseReg++; |
// if a user function is defined, execute it too |
if(TimerIntFunc[TIMER0OVERFLOW_INT]) |
TimerIntFunc[TIMER0OVERFLOW_INT](); |
} |
//! Interrupt handler for tcnt1 overflow interrupt |
TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW1) |
{ |
// if a user function is defined, execute it |
if(TimerIntFunc[TIMER1OVERFLOW_INT]) |
TimerIntFunc[TIMER1OVERFLOW_INT](); |
} |
#ifdef TCNT2 // support timer2 only if it exists |
//! Interrupt handler for tcnt2 overflow interrupt |
TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW2) |
{ |
Timer2Reg0++; // increment low-order counter |
// if a user function is defined, execute it |
if(TimerIntFunc[TIMER2OVERFLOW_INT]) |
TimerIntFunc[TIMER2OVERFLOW_INT](); |
} |
#endif |
#ifdef OCR0 |
// include support for Output Compare 0 for new AVR processors that support it |
//! Interrupt handler for OutputCompare0 match (OC0) interrupt |
TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE0) |
{ |
// if a user function is defined, execute it |
if(TimerIntFunc[TIMER0OUTCOMPARE_INT]) |
TimerIntFunc[TIMER0OUTCOMPARE_INT](); |
} |
#endif |
//! Interrupt handler for CutputCompare1A match (OC1A) interrupt |
TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE1A) |
{ |
// if a user function is defined, execute it |
if(TimerIntFunc[TIMER1OUTCOMPAREA_INT]) |
TimerIntFunc[TIMER1OUTCOMPAREA_INT](); |
} |
//! Interrupt handler for OutputCompare1B match (OC1B) interrupt |
TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE1B) |
{ |
// if a user function is defined, execute it |
if(TimerIntFunc[TIMER1OUTCOMPAREB_INT]) |
TimerIntFunc[TIMER1OUTCOMPAREB_INT](); |
} |
//! Interrupt handler for InputCapture1 (IC1) interrupt |
TIMER_INTERRUPT_HANDLER(SIG_INPUT_CAPTURE1) |
{ |
// if a user function is defined, execute it |
if(TimerIntFunc[TIMER1INPUTCAPTURE_INT]) |
TimerIntFunc[TIMER1INPUTCAPTURE_INT](); |
} |
//! Interrupt handler for OutputCompare2 match (OC2) interrupt |
TIMER_INTERRUPT_HANDLER(SIG_OUTPUT_COMPARE2) |
{ |
// if a user function is defined, execute it |
if(TimerIntFunc[TIMER2OUTCOMPARE_INT]) |
TimerIntFunc[TIMER2OUTCOMPARE_INT](); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/timer.h |
---|
0,0 → 1,314 |
/*! \file timer.h \brief System Timer function library. */ |
//***************************************************************************** |
// |
// File Name : 'timer.h' |
// Title : System Timer function library |
// Author : Pascal Stang - Copyright (C) 2000-2002 |
// Created : 11/22/2000 |
// Revised : 02/10/2003 |
// Version : 1.1 |
// Target MCU : Atmel AVR Series |
// Editor Tabs : 4 |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
/// \ingroup driver_avr |
/// \defgroup timer Timer Function Library (timer.c) |
/// \code #include "timer.h" \endcode |
/// \par Overview |
/// This library provides functions for use with the timers internal |
/// to the AVR processors. Functions include initialization, set prescaler, |
/// calibrated pause function (in milliseconds), attaching and detaching of |
/// user functions to interrupts, overflow counters, PWM. Arbitrary |
/// frequency generation has been moved to the Pulse Library. |
/// |
/// \par About Timers |
/// The Atmel AVR-series processors each contain at least one |
/// hardware timer/counter. Many of the processors contain 2 or 3 |
/// timers. Generally speaking, a timer is a hardware counter inside |
/// the processor which counts at a rate related to the main CPU clock |
/// frequency. Because the counter value increasing (counting up) at |
/// a precise rate, we can use it as a timer to create or measure |
/// precise delays, schedule events, or generate signals of a certain |
/// frequency or pulse-width. |
/// \par |
/// As an example, the ATmega163 processor has 3 timer/counters. |
/// Timer0, Timer1, and Timer2 are 8, 16, and 8 bits wide respectively. |
/// This means that they overflow, or roll over back to zero, at a |
/// count value of 256 for 8bits or 65536 for 16bits. A prescaler is |
/// avaiable for each timer, and the prescaler allows you to pre-divide |
/// the main CPU clock rate down to a slower speed before feeding it to |
/// the counting input of a timer. For example, if the CPU clock |
/// frequency is 3.69MHz, and Timer0's prescaler is set to divide-by-8, |
/// then Timer0 will "tic" at 3690000/8 = 461250Hz. Because Timer0 is |
/// an 8bit timer, it will count to 256 in just 256/461250Hz = 0.555ms. |
/// In fact, when it hits 255, it will overflow and start again at |
/// zero. In this case, Timer0 will overflow 461250/256 = 1801.76 |
/// times per second. |
/// \par |
/// Timer0 can be used a number of ways simultaneously. First, the |
/// value of the timer can be read by accessing the CPU register \c TCNT0. |
/// We could, for example, figure out how long it takes to execute a |
/// C command by recording the value of \c TCNT0 before and after |
/// execution, then subtract (after-before) = time elapsed. Or we can |
/// enable the overflow interrupt which goes off every time T0 |
/// overflows and count out longer delays (multiple overflows), or |
/// execute a special periodic function at every overflow. |
/// \par |
/// The other timers (Timer1 and Timer2) offer all the abilities of |
/// Timer0 and many more features. Both T1 and T2 can operate as |
/// general-purpose timers, but T1 has special hardware allowing it to |
/// generate PWM signals, while T2 is specially designed to help count |
/// out real time (like hours, minutes, seconds). See the |
/// Timer/Counter section of the processor datasheet for more info. |
/// |
//***************************************************************************** |
//@{ |
#ifndef TIMER_H |
#define TIMER_H |
#include "global.h" |
// constants/macros/typdefs |
// processor compatibility fixes |
#ifdef __AVR_ATmega323__ |
// redefinition for the Mega323 |
#define CTC1 CTC10 |
#endif |
#ifndef PWM10 |
// mega128 PWM bits |
#define PWM10 WGM10 |
#define PWM11 WGM11 |
#endif |
// Timer/clock prescaler values and timer overflow rates |
// tics = rate at which the timer counts up |
// 8bitoverflow = rate at which the timer overflows 8bits (or reaches 256) |
// 16bit [overflow] = rate at which the timer overflows 16bits (65536) |
// |
// overflows can be used to generate periodic interrupts |
// |
// for 8MHz crystal |
// 0 = STOP (Timer not counting) |
// 1 = CLOCK tics= 8MHz 8bitoverflow= 31250Hz 16bit= 122.070Hz |
// 2 = CLOCK/8 tics= 1MHz 8bitoverflow= 3906.25Hz 16bit= 15.259Hz |
// 3 = CLOCK/64 tics= 125kHz 8bitoverflow= 488.28Hz 16bit= 1.907Hz |
// 4 = CLOCK/256 tics= 31250Hz 8bitoverflow= 122.07Hz 16bit= 0.477Hz |
// 5 = CLOCK/1024 tics= 7812.5Hz 8bitoverflow= 30.52Hz 16bit= 0.119Hz |
// 6 = External Clock on T(x) pin (falling edge) |
// 7 = External Clock on T(x) pin (rising edge) |
// for 4MHz crystal |
// 0 = STOP (Timer not counting) |
// 1 = CLOCK tics= 4MHz 8bitoverflow= 15625Hz 16bit= 61.035Hz |
// 2 = CLOCK/8 tics= 500kHz 8bitoverflow= 1953.125Hz 16bit= 7.629Hz |
// 3 = CLOCK/64 tics= 62500Hz 8bitoverflow= 244.141Hz 16bit= 0.954Hz |
// 4 = CLOCK/256 tics= 15625Hz 8bitoverflow= 61.035Hz 16bit= 0.238Hz |
// 5 = CLOCK/1024 tics= 3906.25Hz 8bitoverflow= 15.259Hz 16bit= 0.060Hz |
// 6 = External Clock on T(x) pin (falling edge) |
// 7 = External Clock on T(x) pin (rising edge) |
// for 3.69MHz crystal |
// 0 = STOP (Timer not counting) |
// 1 = CLOCK tics= 3.69MHz 8bitoverflow= 14414Hz 16bit= 56.304Hz |
// 2 = CLOCK/8 tics= 461250Hz 8bitoverflow= 1801.758Hz 16bit= 7.038Hz |
// 3 = CLOCK/64 tics= 57625.25Hz 8bitoverflow= 225.220Hz 16bit= 0.880Hz |
// 4 = CLOCK/256 tics= 14414.063Hz 8bitoverflow= 56.305Hz 16bit= 0.220Hz |
// 5 = CLOCK/1024 tics= 3603.516Hz 8bitoverflow= 14.076Hz 16bit= 0.055Hz |
// 6 = External Clock on T(x) pin (falling edge) |
// 7 = External Clock on T(x) pin (rising edge) |
// for 32.768KHz crystal on timer 2 (use for real-time clock) |
// 0 = STOP |
// 1 = CLOCK tics= 32.768kHz 8bitoverflow= 128Hz |
// 2 = CLOCK/8 tics= 4096kHz 8bitoverflow= 16Hz |
// 3 = CLOCK/32 tics= 1024kHz 8bitoverflow= 4Hz |
// 4 = CLOCK/64 tics= 512Hz 8bitoverflow= 2Hz |
// 5 = CLOCK/128 tics= 256Hz 8bitoverflow= 1Hz |
// 6 = CLOCK/256 tics= 128Hz 8bitoverflow= 0.5Hz |
// 7 = CLOCK/1024 tics= 32Hz 8bitoverflow= 0.125Hz |
#define TIMER_CLK_STOP 0x00 ///< Timer Stopped |
#define TIMER_CLK_DIV1 0x01 ///< Timer clocked at F_CPU |
#define TIMER_CLK_DIV8 0x02 ///< Timer clocked at F_CPU/8 |
#define TIMER_CLK_DIV64 0x03 ///< Timer clocked at F_CPU/64 |
#define TIMER_CLK_DIV256 0x04 ///< Timer clocked at F_CPU/256 |
#define TIMER_CLK_DIV1024 0x05 ///< Timer clocked at F_CPU/1024 |
#define TIMER_CLK_T_FALL 0x06 ///< Timer clocked at T falling edge |
#define TIMER_CLK_T_RISE 0x07 ///< Timer clocked at T rising edge |
#define TIMER_PRESCALE_MASK 0x07 ///< Timer Prescaler Bit-Mask |
#define TIMERRTC_CLK_STOP 0x00 ///< RTC Timer Stopped |
#define TIMERRTC_CLK_DIV1 0x01 ///< RTC Timer clocked at F_CPU |
#define TIMERRTC_CLK_DIV8 0x02 ///< RTC Timer clocked at F_CPU/8 |
#define TIMERRTC_CLK_DIV32 0x03 ///< RTC Timer clocked at F_CPU/32 |
#define TIMERRTC_CLK_DIV64 0x04 ///< RTC Timer clocked at F_CPU/64 |
#define TIMERRTC_CLK_DIV128 0x05 ///< RTC Timer clocked at F_CPU/128 |
#define TIMERRTC_CLK_DIV256 0x06 ///< RTC Timer clocked at F_CPU/256 |
#define TIMERRTC_CLK_DIV1024 0x07 ///< RTC Timer clocked at F_CPU/1024 |
#define TIMERRTC_PRESCALE_MASK 0x07 ///< RTC Timer Prescaler Bit-Mask |
// default prescale settings for the timers |
// these settings are applied when you call |
// timerInit or any of the timer<x>Init |
#define TIMER0PRESCALE TIMER_CLK_DIV8 ///< timer 0 prescaler default |
#define TIMER1PRESCALE TIMER_CLK_DIV64 ///< timer 1 prescaler default |
#define TIMER2PRESCALE TIMERRTC_CLK_DIV64 ///< timer 2 prescaler default |
// interrupt macros for attaching user functions to timer interrupts |
// use these with timerAttach( intNum, function ) |
#define TIMER0OVERFLOW_INT 0 |
#define TIMER1OVERFLOW_INT 1 |
#define TIMER1OUTCOMPAREA_INT 2 |
#define TIMER1OUTCOMPAREB_INT 3 |
#define TIMER1INPUTCAPTURE_INT 4 |
#define TIMER2OVERFLOW_INT 5 |
#define TIMER2OUTCOMPARE_INT 6 |
#ifdef OCR0 // for processors that support output compare on Timer0 |
#define TIMER0OUTCOMPARE_INT 7 |
#define TIMER_NUM_INTERRUPTS 8 |
#else |
#define TIMER_NUM_INTERRUPTS 7 |
#endif |
// default type of interrupt handler to use for timers |
// *do not change unless you know what you're doing |
// Value may be SIGNAL or INTERRUPT |
#ifndef TIMER_INTERRUPT_HANDLER |
#define TIMER_INTERRUPT_HANDLER SIGNAL |
#endif |
// functions |
#define delay delay_us |
#define delay_ms timerPause |
void delay_us(unsigned short time_us); |
//! initializes timing system (all timers) |
// runs all timer init functions |
// sets all timers to default prescale values #defined in systimer.c |
void timerInit(void); |
// default initialization routines for each timer |
void timer0Init(void); ///< initialize timer0 |
void timer1Init(void); ///< initialize timer1 |
#ifdef TCNT2 // support timer2 only if it exists |
void timer2Init(void); ///< initialize timer2 |
#endif |
// Clock prescaler set/get commands for each timer/counter |
// For setting the prescaler, you should use one of the #defines |
// above like TIMER_CLK_DIVx, where [x] is the division rate |
// you want. |
// When getting the current prescaler setting, the return value |
// will be the [x] division value currently set. |
void timer0SetPrescaler(u08 prescale); ///< set timer0 prescaler |
u16 timer0GetPrescaler(void); ///< get timer0 prescaler |
void timer1SetPrescaler(u08 prescale); ///< set timer1 prescaler |
u16 timer1GetPrescaler(void); ///< get timer0 prescaler |
#ifdef TCNT2 // support timer2 only if it exists |
void timer2SetPrescaler(u08 prescale); ///< set timer2 prescaler |
u16 timer2GetPrescaler(void); ///< get timer2 prescaler |
#endif |
// TimerAttach and Detach commands |
// These functions allow the attachment (or detachment) of any user function |
// to a timer interrupt. "Attaching" one of your own functions to a timer |
// interrupt means that it will be called whenever that interrupt happens. |
// Using attach is better than rewriting the actual INTERRUPT() function |
// because your code will still work and be compatible if the timer library |
// is updated. Also, using Attach allows your code and any predefined timer |
// code to work together and at the same time. (ie. "attaching" your own |
// function to the timer0 overflow doesn't prevent timerPause from working, |
// but rather allows you to share the interrupt.) |
// |
// timerAttach(TIMER1OVERFLOW_INT, myOverflowFunction); |
// timerDetach(TIMER1OVERFLOW_INT) |
// |
// timerAttach causes the myOverflowFunction() to be attached, and therefore |
// execute, whenever an overflow on timer1 occurs. timerDetach removes the |
// association and executes no user function when the interrupt occurs. |
// myOverflowFunction must be defined with no return value and no arguments: |
// |
// void myOverflowFunction(void) { ... } |
//! Attach a user function to a timer interrupt |
void timerAttach(u08 interruptNum, void (*userFunc)(void) ); |
//! Detach a user function from a timer interrupt |
void timerDetach(u08 interruptNum); |
// timing commands |
/// A timer-based delay/pause function |
/// @param pause_ms Number of integer milliseconds to wait. |
void timerPause(unsigned short pause_ms); |
// overflow counters |
void timer0ClearOverflowCount(void); ///< Clear timer0's overflow counter. |
long timer0GetOverflowCount(void); ///< read timer0's overflow counter |
#ifdef TCNT2 // support timer2 only if it exists |
void timer2ClearOverflowCount(void); ///< clear timer2's overflow counter |
long timer2GetOverflowCount(void); ///< read timer0's overflow counter |
#endif |
/// @defgroup timerpwm Timer PWM Commands |
/// @ingroup timer |
/// These commands control PWM functionality on timer1 |
// PWM initialization and set commands for timer1 |
// timer1PWMInit() |
// configures the timer1 hardware for PWM mode on pins OC1A and OC1B. |
// bitRes should be 8,9,or 10 for 8,9,or 10bit PWM resolution |
// |
// timer1PWMOff() |
// turns off all timer1 PWM output and set timer mode to normal state |
// |
// timer1PWMAOn() and timer1PWMBOn() |
// turn on output of PWM signals to OC1A or OC1B pins |
// NOTE: Until you define the OC1A and OC1B pins as outputs, and run |
// this "on" command, no PWM output will be output |
// |
// timer1PWMAOff() and timer1PWMBOff() |
// turn off output of PWM signals to OC1A or OC1B pins |
// |
// timer1PWMASet() and timer1PWMBSet() |
// sets the PWM duty cycle for each channel |
// NOTE: <pwmDuty> should be in the range 0-255 for 8bit PWM |
// <pwmDuty> should be in the range 0-511 for 9bit PWM |
// <pwmDuty> should be in the range 0-1023 for 10bit PWM |
// NOTE: the PWM frequency can be controlled in increments by setting the |
// prescaler for timer1 |
//@{ |
/// Enter standard PWM Mode on timer1. |
/// \param bitRes indicates the period/resolution to use for PWM output in timer bits. |
/// Must be either 8, 9, or 10 bits corresponding to PWM periods of 256, 512, or 1024 timer tics. |
void timer1PWMInit(u08 bitRes); |
/// Enter PWM Mode on timer1 with a specific top-count value. |
/// \param topcount indicates the desired PWM period in timer tics. |
/// Can be a number between 1 and 65535 (16-bit). |
void timer1PWMInitICR(u16 topcount); |
/// Turn off all timer1 PWM output and set timer mode to normal. |
void timer1PWMOff(void); |
/// Turn on/off Timer1 PWM outputs. |
void timer1PWMAOn(void); ///< Turn on timer1 Channel A (OC1A) PWM output. |
void timer1PWMBOn(void); ///< Turn on timer1 Channel B (OC1B) PWM output. |
void timer1PWMAOff(void); ///< turn off timer1 Channel A (OC1A) PWM output |
void timer1PWMBOff(void); ///< turn off timer1 Channel B (OC1B) PWM output |
void timer1PWMASet(u16 pwmDuty); ///< set duty of timer1 Channel A (OC1A) PWM output |
void timer1PWMBSet(u16 pwmDuty); ///< set duty of timer1 Channel B (OC1B) PWM output |
//@} |
//@} |
// Pulse generation commands have been moved to the pulse.c library |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/uart.c |
---|
0,0 → 1,283 |
/*! \file uart.c \brief UART driver with buffer support. */ |
// ***************************************************************************** |
// |
// File Name : 'uart.c' |
// Title : UART driver with buffer support |
// Author : Pascal Stang - Copyright (C) 2000-2002 |
// Created : 11/22/2000 |
// Revised : 06/09/2003 |
// Version : 1.3 |
// Target MCU : ATMEL AVR Series |
// Editor Tabs : 4 |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
// ***************************************************************************** |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include "buffer.h" |
#include "uart.h" |
// UART global variables |
// flag variables |
volatile u08 uartReadyTx; ///< uartReadyTx flag |
volatile u08 uartBufferedTx; ///< uartBufferedTx flag |
// receive and transmit buffers |
cBuffer uartRxBuffer; ///< uart receive buffer |
cBuffer uartTxBuffer; ///< uart transmit buffer |
unsigned short uartRxOverflow; ///< receive overflow counter |
#ifndef UART_BUFFERS_EXTERNAL_RAM |
// using internal ram, |
// automatically allocate space in ram for each buffer |
static char uartRxData[UART_RX_BUFFER_SIZE]; |
static char uartTxData[UART_TX_BUFFER_SIZE]; |
#endif |
typedef void (*voidFuncPtru08)(unsigned char); |
volatile static voidFuncPtru08 UartRxFunc; |
// enable and initialize the uart |
void uartInit(void) |
{ |
// initialize the buffers |
uartInitBuffers(); |
// initialize user receive handler |
UartRxFunc = 0; |
// enable RxD/TxD and interrupts |
outb(UCR, BV(RXCIE)|BV(TXCIE)|BV(RXEN)|BV(TXEN)); |
// set default baud rate |
uartSetBaudRate(UART_DEFAULT_BAUD_RATE); |
// initialize states |
uartReadyTx = TRUE; |
uartBufferedTx = FALSE; |
// clear overflow count |
uartRxOverflow = 0; |
// enable interrupts |
sei(); |
} |
// create and initialize the uart transmit and receive buffers |
void uartInitBuffers(void) |
{ |
#ifndef UART_BUFFERS_EXTERNAL_RAM |
// initialize the UART receive buffer |
bufferInit(&uartRxBuffer, uartRxData, UART_RX_BUFFER_SIZE); |
// initialize the UART transmit buffer |
bufferInit(&uartTxBuffer, uartTxData, UART_TX_BUFFER_SIZE); |
#else |
// initialize the UART receive buffer |
bufferInit(&uartRxBuffer, (u08*) UART_RX_BUFFER_ADDR, UART_RX_BUFFER_SIZE); |
// initialize the UART transmit buffer |
bufferInit(&uartTxBuffer, (u08*) UART_TX_BUFFER_ADDR, UART_TX_BUFFER_SIZE); |
#endif |
} |
// redirects received data to a user function |
void uartSetRxHandler(void (*rx_func)(unsigned char c)) |
{ |
// set the receive interrupt to run the supplied user function |
UartRxFunc = rx_func; |
} |
// set the uart baud rate |
void uartSetBaudRate(u32 baudrate) |
{ |
// calculate division factor for requested baud rate, and set it |
u16 bauddiv = ((F_CPU+(baudrate*8L))/(baudrate*16L)-1); |
outb(UBRRL, bauddiv); |
#ifdef UBRRH |
outb(UBRRH, bauddiv>>8); |
#endif |
} |
// returns the receive buffer structure |
cBuffer* uartGetRxBuffer(void) |
{ |
// return rx buffer pointer |
return &uartRxBuffer; |
} |
// returns the transmit buffer structure |
cBuffer* uartGetTxBuffer(void) |
{ |
// return tx buffer pointer |
return &uartTxBuffer; |
} |
// transmits a byte over the uart |
void uartSendByte(u08 txData) |
{ |
// wait for the transmitter to be ready |
while(!uartReadyTx); |
// send byte |
outb(UDR, txData); |
// set ready state to FALSE |
uartReadyTx = FALSE; |
} |
// gets a single byte from the uart receive buffer (getchar-style) |
int uartGetByte(void) |
{ |
u08 c; |
if(uartReceiveByte(&c)) |
return c; |
else |
return -1; |
} |
// gets a byte (if available) from the uart receive buffer |
u08 uartReceiveByte(u08* rxData) |
{ |
// make sure we have a receive buffer |
if(uartRxBuffer.size) |
{ |
// make sure we have data |
if(uartRxBuffer.datalength) |
{ |
// get byte from beginning of buffer |
*rxData = bufferGetFromFront(&uartRxBuffer); |
return TRUE; |
} |
else |
{ |
// no data |
return FALSE; |
} |
} |
else |
{ |
// no buffer |
return FALSE; |
} |
} |
// flush all data out of the receive buffer |
void uartFlushReceiveBuffer(void) |
{ |
// flush all data from receive buffer |
//bufferFlush(&uartRxBuffer); |
// same effect as above |
uartRxBuffer.datalength = 0; |
} |
// return true if uart receive buffer is empty |
u08 uartReceiveBufferIsEmpty(void) |
{ |
if(uartRxBuffer.datalength == 0) |
{ |
return TRUE; |
} |
else |
{ |
return FALSE; |
} |
} |
// add byte to end of uart Tx buffer |
u08 uartAddToTxBuffer(u08 data) |
{ |
// add data byte to the end of the tx buffer |
return bufferAddToEnd(&uartTxBuffer, data); |
} |
// start transmission of the current uart Tx buffer contents |
void uartSendTxBuffer(void) |
{ |
// turn on buffered transmit |
uartBufferedTx = TRUE; |
// send the first byte to get things going by interrupts |
uartSendByte(bufferGetFromFront(&uartTxBuffer)); |
} |
/* |
// transmit nBytes from buffer out the uart |
u08 uartSendBuffer(char *buffer, u16 nBytes) |
{ |
register u08 first; |
register u16 i; |
// check if there's space (and that we have any bytes to send at all) |
if((uartTxBuffer.datalength + nBytes < uartTxBuffer.size) && nBytes) |
{ |
// grab first character |
first = *buffer++; |
// copy user buffer to uart transmit buffer |
for(i = 0; i < nBytes-1; i++) |
{ |
// put data bytes at end of buffer |
bufferAddToEnd(&uartTxBuffer, *buffer++); |
} |
// send the first byte to get things going by interrupts |
uartBufferedTx = TRUE; |
uartSendByte(first); |
// return success |
return TRUE; |
} |
else |
{ |
// return failure |
return FALSE; |
} |
} |
*/ |
// UART Transmit Complete Interrupt Handler |
UART_INTERRUPT_HANDLER(SIG_UART_TRANS) |
{ |
// check if buffered tx is enabled |
if(uartBufferedTx) |
{ |
// check if there's data left in the buffer |
if(uartTxBuffer.datalength) |
{ |
// send byte from top of buffer |
outb(UDR, bufferGetFromFront(&uartTxBuffer)); |
} |
else |
{ |
// no data left |
uartBufferedTx = FALSE; |
// return to ready state |
uartReadyTx = TRUE; |
} |
} |
else |
{ |
// we're using single-byte tx mode |
// indicate transmit complete, back to ready |
uartReadyTx = TRUE; |
} |
} |
// UART Receive Complete Interrupt Handler |
UART_INTERRUPT_HANDLER(SIG_UART_RECV) |
{ |
u08 c; |
// get received char |
c = inb(UDR); |
// if there's a user function to handle this receive event |
if(UartRxFunc) |
{ |
// call it and pass the received data |
UartRxFunc(c); |
} |
else |
{ |
// otherwise do default processing |
// put received char in buffer |
// check if there's space |
if( !bufferAddToEnd(&uartRxBuffer, c) ) |
{ |
// no space in buffer |
// count overflow |
uartRxOverflow++; |
} |
} |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/uart.h |
---|
0,0 → 1,232 |
/*! \file uart.h \brief UART driver with buffer support. */ |
//***************************************************************************** |
// |
// File Name : 'uart.h' |
// Title : UART driver with buffer support |
// Author : Pascal Stang - Copyright (C) 2000-2002 |
// Created : 11/22/2000 |
// Revised : 02/01/2004 |
// Version : 1.3 |
// Target MCU : ATMEL AVR Series |
// Editor Tabs : 4 |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
/// \ingroup driver_avr |
/// \defgroup uart UART Driver/Function Library (uart.c) |
/// \code #include "uart.h" \endcode |
/// \par Overview |
/// This library provides both buffered and unbuffered transmit and receive |
/// functions for the AVR processor UART. Buffered access means that the |
/// UART can transmit and receive data in the "background", while your code |
/// continues executing. Also included are functions to initialize the |
/// UART, set the baud rate, flush the buffers, and check buffer status. |
/// |
/// \note For full text output functionality, you may wish to use the rprintf |
/// functions along with this driver. |
/// |
/// \par About UART operations |
/// Most Atmel AVR-series processors contain one or more hardware UARTs |
/// (aka, serial ports). UART serial ports can communicate with other |
/// serial ports of the same type, like those used on PCs. In general, |
/// UARTs are used to communicate with devices that are RS-232 compatible |
/// (RS-232 is a certain kind of serial port). |
/// \par |
/// By far, the most common use for serial communications on AVR processors |
/// is for sending information and data to a PC running a terminal program. |
/// Here is an exmaple: |
/// \code |
/// uartInit(); // initialize UART (serial port) |
/// uartSetBaudRate(9600); // set UART speed to 9600 baud |
/// rprintfInit(uartSendByte); // configure rprintf to use UART for output |
/// rprintf("Hello World\r\n"); // send "hello world" message via serial port |
/// \endcode |
/// |
/// \warning The CPU frequency (F_CPU) must be set correctly in \c global.h |
/// for the UART library to calculate correct baud rates. Furthermore, |
/// certain CPU frequencies will not produce exact baud rates due to |
/// integer frequency division round-off. See your AVR processor's |
/// datasheet for full details. |
// |
//***************************************************************************** |
//@{ |
#ifndef UART_H |
#define UART_H |
#include "global.h" |
#include "buffer.h" |
//! Default uart baud rate. |
/// This is the default speed after a uartInit() command, |
/// and can be changed by using uartSetBaudRate(). |
#define UART_DEFAULT_BAUD_RATE 9600 |
// buffer memory allocation defines |
// buffer sizes |
#ifndef UART_TX_BUFFER_SIZE |
//! Number of bytes for uart transmit buffer. |
/// Do not change this value in uart.h, but rather override |
/// it with the desired value defined in your project's global.h |
#define UART_TX_BUFFER_SIZE 0x0040 |
#endif |
#ifndef UART_RX_BUFFER_SIZE |
//! Number of bytes for uart receive buffer. |
/// Do not change this value in uart.h, but rather override |
/// it with the desired value defined in your project's global.h |
#define UART_RX_BUFFER_SIZE 0x0040 |
#endif |
// define this key if you wish to use |
// external RAM for the UART buffers |
//#define UART_BUFFER_EXTERNAL_RAM |
#ifdef UART_BUFFER_EXTERNAL_RAM |
// absolute address of uart buffers |
#define UART_TX_BUFFER_ADDR 0x1000 |
#define UART_RX_BUFFER_ADDR 0x1100 |
#endif |
//! Type of interrupt handler to use for uart interrupts. |
/// Value may be SIGNAL or INTERRUPT. |
/// \warning Do not change unless you know what you're doing. |
#ifndef UART_INTERRUPT_HANDLER |
#define UART_INTERRUPT_HANDLER SIGNAL |
#endif |
// compatibility with most newer processors |
#ifdef UCSRB |
#define UCR UCSRB |
#endif |
// compatibility with old Mega processors |
#if defined(UBRR) && !defined(UBRRL) |
#define UBRRL UBRR |
#endif |
// compatibility with megaXX8 processors |
#if defined(__AVR_ATmega88__) || \ |
defined(__AVR_ATmega168__) || \ |
defined(__AVR_ATmega644__) |
#define UDR UDR0 |
#define UCR UCSR0B |
#define RXCIE RXCIE0 |
#define TXCIE TXCIE0 |
#define RXC RXC0 |
#define TXC TXC0 |
#define RXEN RXEN0 |
#define TXEN TXEN0 |
#define UBRRL UBRR0L |
#define UBRRH UBRR0H |
#define SIG_UART_TRANS SIG_USART_TRANS |
#define SIG_UART_RECV SIG_USART_RECV |
#define SIG_UART_DATA SIG_USART_DATA |
#endif |
// compatibility with mega169 processors |
#if defined(__AVR_ATmega169__) |
#define SIG_UART_TRANS SIG_USART_TRANS |
#define SIG_UART_RECV SIG_USART_RECV |
#define SIG_UART_DATA SIG_USART_DATA |
#endif |
// compatibility with dual-uart processors |
// (if you need to use both uarts, please use the uart2 library) |
#if defined(__AVR_ATmega161__) |
#define UDR UDR0 |
#define UCR UCSR0B |
#define UBRRL UBRR0 |
#define SIG_UART_TRANS SIG_UART0_TRANS |
#define SIG_UART_RECV SIG_UART0_RECV |
#define SIG_UART_DATA SIG_UART0_DATA |
#endif |
#if defined(__AVR_ATmega128__) |
#ifdef UART_USE_UART1 |
#define UDR UDR1 |
#define UCR UCSR1B |
#define UBRRL UBRR1L |
#define UBRRH UBRR1H |
#define SIG_UART_TRANS SIG_UART1_TRANS |
#define SIG_UART_RECV SIG_UART1_RECV |
#define SIG_UART_DATA SIG_UART1_DATA |
#else |
#define UDR UDR0 |
#define UCR UCSR0B |
#define UBRRL UBRR0L |
#define UBRRH UBRR0H |
#define SIG_UART_TRANS SIG_UART0_TRANS |
#define SIG_UART_RECV SIG_UART0_RECV |
#define SIG_UART_DATA SIG_UART0_DATA |
#endif |
#endif |
// functions |
//! Initializes uart. |
/// \note After running this init function, the processor |
/// I/O pins that used for uart communications (RXD, TXD) |
/// are no long available for general purpose I/O. |
void uartInit(void); |
//! Initializes transmit and receive buffers. |
/// Automatically called from uartInit() |
void uartInitBuffers(void); |
//! Redirects received data to a user function. |
/// |
void uartSetRxHandler(void (*rx_func)(unsigned char c)); |
//! Sets the uart baud rate. |
/// Argument should be in bits-per-second, like \c uartSetBaudRate(9600); |
void uartSetBaudRate(u32 baudrate); |
//! Returns pointer to the receive buffer structure. |
/// |
cBuffer* uartGetRxBuffer(void); |
//! Returns pointer to the transmit buffer structure. |
/// |
cBuffer* uartGetTxBuffer(void); |
//! Sends a single byte over the uart. |
/// \note This function waits for the uart to be ready, |
/// therefore, consecutive calls to uartSendByte() will |
/// go only as fast as the data can be sent over the |
/// serial port. |
void uartSendByte(u08 data); |
//! Gets a single byte from the uart receive buffer. |
/// Returns the byte, or -1 if no byte is available (getchar-style). |
int uartGetByte(void); |
//! Gets a single byte from the uart receive buffer. |
/// Function returns TRUE if data was available, FALSE if not. |
/// Actual data is returned in variable pointed to by "data". |
/// Example usage: |
/// \code |
/// char myReceivedByte; |
/// uartReceiveByte( &myReceivedByte ); |
/// \endcode |
u08 uartReceiveByte(u08* data); |
//! Returns TRUE/FALSE if receive buffer is empty/not-empty. |
/// |
u08 uartReceiveBufferIsEmpty(void); |
//! Flushes (deletes) all data from receive buffer. |
/// |
void uartFlushReceiveBuffer(void); |
//! Add byte to end of uart Tx buffer. |
/// Returns TRUE if successful, FALSE if failed (no room left in buffer). |
u08 uartAddToTxBuffer(u08 data); |
//! Begins transmission of the transmit buffer under interrupt control. |
/// |
void uartSendTxBuffer(void); |
//! Sends a block of data via the uart using interrupt control. |
/// \param buffer pointer to data to be sent |
/// \param nBytes length of data (number of bytes to sent) |
u08 uartSendBuffer(char *buffer, u16 nBytes); |
#endif |
//@} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/vt100.c |
---|
0,0 → 1,69 |
/*! \file vt100.c \brief VT100 terminal function library. */ |
//***************************************************************************** |
// |
// File Name : 'vt100.c' |
// Title : VT100 terminal function library |
// Author : Pascal Stang - Copyright (C) 2002 |
// Created : 2002.08.27 |
// Revised : 2002.08.27 |
// Version : 0.1 |
// Target MCU : Atmel AVR Series |
// Editor Tabs : 4 |
// |
// NOTE: This code is currently below version 1.0, and therefore is considered |
// to be lacking in some functionality or documentation, or may not be fully |
// tested. Nonetheless, you can expect most functions to work. |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
//***************************************************************************** |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include <avr/pgmspace.h> |
#include "global.h" |
#include "rprintf.h" |
#include "vt100.h" |
// Program ROM constants |
// Global variables |
// Functions |
void vt100Init(void) |
{ |
// initializes terminal to "power-on" settings |
// ESC c |
rprintfProgStrM("\x1B\x63"); |
} |
void vt100ClearScreen(void) |
{ |
// ESC [ 2 J |
rprintfProgStrM("\x1B[2J"); |
} |
void vt100SetAttr(u08 attr) |
{ |
// ESC [ Ps m |
rprintf("\x1B[%dm",attr); |
} |
void vt100SetCursorMode(u08 visible) |
{ |
if(visible) |
// ESC [ ? 25 h |
rprintf("\x1B[?25h"); |
else |
// ESC [ ? 25 l |
rprintf("\x1B[?25l"); |
} |
void vt100SetCursorPos(u08 line, u08 col) |
{ |
// ESC [ Pl ; Pc H |
rprintf("\x1B[%d;%dH",line,col); |
} |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/buffer/vt100.h |
---|
0,0 → 1,72 |
/*! \file vt100.h \brief VT100 terminal function library. */ |
//***************************************************************************** |
// |
// File Name : 'vt100.h' |
// Title : VT100 terminal function library |
// Author : Pascal Stang - Copyright (C) 2002 |
// Created : 2002.08.27 |
// Revised : 2002.08.27 |
// Version : 0.1 |
// Target MCU : Atmel AVR Series |
// Editor Tabs : 4 |
// |
// NOTE: This code is currently below version 1.0, and therefore is considered |
// to be lacking in some functionality or documentation, or may not be fully |
// tested. Nonetheless, you can expect most functions to work. |
// |
/// \ingroup general |
/// \defgroup vt100 VT100 Terminal Function Library (vt100.c) |
/// \code #include "vt100.h" \endcode |
/// \par Overview |
/// This library provides functions for sending VT100 escape codes to |
/// control a connected VT100 or ANSI terminal. Commonly useful functions |
/// include setting the cursor position, clearing the screen, setting the text |
/// attributes (bold, inverse, blink, etc), and setting the text color. This |
/// library will slowly be expanded to include support for codes as needed and |
/// may eventually receive VT100 escape codes too. |
// |
// This code is distributed under the GNU Public License |
// which can be found at http://www.gnu.org/licenses/gpl.txt |
// |
//***************************************************************************** |
#ifndef VT100_H |
#define VT100_H |
#include "global.h" |
// constants/macros/typdefs |
// text attributes |
#define VT100_ATTR_OFF 0 |
#define VT100_BOLD 1 |
#define VT100_USCORE 4 |
#define VT100_BLINK 5 |
#define VT100_REVERSE 7 |
#define VT100_BOLD_OFF 21 |
#define VT100_USCORE_OFF 24 |
#define VT100_BLINK_OFF 25 |
#define VT100_REVERSE_OFF 27 |
// functions |
//! vt100Init() initializes terminal and vt100 library |
/// Run this init routine once before using any other vt100 function. |
void vt100Init(void); |
//! vt100ClearScreen() clears the terminal screen |
void vt100ClearScreen(void); |
//! vt100SetAttr() sets the text attributes like BOLD or REVERSE |
/// Text written to the terminal after this function is called will have |
/// the desired attribuutes. |
void vt100SetAttr(u08 attr); |
//! vt100SetCursorMode() sets the cursor to visible or invisible |
void vt100SetCursorMode(u08 visible); |
//! vt100SetCursorPos() sets the cursor position |
/// All text which is written to the terminal after a SetCursorPos command |
/// will begin at the new location of the cursor. |
void vt100SetCursorPos(u08 line, u08 col); |
#endif |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/logger/ChangeLog |
---|
0,0 → 1,68 |
2007-12-13 sd-reader |
* dual-license the major implementation modules under GPL and LGPL |
2007-06-03 sd-reader |
* Fix reading beyond cached block (by Benjamin Meier). |
* Implement support for reading and writing file modification dates/times. |
(Thanks to Torsten Seeboth for testing.) |
2007-03-01 sd-reader |
* Avoid LFN directory entries for the "." and ".." directory references. |
This prevented Windows from deleting directories. |
* Handle special case where the 8.3 filename begins with 0xe5. |
* Fix return value of fat16_delete_file() when deleting empty files. |
* Fix fat16_clear_cluster() which was zeroing only 16 of every 32 bytes. |
2007-01-20 sd-reader |
* fix directory creation |
- correctly create "." and ".." directory entries (8.3 <-> lfn versions) |
- correctly clear cluster containing the directory entries for new directory |
2006-11-01 sd-reader |
* Implement creation and deletion of directories. |
* Clear the directory entries of new directory clusters. |
* Prevent linkage against printf(). |
* Make the use of malloc()/free() optional. |
2006-09-01 sd-reader |
* Fix shortening files. |
* Fix free disk space calculation. |
2006-08-24 sd-reader |
* Improve sleep handling. |
* Display extended card information on boot and |
when executing the "disk" shell command. |
* Correctly determine FAT type by cluster count. |
* Fix cluster allocation beyond card capacity. |
2006-08-16 sd-reader |
* Provide FAT16 capacity and usage information. |
* Implement the backspace key in the mini shell. |
* Enter idle mode when waiting for uart activity. |
* Make the Card Select pin MCU dependent as well. |
* Add mini shell commands to documentation. |
2006-08-08 sd-reader |
* Thanks go to Torsten Seeboth for his ongoing efforts |
to test changes, fix regressions and give suggestions. |
Many of the changes below were initiated by him. |
* Much more reliable card initialization. |
* Highly improved performance |
- optional write buffering |
- better cluster handling |
- remove unneeded SPI access when reading from buffered block |
- use highest spi frequency after card initialization |
* Add superfloppy support. |
* Better checks when opening a FAT16 filesystem. |
* Provide SPI pin mappings for commonly used ATmegas. |
* Fix resizing files, hangs could occur. |
* Fix overflow when creating files with names longer than 31 characters. |
* Fix numerous other small things. |
2006-03-19 sd-reader |
* Fix speed regressions. |
2006-03-16 sd-reader |
* Initial release. |
/Designs/Data_loggers/GPSRL02A/SW/logger/Doxyfile |
---|
0,0 → 1,1311 |
# Doxyfile 1.5.3-20071008 |
# This file describes the settings to be used by the documentation system |
# doxygen (www.doxygen.org) for a project |
# |
# All text after a hash (#) is considered a comment and will be ignored |
# The format is: |
# TAG = value [value, ...] |
# For lists items can also be appended using: |
# TAG += value [value, ...] |
# Values that contain spaces should be placed between quotes (" ") |
#--------------------------------------------------------------------------- |
# Project related configuration options |
#--------------------------------------------------------------------------- |
# This tag specifies the encoding used for all characters in the config file that |
# follow. The default is UTF-8 which is also the encoding used for all text before |
# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into |
# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of |
# possible encodings. |
DOXYFILE_ENCODING = UTF-8 |
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded |
# by quotes) that should identify the project. |
PROJECT_NAME = sd-reader |
# The PROJECT_NUMBER tag can be used to enter a project or revision number. |
# This could be handy for archiving the generated documentation or |
# if some version control system is used. |
PROJECT_NUMBER = |
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) |
# base path where the generated documentation will be put. |
# If a relative path is entered, it will be relative to the location |
# where doxygen was started. If left blank the current directory will be used. |
OUTPUT_DIRECTORY = doc |
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create |
# 4096 sub-directories (in 2 levels) under the output directory of each output |
# format and will distribute the generated files over these directories. |
# Enabling this option can be useful when feeding doxygen a huge amount of |
# source files, where putting all generated files in the same directory would |
# otherwise cause performance problems for the file system. |
CREATE_SUBDIRS = NO |
# The OUTPUT_LANGUAGE tag is used to specify the language in which all |
# documentation generated by doxygen is written. Doxygen will use this |
# information to generate all constant output in the proper language. |
# The default language is English, other supported languages are: |
# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, |
# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, |
# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, |
# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, |
# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. |
OUTPUT_LANGUAGE = English |
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will |
# include brief member descriptions after the members that are listed in |
# the file and class documentation (similar to JavaDoc). |
# Set to NO to disable this. |
BRIEF_MEMBER_DESC = YES |
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend |
# the brief description of a member or function before the detailed description. |
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the |
# brief descriptions will be completely suppressed. |
REPEAT_BRIEF = YES |
# This tag implements a quasi-intelligent brief description abbreviator |
# that is used to form the text in various listings. Each string |
# in this list, if found as the leading text of the brief description, will be |
# stripped from the text and the result after processing the whole list, is |
# used as the annotated text. Otherwise, the brief description is used as-is. |
# If left blank, the following values are used ("$name" is automatically |
# replaced with the name of the entity): "The $name class" "The $name widget" |
# "The $name file" "is" "provides" "specifies" "contains" |
# "represents" "a" "an" "the" |
ABBREVIATE_BRIEF = "The $name class " \ |
"The $name widget " \ |
"The $name file " \ |
is \ |
provides \ |
specifies \ |
contains \ |
represents \ |
a \ |
an \ |
the |
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then |
# Doxygen will generate a detailed section even if there is only a brief |
# description. |
ALWAYS_DETAILED_SEC = NO |
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all |
# inherited members of a class in the documentation of that class as if those |
# members were ordinary class members. Constructors, destructors and assignment |
# operators of the base classes will not be shown. |
INLINE_INHERITED_MEMB = NO |
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full |
# path before files name in the file list and in the header files. If set |
# to NO the shortest path that makes the file name unique will be used. |
FULL_PATH_NAMES = NO |
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag |
# can be used to strip a user-defined part of the path. Stripping is |
# only done if one of the specified strings matches the left-hand part of |
# the path. The tag can be used to show relative paths in the file list. |
# If left blank the directory from which doxygen is run is used as the |
# path to strip. |
STRIP_FROM_PATH = |
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of |
# the path mentioned in the documentation of a class, which tells |
# the reader which header file to include in order to use a class. |
# If left blank only the name of the header file containing the class |
# definition is used. Otherwise one should specify the include paths that |
# are normally passed to the compiler using the -I flag. |
STRIP_FROM_INC_PATH = |
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter |
# (but less readable) file names. This can be useful is your file systems |
# doesn't support long names like on DOS, Mac, or CD-ROM. |
SHORT_NAMES = NO |
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen |
# will interpret the first line (until the first dot) of a JavaDoc-style |
# comment as the brief description. If set to NO, the JavaDoc |
# comments will behave just like regular Qt-style comments |
# (thus requiring an explicit @brief command for a brief description.) |
JAVADOC_AUTOBRIEF = YES |
# If the QT_AUTOBRIEF tag is set to YES then Doxygen will |
# interpret the first line (until the first dot) of a Qt-style |
# comment as the brief description. If set to NO, the comments |
# will behave just like regular Qt-style comments (thus requiring |
# an explicit \brief command for a brief description.) |
QT_AUTOBRIEF = NO |
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen |
# treat a multi-line C++ special comment block (i.e. a block of //! or /// |
# comments) as a brief description. This used to be the default behaviour. |
# The new default is to treat a multi-line C++ comment block as a detailed |
# description. Set this tag to YES if you prefer the old behaviour instead. |
MULTILINE_CPP_IS_BRIEF = NO |
# If the DETAILS_AT_TOP tag is set to YES then Doxygen |
# will output the detailed description near the top, like JavaDoc. |
# If set to NO, the detailed description appears after the member |
# documentation. |
DETAILS_AT_TOP = YES |
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented |
# member inherits the documentation from any documented member that it |
# re-implements. |
INHERIT_DOCS = YES |
# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce |
# a new page for each member. If set to NO, the documentation of a member will |
# be part of the file/class/namespace that contains it. |
SEPARATE_MEMBER_PAGES = NO |
# The TAB_SIZE tag can be used to set the number of spaces in a tab. |
# Doxygen uses this value to replace tabs by spaces in code fragments. |
TAB_SIZE = 4 |
# This tag can be used to specify a number of aliases that acts |
# as commands in the documentation. An alias has the form "name=value". |
# For example adding "sideeffect=\par Side Effects:\n" will allow you to |
# put the command \sideeffect (or @sideeffect) in the documentation, which |
# will result in a user-defined paragraph with heading "Side Effects:". |
# You can put \n's in the value part of an alias to insert newlines. |
ALIASES = |
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C |
# sources only. Doxygen will then generate output that is more tailored for C. |
# For instance, some of the names that are used will be different. The list |
# of all members will be omitted, etc. |
OPTIMIZE_OUTPUT_FOR_C = YES |
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java |
# sources only. Doxygen will then generate output that is more tailored for Java. |
# For instance, namespaces will be presented as packages, qualified scopes |
# will look different, etc. |
OPTIMIZE_OUTPUT_JAVA = NO |
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to |
# include (a tag file for) the STL sources as input, then you should |
# set this tag to YES in order to let doxygen match functions declarations and |
# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. |
# func(std::string) {}). This also make the inheritance and collaboration |
# diagrams that involve STL classes more complete and accurate. |
BUILTIN_STL_SUPPORT = NO |
# If you use Microsoft's C++/CLI language, you should set this option to YES to |
# enable parsing support. |
CPP_CLI_SUPPORT = NO |
# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. |
# Doxygen will parse them like normal C++ but will assume all classes use public |
# instead of private inheritance when no explicit protection keyword is present. |
SIP_SUPPORT = NO |
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC |
# tag is set to YES, then doxygen will reuse the documentation of the first |
# member in the group (if any) for the other members of the group. By default |
# all members of a group must be documented explicitly. |
DISTRIBUTE_GROUP_DOC = NO |
# Set the SUBGROUPING tag to YES (the default) to allow class member groups of |
# the same type (for instance a group of public functions) to be put as a |
# subgroup of that type (e.g. under the Public Functions section). Set it to |
# NO to prevent subgrouping. Alternatively, this can be done per class using |
# the \nosubgrouping command. |
SUBGROUPING = YES |
#--------------------------------------------------------------------------- |
# Build related configuration options |
#--------------------------------------------------------------------------- |
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in |
# documentation are documented, even if no documentation was available. |
# Private class members and static file members will be hidden unless |
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES |
EXTRACT_ALL = NO |
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class |
# will be included in the documentation. |
EXTRACT_PRIVATE = NO |
# If the EXTRACT_STATIC tag is set to YES all static members of a file |
# will be included in the documentation. |
EXTRACT_STATIC = NO |
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) |
# defined locally in source files will be included in the documentation. |
# If set to NO only classes defined in header files are included. |
EXTRACT_LOCAL_CLASSES = YES |
# This flag is only useful for Objective-C code. When set to YES local |
# methods, which are defined in the implementation section but not in |
# the interface are included in the documentation. |
# If set to NO (the default) only methods in the interface are included. |
EXTRACT_LOCAL_METHODS = NO |
# If this flag is set to YES, the members of anonymous namespaces will be extracted |
# and appear in the documentation as a namespace called 'anonymous_namespace{file}', |
# where file will be replaced with the base name of the file that contains the anonymous |
# namespace. By default anonymous namespace are hidden. |
EXTRACT_ANON_NSPACES = NO |
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all |
# undocumented members of documented classes, files or namespaces. |
# If set to NO (the default) these members will be included in the |
# various overviews, but no documentation section is generated. |
# This option has no effect if EXTRACT_ALL is enabled. |
HIDE_UNDOC_MEMBERS = YES |
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all |
# undocumented classes that are normally visible in the class hierarchy. |
# If set to NO (the default) these classes will be included in the various |
# overviews. This option has no effect if EXTRACT_ALL is enabled. |
HIDE_UNDOC_CLASSES = YES |
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all |
# friend (class|struct|union) declarations. |
# If set to NO (the default) these declarations will be included in the |
# documentation. |
HIDE_FRIEND_COMPOUNDS = NO |
# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any |
# documentation blocks found inside the body of a function. |
# If set to NO (the default) these blocks will be appended to the |
# function's detailed documentation block. |
HIDE_IN_BODY_DOCS = NO |
# The INTERNAL_DOCS tag determines if documentation |
# that is typed after a \internal command is included. If the tag is set |
# to NO (the default) then the documentation will be excluded. |
# Set it to YES to include the internal documentation. |
INTERNAL_DOCS = NO |
# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate |
# file names in lower-case letters. If set to YES upper-case letters are also |
# allowed. This is useful if you have classes or files whose names only differ |
# in case and if your file system supports case sensitive file names. Windows |
# and Mac users are advised to set this option to NO. |
CASE_SENSE_NAMES = YES |
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen |
# will show members with their full class and namespace scopes in the |
# documentation. If set to YES the scope will be hidden. |
HIDE_SCOPE_NAMES = NO |
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen |
# will put a list of the files that are included by a file in the documentation |
# of that file. |
SHOW_INCLUDE_FILES = NO |
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] |
# is inserted in the documentation for inline members. |
INLINE_INFO = YES |
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen |
# will sort the (detailed) documentation of file and class members |
# alphabetically by member name. If set to NO the members will appear in |
# declaration order. |
SORT_MEMBER_DOCS = YES |
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the |
# brief documentation of file, namespace and class members alphabetically |
# by member name. If set to NO (the default) the members will appear in |
# declaration order. |
SORT_BRIEF_DOCS = NO |
# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be |
# sorted by fully-qualified names, including namespaces. If set to |
# NO (the default), the class list will be sorted only by class name, |
# not including the namespace part. |
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. |
# Note: This option applies only to the class list, not to the |
# alphabetical list. |
SORT_BY_SCOPE_NAME = NO |
# The GENERATE_TODOLIST tag can be used to enable (YES) or |
# disable (NO) the todo list. This list is created by putting \todo |
# commands in the documentation. |
GENERATE_TODOLIST = YES |
# The GENERATE_TESTLIST tag can be used to enable (YES) or |
# disable (NO) the test list. This list is created by putting \test |
# commands in the documentation. |
GENERATE_TESTLIST = YES |
# The GENERATE_BUGLIST tag can be used to enable (YES) or |
# disable (NO) the bug list. This list is created by putting \bug |
# commands in the documentation. |
GENERATE_BUGLIST = YES |
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or |
# disable (NO) the deprecated list. This list is created by putting |
# \deprecated commands in the documentation. |
GENERATE_DEPRECATEDLIST= YES |
# The ENABLED_SECTIONS tag can be used to enable conditional |
# documentation sections, marked by \if sectionname ... \endif. |
ENABLED_SECTIONS = |
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines |
# the initial value of a variable or define consists of for it to appear in |
# the documentation. If the initializer consists of more lines than specified |
# here it will be hidden. Use a value of 0 to hide initializers completely. |
# The appearance of the initializer of individual variables and defines in the |
# documentation can be controlled using \showinitializer or \hideinitializer |
# command in the documentation regardless of this setting. |
MAX_INITIALIZER_LINES = 0 |
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated |
# at the bottom of the documentation of classes and structs. If set to YES the |
# list will mention the files that were used to generate the documentation. |
SHOW_USED_FILES = NO |
# If the sources in your project are distributed over multiple directories |
# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy |
# in the documentation. The default is NO. |
SHOW_DIRECTORIES = NO |
# The FILE_VERSION_FILTER tag can be used to specify a program or script that |
# doxygen should invoke to get the current version for each file (typically from the |
# version control system). Doxygen will invoke the program by executing (via |
# popen()) the command <command> <input-file>, where <command> is the value of |
# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file |
# provided by doxygen. Whatever the program writes to standard output |
# is used as the file version. See the manual for examples. |
FILE_VERSION_FILTER = |
#--------------------------------------------------------------------------- |
# configuration options related to warning and progress messages |
#--------------------------------------------------------------------------- |
# The QUIET tag can be used to turn on/off the messages that are generated |
# by doxygen. Possible values are YES and NO. If left blank NO is used. |
QUIET = NO |
# The WARNINGS tag can be used to turn on/off the warning messages that are |
# generated by doxygen. Possible values are YES and NO. If left blank |
# NO is used. |
WARNINGS = YES |
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings |
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will |
# automatically be disabled. |
WARN_IF_UNDOCUMENTED = NO |
# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for |
# potential errors in the documentation, such as not documenting some |
# parameters in a documented function, or documenting parameters that |
# don't exist or using markup commands wrongly. |
WARN_IF_DOC_ERROR = YES |
# This WARN_NO_PARAMDOC option can be abled to get warnings for |
# functions that are documented, but have no documentation for their parameters |
# or return value. If set to NO (the default) doxygen will only warn about |
# wrong or incomplete parameter documentation, but not about the absence of |
# documentation. |
WARN_NO_PARAMDOC = NO |
# The WARN_FORMAT tag determines the format of the warning messages that |
# doxygen can produce. The string should contain the $file, $line, and $text |
# tags, which will be replaced by the file and line number from which the |
# warning originated and the warning text. Optionally the format may contain |
# $version, which will be replaced by the version of the file (if it could |
# be obtained via FILE_VERSION_FILTER) |
WARN_FORMAT = "$file:$line: $text " |
# The WARN_LOGFILE tag can be used to specify a file to which warning |
# and error messages should be written. If left blank the output is written |
# to stderr. |
WARN_LOGFILE = |
#--------------------------------------------------------------------------- |
# configuration options related to the input files |
#--------------------------------------------------------------------------- |
# The INPUT tag can be used to specify the files and/or directories that contain |
# documented source files. You may enter file names like "myfile.cpp" or |
# directories like "/usr/src/myproject". Separate the files or directories |
# with spaces. |
INPUT = . |
# This tag can be used to specify the character encoding of the source files that |
# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default |
# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. |
# See http://www.gnu.org/software/libiconv for the list of possible encodings. |
INPUT_ENCODING = UTF-8 |
# If the value of the INPUT tag contains directories, you can use the |
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp |
# and *.h) to filter out the source-files in the directories. If left |
# blank the following patterns are tested: |
# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx |
# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py |
FILE_PATTERNS = *.c \ |
*.h |
# The RECURSIVE tag can be used to turn specify whether or not subdirectories |
# should be searched for input files as well. Possible values are YES and NO. |
# If left blank NO is used. |
RECURSIVE = NO |
# The EXCLUDE tag can be used to specify files and/or directories that should |
# excluded from the INPUT source files. This way you can easily exclude a |
# subdirectory from a directory tree whose root is specified with the INPUT tag. |
EXCLUDE = |
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or |
# directories that are symbolic links (a Unix filesystem feature) are excluded |
# from the input. |
EXCLUDE_SYMLINKS = NO |
# If the value of the INPUT tag contains directories, you can use the |
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude |
# certain files from those directories. Note that the wildcards are matched |
# against the file with absolute path, so to exclude all test directories |
# for example use the pattern */test/* |
EXCLUDE_PATTERNS = |
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names |
# (namespaces, classes, functions, etc.) that should be excluded from the output. |
# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, |
# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test |
EXCLUDE_SYMBOLS = |
# The EXAMPLE_PATH tag can be used to specify one or more files or |
# directories that contain example code fragments that are included (see |
# the \include command). |
EXAMPLE_PATH = |
# If the value of the EXAMPLE_PATH tag contains directories, you can use the |
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp |
# and *.h) to filter out the source-files in the directories. If left |
# blank all files are included. |
EXAMPLE_PATTERNS = * |
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be |
# searched for input files to be used with the \include or \dontinclude |
# commands irrespective of the value of the RECURSIVE tag. |
# Possible values are YES and NO. If left blank NO is used. |
EXAMPLE_RECURSIVE = NO |
# The IMAGE_PATH tag can be used to specify one or more files or |
# directories that contain image that are included in the documentation (see |
# the \image command). |
IMAGE_PATH = doc |
# The INPUT_FILTER tag can be used to specify a program that doxygen should |
# invoke to filter for each input file. Doxygen will invoke the filter program |
# by executing (via popen()) the command <filter> <input-file>, where <filter> |
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an |
# input file. Doxygen will then use the output that the filter program writes |
# to standard output. If FILTER_PATTERNS is specified, this tag will be |
# ignored. |
INPUT_FILTER = |
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern |
# basis. Doxygen will compare the file name with each pattern and apply the |
# filter if there is a match. The filters are a list of the form: |
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further |
# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER |
# is applied to all files. |
FILTER_PATTERNS = |
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using |
# INPUT_FILTER) will be used to filter the input files when producing source |
# files to browse (i.e. when SOURCE_BROWSER is set to YES). |
FILTER_SOURCE_FILES = NO |
#--------------------------------------------------------------------------- |
# configuration options related to source browsing |
#--------------------------------------------------------------------------- |
# If the SOURCE_BROWSER tag is set to YES then a list of source files will |
# be generated. Documented entities will be cross-referenced with these sources. |
# Note: To get rid of all source code in the generated output, make sure also |
# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH |
# then you must also enable this option. If you don't then doxygen will produce |
# a warning and turn it on anyway |
SOURCE_BROWSER = NO |
# Setting the INLINE_SOURCES tag to YES will include the body |
# of functions and classes directly in the documentation. |
INLINE_SOURCES = NO |
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct |
# doxygen to hide any special comment blocks from generated source code |
# fragments. Normal C and C++ comments will always remain visible. |
STRIP_CODE_COMMENTS = YES |
# If the REFERENCED_BY_RELATION tag is set to YES (the default) |
# then for each documented function all documented |
# functions referencing it will be listed. |
REFERENCED_BY_RELATION = NO |
# If the REFERENCES_RELATION tag is set to YES (the default) |
# then for each documented function all documented entities |
# called/used by that function will be listed. |
REFERENCES_RELATION = NO |
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) |
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from |
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will |
# link to the source code. Otherwise they will link to the documentstion. |
REFERENCES_LINK_SOURCE = YES |
# If the USE_HTAGS tag is set to YES then the references to source code |
# will point to the HTML generated by the htags(1) tool instead of doxygen |
# built-in source browser. The htags tool is part of GNU's global source |
# tagging system (see http://www.gnu.org/software/global/global.html). You |
# will need version 4.8.6 or higher. |
USE_HTAGS = NO |
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen |
# will generate a verbatim copy of the header file for each class for |
# which an include is specified. Set to NO to disable this. |
VERBATIM_HEADERS = NO |
#--------------------------------------------------------------------------- |
# configuration options related to the alphabetical class index |
#--------------------------------------------------------------------------- |
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index |
# of all compounds will be generated. Enable this if the project |
# contains a lot of classes, structs, unions or interfaces. |
ALPHABETICAL_INDEX = NO |
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then |
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns |
# in which this list will be split (can be a number in the range [1..20]) |
COLS_IN_ALPHA_INDEX = 5 |
# In case all classes in a project start with a common prefix, all |
# classes will be put under the same header in the alphabetical index. |
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that |
# should be ignored while generating the index headers. |
IGNORE_PREFIX = |
#--------------------------------------------------------------------------- |
# configuration options related to the HTML output |
#--------------------------------------------------------------------------- |
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will |
# generate HTML output. |
GENERATE_HTML = YES |
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. |
# If a relative path is entered the value of OUTPUT_DIRECTORY will be |
# put in front of it. If left blank `html' will be used as the default path. |
HTML_OUTPUT = html |
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for |
# each generated HTML page (for example: .htm,.php,.asp). If it is left blank |
# doxygen will generate files with .html extension. |
HTML_FILE_EXTENSION = .html |
# The HTML_HEADER tag can be used to specify a personal HTML header for |
# each generated HTML page. If it is left blank doxygen will generate a |
# standard header. |
HTML_HEADER = |
# The HTML_FOOTER tag can be used to specify a personal HTML footer for |
# each generated HTML page. If it is left blank doxygen will generate a |
# standard footer. |
HTML_FOOTER = |
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading |
# style sheet that is used by each HTML page. It can be used to |
# fine-tune the look of the HTML output. If the tag is left blank doxygen |
# will generate a default style sheet. Note that doxygen will try to copy |
# the style sheet file to the HTML output directory, so don't put your own |
# stylesheet in the HTML output directory as well, or it will be erased! |
HTML_STYLESHEET = |
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, |
# files or namespaces will be aligned in HTML using tables. If set to |
# NO a bullet list will be used. |
HTML_ALIGN_MEMBERS = YES |
# If the GENERATE_HTMLHELP tag is set to YES, additional index files |
# will be generated that can be used as input for tools like the |
# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) |
# of the generated HTML documentation. |
GENERATE_HTMLHELP = NO |
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML |
# documentation will contain sections that can be hidden and shown after the |
# page has loaded. For this to work a browser that supports |
# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox |
# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). |
HTML_DYNAMIC_SECTIONS = NO |
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can |
# be used to specify the file name of the resulting .chm file. You |
# can add a path in front of the file if the result should not be |
# written to the html output directory. |
CHM_FILE = |
# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can |
# be used to specify the location (absolute path including file name) of |
# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run |
# the HTML help compiler on the generated index.hhp. |
HHC_LOCATION = |
# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag |
# controls if a separate .chi index file is generated (YES) or that |
# it should be included in the master .chm file (NO). |
GENERATE_CHI = NO |
# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag |
# controls whether a binary table of contents is generated (YES) or a |
# normal table of contents (NO) in the .chm file. |
BINARY_TOC = NO |
# The TOC_EXPAND flag can be set to YES to add extra items for group members |
# to the contents of the HTML help documentation and to the tree view. |
TOC_EXPAND = NO |
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at |
# top of each HTML page. The value NO (the default) enables the index and |
# the value YES disables it. |
DISABLE_INDEX = NO |
# This tag can be used to set the number of enum values (range [1..20]) |
# that doxygen will group on one line in the generated HTML documentation. |
ENUM_VALUES_PER_LINE = 4 |
# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be |
# generated containing a tree-like index structure (just like the one that |
# is generated for HTML Help). For this to work a browser that supports |
# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, |
# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are |
# probably better off using the HTML help feature. |
GENERATE_TREEVIEW = NO |
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be |
# used to set the initial width (in pixels) of the frame in which the tree |
# is shown. |
TREEVIEW_WIDTH = 250 |
#--------------------------------------------------------------------------- |
# configuration options related to the LaTeX output |
#--------------------------------------------------------------------------- |
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will |
# generate Latex output. |
GENERATE_LATEX = NO |
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. |
# If a relative path is entered the value of OUTPUT_DIRECTORY will be |
# put in front of it. If left blank `latex' will be used as the default path. |
LATEX_OUTPUT = latex |
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be |
# invoked. If left blank `latex' will be used as the default command name. |
LATEX_CMD_NAME = latex |
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to |
# generate index for LaTeX. If left blank `makeindex' will be used as the |
# default command name. |
MAKEINDEX_CMD_NAME = makeindex |
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact |
# LaTeX documents. This may be useful for small projects and may help to |
# save some trees in general. |
COMPACT_LATEX = NO |
# The PAPER_TYPE tag can be used to set the paper type that is used |
# by the printer. Possible values are: a4, a4wide, letter, legal and |
# executive. If left blank a4wide will be used. |
PAPER_TYPE = a4wide |
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX |
# packages that should be included in the LaTeX output. |
EXTRA_PACKAGES = |
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for |
# the generated latex document. The header should contain everything until |
# the first chapter. If it is left blank doxygen will generate a |
# standard header. Notice: only use this tag if you know what you are doing! |
LATEX_HEADER = |
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated |
# is prepared for conversion to pdf (using ps2pdf). The pdf file will |
# contain links (just like the HTML output) instead of page references |
# This makes the output suitable for online browsing using a pdf viewer. |
PDF_HYPERLINKS = NO |
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of |
# plain latex in the generated Makefile. Set this option to YES to get a |
# higher quality PDF documentation. |
USE_PDFLATEX = NO |
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. |
# command to the generated LaTeX files. This will instruct LaTeX to keep |
# running if errors occur, instead of asking the user for help. |
# This option is also used when generating formulas in HTML. |
LATEX_BATCHMODE = NO |
# If LATEX_HIDE_INDICES is set to YES then doxygen will not |
# include the index chapters (such as File Index, Compound Index, etc.) |
# in the output. |
LATEX_HIDE_INDICES = NO |
#--------------------------------------------------------------------------- |
# configuration options related to the RTF output |
#--------------------------------------------------------------------------- |
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output |
# The RTF output is optimized for Word 97 and may not look very pretty with |
# other RTF readers or editors. |
GENERATE_RTF = NO |
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. |
# If a relative path is entered the value of OUTPUT_DIRECTORY will be |
# put in front of it. If left blank `rtf' will be used as the default path. |
RTF_OUTPUT = rtf |
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact |
# RTF documents. This may be useful for small projects and may help to |
# save some trees in general. |
COMPACT_RTF = NO |
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated |
# will contain hyperlink fields. The RTF file will |
# contain links (just like the HTML output) instead of page references. |
# This makes the output suitable for online browsing using WORD or other |
# programs which support those fields. |
# Note: wordpad (write) and others do not support links. |
RTF_HYPERLINKS = NO |
# Load stylesheet definitions from file. Syntax is similar to doxygen's |
# config file, i.e. a series of assignments. You only have to provide |
# replacements, missing definitions are set to their default value. |
RTF_STYLESHEET_FILE = |
# Set optional variables used in the generation of an rtf document. |
# Syntax is similar to doxygen's config file. |
RTF_EXTENSIONS_FILE = |
#--------------------------------------------------------------------------- |
# configuration options related to the man page output |
#--------------------------------------------------------------------------- |
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will |
# generate man pages |
GENERATE_MAN = NO |
# The MAN_OUTPUT tag is used to specify where the man pages will be put. |
# If a relative path is entered the value of OUTPUT_DIRECTORY will be |
# put in front of it. If left blank `man' will be used as the default path. |
MAN_OUTPUT = man |
# The MAN_EXTENSION tag determines the extension that is added to |
# the generated man pages (default is the subroutine's section .3) |
MAN_EXTENSION = .3 |
# If the MAN_LINKS tag is set to YES and Doxygen generates man output, |
# then it will generate one additional man file for each entity |
# documented in the real man page(s). These additional files |
# only source the real man page, but without them the man command |
# would be unable to find the correct page. The default is NO. |
MAN_LINKS = NO |
#--------------------------------------------------------------------------- |
# configuration options related to the XML output |
#--------------------------------------------------------------------------- |
# If the GENERATE_XML tag is set to YES Doxygen will |
# generate an XML file that captures the structure of |
# the code including all documentation. |
GENERATE_XML = NO |
# The XML_OUTPUT tag is used to specify where the XML pages will be put. |
# If a relative path is entered the value of OUTPUT_DIRECTORY will be |
# put in front of it. If left blank `xml' will be used as the default path. |
XML_OUTPUT = xml |
# The XML_SCHEMA tag can be used to specify an XML schema, |
# which can be used by a validating XML parser to check the |
# syntax of the XML files. |
XML_SCHEMA = |
# The XML_DTD tag can be used to specify an XML DTD, |
# which can be used by a validating XML parser to check the |
# syntax of the XML files. |
XML_DTD = |
# If the XML_PROGRAMLISTING tag is set to YES Doxygen will |
# dump the program listings (including syntax highlighting |
# and cross-referencing information) to the XML output. Note that |
# enabling this will significantly increase the size of the XML output. |
XML_PROGRAMLISTING = YES |
#--------------------------------------------------------------------------- |
# configuration options for the AutoGen Definitions output |
#--------------------------------------------------------------------------- |
# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will |
# generate an AutoGen Definitions (see autogen.sf.net) file |
# that captures the structure of the code including all |
# documentation. Note that this feature is still experimental |
# and incomplete at the moment. |
GENERATE_AUTOGEN_DEF = NO |
#--------------------------------------------------------------------------- |
# configuration options related to the Perl module output |
#--------------------------------------------------------------------------- |
# If the GENERATE_PERLMOD tag is set to YES Doxygen will |
# generate a Perl module file that captures the structure of |
# the code including all documentation. Note that this |
# feature is still experimental and incomplete at the |
# moment. |
GENERATE_PERLMOD = NO |
# If the PERLMOD_LATEX tag is set to YES Doxygen will generate |
# the necessary Makefile rules, Perl scripts and LaTeX code to be able |
# to generate PDF and DVI output from the Perl module output. |
PERLMOD_LATEX = NO |
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be |
# nicely formatted so it can be parsed by a human reader. This is useful |
# if you want to understand what is going on. On the other hand, if this |
# tag is set to NO the size of the Perl module output will be much smaller |
# and Perl will parse it just the same. |
PERLMOD_PRETTY = YES |
# The names of the make variables in the generated doxyrules.make file |
# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. |
# This is useful so different doxyrules.make files included by the same |
# Makefile don't overwrite each other's variables. |
PERLMOD_MAKEVAR_PREFIX = |
#--------------------------------------------------------------------------- |
# Configuration options related to the preprocessor |
#--------------------------------------------------------------------------- |
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will |
# evaluate all C-preprocessor directives found in the sources and include |
# files. |
ENABLE_PREPROCESSING = YES |
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro |
# names in the source code. If set to NO (the default) only conditional |
# compilation will be performed. Macro expansion can be done in a controlled |
# way by setting EXPAND_ONLY_PREDEF to YES. |
MACRO_EXPANSION = NO |
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES |
# then the macro expansion is limited to the macros specified with the |
# PREDEFINED and EXPAND_AS_DEFINED tags. |
EXPAND_ONLY_PREDEF = NO |
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files |
# in the INCLUDE_PATH (see below) will be search if a #include is found. |
SEARCH_INCLUDES = YES |
# The INCLUDE_PATH tag can be used to specify one or more directories that |
# contain include files that are not input files but should be processed by |
# the preprocessor. |
INCLUDE_PATH = |
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard |
# patterns (like *.h and *.hpp) to filter out the header-files in the |
# directories. If left blank, the patterns specified with FILE_PATTERNS will |
# be used. |
INCLUDE_FILE_PATTERNS = |
# The PREDEFINED tag can be used to specify one or more macro names that |
# are defined before the preprocessor is started (similar to the -D option of |
# gcc). The argument of the tag is a list of macros of the form: name |
# or name=definition (no spaces). If the definition and the = are |
# omitted =1 is assumed. To prevent a macro definition from being |
# undefined via #undef or recursively expanded use the := operator |
# instead of the = operator. |
PREDEFINED = DOXYGEN=1 |
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then |
# this tag can be used to specify a list of macro names that should be expanded. |
# The macro definition that is found in the sources will be used. |
# Use the PREDEFINED tag if you want to use a different macro definition. |
EXPAND_AS_DEFINED = |
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then |
# doxygen's preprocessor will remove all function-like macros that are alone |
# on a line, have an all uppercase name, and do not end with a semicolon. Such |
# function macros are typically used for boiler-plate code, and will confuse |
# the parser if not removed. |
SKIP_FUNCTION_MACROS = YES |
#--------------------------------------------------------------------------- |
# Configuration::additions related to external references |
#--------------------------------------------------------------------------- |
# The TAGFILES option can be used to specify one or more tagfiles. |
# Optionally an initial location of the external documentation |
# can be added for each tagfile. The format of a tag file without |
# this location is as follows: |
# TAGFILES = file1 file2 ... |
# Adding location for the tag files is done as follows: |
# TAGFILES = file1=loc1 "file2 = loc2" ... |
# where "loc1" and "loc2" can be relative or absolute paths or |
# URLs. If a location is present for each tag, the installdox tool |
# does not have to be run to correct the links. |
# Note that each tag file must have a unique name |
# (where the name does NOT include the path) |
# If a tag file is not located in the directory in which doxygen |
# is run, you must also specify the path to the tagfile here. |
TAGFILES = |
# When a file name is specified after GENERATE_TAGFILE, doxygen will create |
# a tag file that is based on the input files it reads. |
GENERATE_TAGFILE = |
# If the ALLEXTERNALS tag is set to YES all external classes will be listed |
# in the class index. If set to NO only the inherited external classes |
# will be listed. |
ALLEXTERNALS = NO |
# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed |
# in the modules index. If set to NO, only the current project's groups will |
# be listed. |
EXTERNAL_GROUPS = YES |
# The PERL_PATH should be the absolute path and name of the perl script |
# interpreter (i.e. the result of `which perl'). |
PERL_PATH = /usr/bin/perl |
#--------------------------------------------------------------------------- |
# Configuration options related to the dot tool |
#--------------------------------------------------------------------------- |
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will |
# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base |
# or super classes. Setting the tag to NO turns the diagrams off. Note that |
# this option is superseded by the HAVE_DOT option below. This is only a |
# fallback. It is recommended to install and use dot, since it yields more |
# powerful graphs. |
CLASS_DIAGRAMS = YES |
# You can define message sequence charts within doxygen comments using the \msc |
# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to |
# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to |
# specify the directory where the mscgen tool resides. If left empty the tool is assumed to |
# be found in the default search path. |
MSCGEN_PATH = |
# If set to YES, the inheritance and collaboration graphs will hide |
# inheritance and usage relations if the target is undocumented |
# or is not a class. |
HIDE_UNDOC_RELATIONS = YES |
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is |
# available from the path. This tool is part of Graphviz, a graph visualization |
# toolkit from AT&T and Lucent Bell Labs. The other options in this section |
# have no effect if this option is set to NO (the default) |
HAVE_DOT = NO |
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen |
# will generate a graph for each documented class showing the direct and |
# indirect inheritance relations. Setting this tag to YES will force the |
# the CLASS_DIAGRAMS tag to NO. |
CLASS_GRAPH = YES |
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen |
# will generate a graph for each documented class showing the direct and |
# indirect implementation dependencies (inheritance, containment, and |
# class references variables) of the class with other documented classes. |
COLLABORATION_GRAPH = YES |
# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen |
# will generate a graph for groups, showing the direct groups dependencies |
GROUP_GRAPHS = YES |
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and |
# collaboration diagrams in a style similar to the OMG's Unified Modeling |
# Language. |
UML_LOOK = NO |
# If set to YES, the inheritance and collaboration graphs will show the |
# relations between templates and their instances. |
TEMPLATE_RELATIONS = NO |
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT |
# tags are set to YES then doxygen will generate a graph for each documented |
# file showing the direct and indirect include dependencies of the file with |
# other documented files. |
INCLUDE_GRAPH = YES |
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and |
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each |
# documented header file showing the documented files that directly or |
# indirectly include this file. |
INCLUDED_BY_GRAPH = YES |
# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will |
# generate a call dependency graph for every global function or class method. |
# Note that enabling this option will significantly increase the time of a run. |
# So in most cases it will be better to enable call graphs for selected |
# functions only using the \callgraph command. |
CALL_GRAPH = NO |
# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will |
# generate a caller dependency graph for every global function or class method. |
# Note that enabling this option will significantly increase the time of a run. |
# So in most cases it will be better to enable caller graphs for selected |
# functions only using the \callergraph command. |
CALLER_GRAPH = NO |
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen |
# will graphical hierarchy of all classes instead of a textual one. |
GRAPHICAL_HIERARCHY = YES |
# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES |
# then doxygen will show the dependencies a directory has on other directories |
# in a graphical way. The dependency relations are determined by the #include |
# relations between the files in the directories. |
DIRECTORY_GRAPH = YES |
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images |
# generated by dot. Possible values are png, jpg, or gif |
# If left blank png will be used. |
DOT_IMAGE_FORMAT = png |
# The tag DOT_PATH can be used to specify the path where the dot tool can be |
# found. If left blank, it is assumed the dot tool can be found in the path. |
DOT_PATH = |
# The DOTFILE_DIRS tag can be used to specify one or more directories that |
# contain dot files that are included in the documentation (see the |
# \dotfile command). |
DOTFILE_DIRS = |
# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of |
# nodes that will be shown in the graph. If the number of nodes in a graph |
# becomes larger than this value, doxygen will truncate the graph, which is |
# visualized by representing a node as a red box. Note that doxygen if the number |
# of direct children of the root node in a graph is already larger than |
# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note |
# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. |
DOT_GRAPH_MAX_NODES = 50 |
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the |
# graphs generated by dot. A depth value of 3 means that only nodes reachable |
# from the root by following a path via at most 3 edges will be shown. Nodes |
# that lay further from the root node will be omitted. Note that setting this |
# option to 1 or 2 may greatly reduce the computation time needed for large |
# code bases. Also note that the size of a graph can be further restricted by |
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. |
MAX_DOT_GRAPH_DEPTH = 1000 |
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent |
# background. This is disabled by default, which results in a white background. |
# Warning: Depending on the platform used, enabling this option may lead to |
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to |
# read). |
DOT_TRANSPARENT = NO |
# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output |
# files in one run (i.e. multiple -o and -T options on the command line). This |
# makes dot run faster, but since only newer versions of dot (>1.8.10) |
# support this, this feature is disabled by default. |
DOT_MULTI_TARGETS = NO |
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will |
# generate a legend page explaining the meaning of the various boxes and |
# arrows in the dot generated graphs. |
GENERATE_LEGEND = YES |
# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will |
# remove the intermediate dot files that are used to generate |
# the various graphs. |
DOT_CLEANUP = YES |
#--------------------------------------------------------------------------- |
# Configuration::additions related to the search engine |
#--------------------------------------------------------------------------- |
# The SEARCHENGINE tag specifies whether or not a search engine should be |
# used. If set to NO the values of all tags below this one will be ignored. |
SEARCHENGINE = NO |
/Designs/Data_loggers/GPSRL02A/SW/logger/Makefile |
---|
0,0 → 1,52 |
NAME := sd-reader |
HEX := $(NAME).hex |
OUT := $(NAME).out |
MAP := $(NAME).map |
SOURCES := $(wildcard *.c) |
HEADERS := $(wildcard *.h) |
OBJECTS := $(patsubst %.c,%.o,$(SOURCES)) |
MCU := atmega168 |
MCU_AVRDUDE := m168 |
MCU_FREQ := 16000000UL |
CC := avr-gcc |
OBJCOPY := avr-objcopy |
SIZE := avr-size -A |
DOXYGEN := doxygen |
CFLAGS := -Wall -pedantic -mmcu=$(MCU) -std=c99 -g -Os -DF_CPU=$(MCU_FREQ) |
all: $(HEX) |
clean: |
rm -f $(HEX) $(OUT) $(MAP) $(OBJECTS) |
rm -rf doc/html |
flash: $(HEX) |
avrdude -y -p $(MCU_AVRDUDE) -P /dev/ttyUSB0 -c stk500v2 -U flash:w:$(HEX) |
$(HEX): $(OUT) |
$(OBJCOPY) -R .eeprom -O ihex $< $@ |
$(OUT): $(OBJECTS) |
$(CC) $(CFLAGS) -o $@ -Wl,-Map,$(MAP) $^ |
@echo |
@$(SIZE) $@ |
@echo |
%.o: %.c $(HEADERS) |
$(CC) $(CFLAGS) -c -o $@ $< |
%.pp: %.c |
$(CC) $(CFLAGS) -E -o $@ $< |
%.ppo: %.c |
$(CC) $(CFLAGS) -E $< |
doc: $(HEADERS) $(SOURCES) Doxyfile |
$(DOXYGEN) Doxyfile |
.PHONY: all clean flash doc |
/Designs/Data_loggers/GPSRL02A/SW/logger/doc/pic01.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/logger/doc/pic02.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/logger/fat16.c |
---|
0,0 → 1,2233 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* This file is free software; you can redistribute it and/or modify |
* it under the terms of either the GNU General Public License version 2 |
* or the GNU Lesser General Public License version 2.1, both as |
* published by the Free Software Foundation. |
*/ |
#include "partition.h" |
#include "fat16.h" |
#include "fat16_config.h" |
#include "sd-reader_config.h" |
#include <string.h> |
#if USE_DYNAMIC_MEMORY |
#include <stdlib.h> |
#endif |
/** |
* \addtogroup fat16 FAT16 support |
* |
* This module implements FAT16 read and write access. |
* |
* The following features are supported: |
* - File names up to 31 characters long. |
* - Unlimited depth of subdirectories. |
* - Short 8.3 and long filenames. |
* - Creating and deleting files. |
* - Reading and writing from and to files. |
* - File resizing. |
* - File sizes of up to 4 gigabytes. |
* |
* @{ |
*/ |
/** |
* \file |
* FAT16 implementation (license: GPLv2 or LGPLv2.1) |
* |
* \author Roland Riegel |
*/ |
/** |
* \addtogroup fat16_config FAT16 configuration |
* Preprocessor defines to configure the FAT16 implementation. |
*/ |
/** |
* \addtogroup fat16_fs FAT16 access |
* Basic functions for handling a FAT16 filesystem. |
*/ |
/** |
* \addtogroup fat16_file FAT16 file functions |
* Functions for managing files. |
*/ |
/** |
* \addtogroup fat16_dir FAT16 directory functions |
* Functions for managing directories. |
*/ |
/** |
* @} |
*/ |
#define FAT16_CLUSTER_FREE 0x0000 |
#define FAT16_CLUSTER_RESERVED_MIN 0xfff0 |
#define FAT16_CLUSTER_RESERVED_MAX 0xfff6 |
#define FAT16_CLUSTER_BAD 0xfff7 |
#define FAT16_CLUSTER_LAST_MIN 0xfff8 |
#define FAT16_CLUSTER_LAST_MAX 0xffff |
#define FAT16_DIRENTRY_DELETED 0xe5 |
#define FAT16_DIRENTRY_LFNLAST (1 << 6) |
#define FAT16_DIRENTRY_LFNSEQMASK ((1 << 6) - 1) |
/* Each entry within the directory table has a size of 32 bytes |
* and either contains a 8.3 DOS-style file name or a part of a |
* long file name, which may consist of several directory table |
* entries at once. |
* |
* multi-byte integer values are stored little-endian! |
* |
* 8.3 file name entry: |
* ==================== |
* offset length description |
* 0 8 name (space padded) |
* 8 3 extension (space padded) |
* 11 1 attributes (FAT16_ATTRIB_*) |
* |
* long file name (lfn) entry ordering for a single file name: |
* =========================================================== |
* LFN entry n |
* ... |
* LFN entry 2 |
* LFN entry 1 |
* 8.3 entry (see above) |
* |
* lfn entry: |
* ========== |
* offset length description |
* 0 1 ordinal field |
* 1 2 unicode character 1 |
* 3 3 unicode character 2 |
* 5 3 unicode character 3 |
* 7 3 unicode character 4 |
* 9 3 unicode character 5 |
* 11 1 attribute (always 0x0f) |
* 12 1 type (reserved, always 0) |
* 13 1 checksum |
* 14 2 unicode character 6 |
* 16 2 unicode character 7 |
* 18 2 unicode character 8 |
* 20 2 unicode character 9 |
* 22 2 unicode character 10 |
* 24 2 unicode character 11 |
* 26 2 cluster (unused, always 0) |
* 28 2 unicode character 12 |
* 30 2 unicode character 13 |
* |
* The ordinal field contains a descending number, from n to 1. |
* For the n'th lfn entry the ordinal field is or'ed with 0x40. |
* For deleted lfn entries, the ordinal field is set to 0xe5. |
*/ |
struct fat16_header_struct |
{ |
uint32_t size; |
uint32_t fat_offset; |
uint32_t fat_size; |
uint16_t sector_size; |
uint16_t cluster_size; |
uint32_t root_dir_offset; |
uint32_t cluster_zero_offset; |
}; |
struct fat16_fs_struct |
{ |
struct partition_struct* partition; |
struct fat16_header_struct header; |
}; |
struct fat16_file_struct |
{ |
struct fat16_fs_struct* fs; |
struct fat16_dir_entry_struct dir_entry; |
uint32_t pos; |
uint16_t pos_cluster; |
}; |
struct fat16_dir_struct |
{ |
struct fat16_fs_struct* fs; |
struct fat16_dir_entry_struct dir_entry; |
uint16_t entry_next; |
}; |
struct fat16_read_callback_arg |
{ |
uint16_t entry_cur; |
uint16_t entry_num; |
uint32_t entry_offset; |
uint8_t byte_count; |
}; |
struct fat16_usage_count_callback_arg |
{ |
uint16_t cluster_count; |
uint8_t buffer_size; |
}; |
#if !USE_DYNAMIC_MEMORY |
static struct fat16_fs_struct fat16_fs_handlers[FAT16_FS_COUNT]; |
static struct fat16_file_struct fat16_file_handlers[FAT16_FILE_COUNT]; |
static struct fat16_dir_struct fat16_dir_handlers[FAT16_DIR_COUNT]; |
#endif |
static uint8_t fat16_read_header(struct fat16_fs_struct* fs); |
static uint8_t fat16_read_root_dir_entry(const struct fat16_fs_struct* fs, uint16_t entry_num, struct fat16_dir_entry_struct* dir_entry); |
static uint8_t fat16_read_sub_dir_entry(const struct fat16_fs_struct* fs, uint16_t entry_num, const struct fat16_dir_entry_struct* parent, struct fat16_dir_entry_struct* dir_entry); |
static uint8_t fat16_dir_entry_seek_callback(uint8_t* buffer, uint32_t offset, void* p); |
static uint8_t fat16_dir_entry_read_callback(uint8_t* buffer, uint32_t offset, void* p); |
static uint8_t fat16_interpret_dir_entry(struct fat16_dir_entry_struct* dir_entry, const uint8_t* raw_entry); |
static uint16_t fat16_get_next_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num); |
static uint16_t fat16_append_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num, uint16_t count); |
static uint8_t fat16_free_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num); |
static uint8_t fat16_terminate_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num); |
static uint8_t fat16_clear_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num); |
static uint16_t fat16_clear_cluster_callback(uint8_t* buffer, uint32_t offset, void* p); |
static uint32_t fat16_find_offset_for_dir_entry(const struct fat16_fs_struct* fs, const struct fat16_dir_struct* parent, const struct fat16_dir_entry_struct* dir_entry); |
static uint8_t fat16_write_dir_entry(const struct fat16_fs_struct* fs, struct fat16_dir_entry_struct* dir_entry); |
static uint8_t fat16_get_fs_free_callback(uint8_t* buffer, uint32_t offset, void* p); |
static void fat16_set_file_modification_date(struct fat16_dir_entry_struct* dir_entry, uint16_t year, uint8_t month, uint8_t day); |
static void fat16_set_file_modification_time(struct fat16_dir_entry_struct* dir_entry, uint8_t hour, uint8_t min, uint8_t sec); |
/** |
* \ingroup fat16_fs |
* Opens a FAT16 filesystem. |
* |
* \param[in] partition Discriptor of partition on which the filesystem resides. |
* \returns 0 on error, a FAT16 filesystem descriptor on success. |
* \see fat16_open |
*/ |
struct fat16_fs_struct* fat16_open(struct partition_struct* partition) |
{ |
if(!partition || |
#if FAT16_WRITE_SUPPORT |
!partition->device_write || |
!partition->device_write_interval |
#else |
0 |
#endif |
) |
return 0; |
#if USE_DYNAMIC_MEMORY |
struct fat16_fs_struct* fs = malloc(sizeof(*fs)); |
if(!fs) |
return 0; |
#else |
struct fat16_fs_struct* fs = fat16_fs_handlers; |
uint8_t i; |
for(i = 0; i < FAT16_FS_COUNT; ++i) |
{ |
if(!fs->partition) |
break; |
++fs; |
} |
if(i >= FAT16_FS_COUNT) |
return 0; |
#endif |
memset(fs, 0, sizeof(*fs)); |
fs->partition = partition; |
if(!fat16_read_header(fs)) |
{ |
#if USE_DYNAMIC_MEMORY |
free(fs); |
#else |
fs->partition = 0; |
#endif |
return 0; |
} |
return fs; |
} |
/** |
* \ingroup fat16_fs |
* Closes a FAT16 filesystem. |
* |
* When this function returns, the given filesystem descriptor |
* will be invalid. |
* |
* \param[in] fs The filesystem to close. |
* \see fat16_open |
*/ |
void fat16_close(struct fat16_fs_struct* fs) |
{ |
if(!fs) |
return; |
#if USE_DYNAMIC_MEMORY |
free(fs); |
#else |
fs->partition = 0; |
#endif |
} |
/** |
* \ingroup fat16_fs |
* Reads and parses the header of a FAT16 filesystem. |
* |
* \param[inout] fs The filesystem for which to parse the header. |
* \returns 0 on failure, 1 on success. |
*/ |
uint8_t fat16_read_header(struct fat16_fs_struct* fs) |
{ |
if(!fs) |
return 0; |
struct partition_struct* partition = fs->partition; |
if(!partition) |
return 0; |
/* read fat parameters */ |
uint8_t buffer[25]; |
uint32_t partition_offset = partition->offset * 512; |
if(!partition->device_read(partition_offset + 0x0b, buffer, sizeof(buffer))) |
return 0; |
uint16_t bytes_per_sector = ((uint16_t) buffer[0x00]) | |
((uint16_t) buffer[0x01] << 8); |
uint8_t sectors_per_cluster = buffer[0x02]; |
uint16_t reserved_sectors = ((uint16_t) buffer[0x03]) | |
((uint16_t) buffer[0x04] << 8); |
uint8_t fat_copies = buffer[0x05]; |
uint16_t max_root_entries = ((uint16_t) buffer[0x06]) | |
((uint16_t) buffer[0x07] << 8); |
uint16_t sector_count_16 = ((uint16_t) buffer[0x08]) | |
((uint16_t) buffer[0x09] << 8); |
uint16_t sectors_per_fat = ((uint16_t) buffer[0x0b]) | |
((uint16_t) buffer[0x0c] << 8); |
uint32_t sector_count = ((uint32_t) buffer[0x15]) | |
((uint32_t) buffer[0x16] << 8) | |
((uint32_t) buffer[0x17] << 16) | |
((uint32_t) buffer[0x18] << 24); |
if(sectors_per_fat == 0) |
/* this is not a FAT16 */ |
return 0; |
if(sector_count == 0) |
{ |
if(sector_count_16 == 0) |
/* illegal volume size */ |
return 0; |
else |
sector_count = sector_count_16; |
} |
/* ensure we really have a FAT16 fs here */ |
uint32_t data_sector_count = sector_count |
- reserved_sectors |
- (uint32_t) sectors_per_fat * fat_copies |
- ((max_root_entries * 32 + bytes_per_sector - 1) / bytes_per_sector); |
uint32_t data_cluster_count = data_sector_count / sectors_per_cluster; |
if(data_cluster_count < 4085 || data_cluster_count >= 65525) |
/* this is not a FAT16 */ |
return 0; |
partition->type = PARTITION_TYPE_FAT16; |
/* fill header information */ |
struct fat16_header_struct* header = &fs->header; |
memset(header, 0, sizeof(*header)); |
header->size = sector_count * bytes_per_sector; |
header->fat_offset = /* jump to partition */ |
partition_offset + |
/* jump to fat */ |
(uint32_t) reserved_sectors * bytes_per_sector; |
header->fat_size = (data_cluster_count + 2) * 2; |
header->sector_size = bytes_per_sector; |
header->cluster_size = (uint32_t) bytes_per_sector * sectors_per_cluster; |
header->root_dir_offset = /* jump to fats */ |
header->fat_offset + |
/* jump to root directory entries */ |
(uint32_t) fat_copies * sectors_per_fat * bytes_per_sector; |
header->cluster_zero_offset = /* jump to root directory entries */ |
header->root_dir_offset + |
/* skip root directory entries */ |
(uint32_t) max_root_entries * 32; |
return 1; |
} |
/** |
* \ingroup fat16_fs |
* Reads a directory entry of the root directory. |
* |
* \param[in] fs Descriptor of file system to use. |
* \param[in] entry_num The index of the directory entry to read. |
* \param[out] dir_entry Directory entry descriptor which will get filled. |
* \returns 0 on failure, 1 on success |
* \see fat16_read_sub_dir_entry, fat16_read_dir_entry_by_path |
*/ |
uint8_t fat16_read_root_dir_entry(const struct fat16_fs_struct* fs, uint16_t entry_num, struct fat16_dir_entry_struct* dir_entry) |
{ |
if(!fs || !dir_entry) |
return 0; |
/* we read from the root directory entry */ |
const struct fat16_header_struct* header = &fs->header; |
device_read_interval_t device_read_interval = fs->partition->device_read_interval; |
uint8_t buffer[32]; |
/* seek to the n-th entry */ |
struct fat16_read_callback_arg arg; |
memset(&arg, 0, sizeof(arg)); |
arg.entry_num = entry_num; |
if(!device_read_interval(header->root_dir_offset, |
buffer, |
sizeof(buffer), |
header->cluster_zero_offset - header->root_dir_offset, |
fat16_dir_entry_seek_callback, |
&arg) || |
arg.entry_offset == 0 |
) |
return 0; |
/* read entry */ |
memset(dir_entry, 0, sizeof(*dir_entry)); |
if(!device_read_interval(arg.entry_offset, |
buffer, |
sizeof(buffer), |
arg.byte_count, |
fat16_dir_entry_read_callback, |
dir_entry)) |
return 0; |
return dir_entry->long_name[0] != '\0' ? 1 : 0; |
} |
/** |
* \ingroup fat16_fs |
* Reads a directory entry of a given parent directory. |
* |
* \param[in] fs Descriptor of file system to use. |
* \param[in] entry_num The index of the directory entry to read. |
* \param[in] parent Directory entry descriptor in which to read directory entry. |
* \param[out] dir_entry Directory entry descriptor which will get filled. |
* \returns 0 on failure, 1 on success |
* \see fat16_read_root_dir_entry, fat16_read_dir_entry_by_path |
*/ |
uint8_t fat16_read_sub_dir_entry(const struct fat16_fs_struct* fs, uint16_t entry_num, const struct fat16_dir_entry_struct* parent, struct fat16_dir_entry_struct* dir_entry) |
{ |
if(!fs || !parent || !dir_entry) |
return 0; |
/* we are in a parent directory and want to search within its directory entry table */ |
if(!(parent->attributes & FAT16_ATTRIB_DIR)) |
return 0; |
/* loop through all clusters of the directory */ |
uint8_t buffer[32]; |
uint32_t cluster_offset; |
uint16_t cluster_size = fs->header.cluster_size; |
uint16_t cluster_num = parent->cluster; |
struct fat16_read_callback_arg arg; |
while(1) |
{ |
/* calculate new cluster offset */ |
cluster_offset = fs->header.cluster_zero_offset + (uint32_t) (cluster_num - 2) * cluster_size; |
/* seek to the n-th entry */ |
memset(&arg, 0, sizeof(arg)); |
arg.entry_num = entry_num; |
if(!fs->partition->device_read_interval(cluster_offset, |
buffer, |
sizeof(buffer), |
cluster_size, |
fat16_dir_entry_seek_callback, |
&arg) |
) |
return 0; |
/* check if we found the entry */ |
if(arg.entry_offset) |
break; |
/* get number of next cluster */ |
if(!(cluster_num = fat16_get_next_cluster(fs, cluster_num))) |
return 0; /* directory entry not found */ |
} |
memset(dir_entry, 0, sizeof(*dir_entry)); |
/* read entry */ |
if(!fs->partition->device_read_interval(arg.entry_offset, |
buffer, |
sizeof(buffer), |
arg.byte_count, |
fat16_dir_entry_read_callback, |
dir_entry)) |
return 0; |
return dir_entry->long_name[0] != '\0' ? 1 : 0; |
} |
/** |
* \ingroup fat16_fs |
* Callback function for seeking through subdirectory entries. |
*/ |
uint8_t fat16_dir_entry_seek_callback(uint8_t* buffer, uint32_t offset, void* p) |
{ |
struct fat16_read_callback_arg* arg = p; |
/* skip deleted or empty entries */ |
if(buffer[0] == FAT16_DIRENTRY_DELETED || !buffer[0]) |
return 1; |
if(arg->entry_cur == arg->entry_num) |
{ |
arg->entry_offset = offset; |
arg->byte_count = buffer[11] == 0x0f ? |
((buffer[0] & FAT16_DIRENTRY_LFNSEQMASK) + 1) * 32 : |
32; |
return 0; |
} |
/* if we read a 8.3 entry, we reached a new directory entry */ |
if(buffer[11] != 0x0f) |
++arg->entry_cur; |
return 1; |
} |
/** |
* \ingroup fat16_fs |
* Callback function for reading a directory entry. |
*/ |
uint8_t fat16_dir_entry_read_callback(uint8_t* buffer, uint32_t offset, void* p) |
{ |
struct fat16_dir_entry_struct* dir_entry = p; |
/* there should not be any deleted or empty entries */ |
if(buffer[0] == FAT16_DIRENTRY_DELETED || !buffer[0]) |
return 0; |
if(!dir_entry->entry_offset) |
dir_entry->entry_offset = offset; |
switch(fat16_interpret_dir_entry(dir_entry, buffer)) |
{ |
case 0: /* failure */ |
return 0; |
case 1: /* buffer successfully parsed, continue */ |
return 1; |
case 2: /* directory entry complete, finish */ |
return 0; |
} |
return 0; |
} |
/** |
* \ingroup fat16_fs |
* Interprets a raw directory entry and puts the contained |
* information into the directory entry. |
* |
* For a single file there may exist multiple directory |
* entries. All except the last one are lfn entries, which |
* contain parts of the long filename. The last directory |
* entry is a traditional 8.3 style one. It contains all |
* other information like size, cluster, date and time. |
* |
* \param[in,out] dir_entry The directory entry to fill. |
* \param[in] raw_entry A pointer to 32 bytes of raw data. |
* \returns 0 on failure, 1 on success and 2 if the |
* directory entry is complete. |
*/ |
uint8_t fat16_interpret_dir_entry(struct fat16_dir_entry_struct* dir_entry, const uint8_t* raw_entry) |
{ |
if(!dir_entry || !raw_entry || !raw_entry[0]) |
return 0; |
char* long_name = dir_entry->long_name; |
if(raw_entry[11] == 0x0f) |
{ |
uint16_t char_offset = ((raw_entry[0] & 0x3f) - 1) * 13; |
if(char_offset + 12 < sizeof(dir_entry->long_name)) |
{ |
/* Lfn supports unicode, but we do not, for now. |
* So we assume pure ascii and read only every |
* second byte. |
*/ |
long_name[char_offset + 0] = raw_entry[1]; |
long_name[char_offset + 1] = raw_entry[3]; |
long_name[char_offset + 2] = raw_entry[5]; |
long_name[char_offset + 3] = raw_entry[7]; |
long_name[char_offset + 4] = raw_entry[9]; |
long_name[char_offset + 5] = raw_entry[14]; |
long_name[char_offset + 6] = raw_entry[16]; |
long_name[char_offset + 7] = raw_entry[18]; |
long_name[char_offset + 8] = raw_entry[20]; |
long_name[char_offset + 9] = raw_entry[22]; |
long_name[char_offset + 10] = raw_entry[24]; |
long_name[char_offset + 11] = raw_entry[28]; |
long_name[char_offset + 12] = raw_entry[30]; |
} |
return 1; |
} |
else |
{ |
/* if we do not have a long name, take the short one */ |
if(long_name[0] == '\0') |
{ |
uint8_t i; |
for(i = 0; i < 8; ++i) |
{ |
if(raw_entry[i] == ' ') |
break; |
long_name[i] = raw_entry[i]; |
} |
if(long_name[0] == 0x05) |
long_name[0] = (char) FAT16_DIRENTRY_DELETED; |
if(raw_entry[8] != ' ') |
{ |
long_name[i++] = '.'; |
uint8_t j = 8; |
for(; j < 11; ++j) |
{ |
if(raw_entry[j] != ' ') |
{ |
long_name[i++] = raw_entry[j]; |
} |
else |
{ |
break; |
} |
} |
} |
long_name[i] = '\0'; |
} |
/* extract properties of file and store them within the structure */ |
dir_entry->attributes = raw_entry[11]; |
dir_entry->cluster = ((uint16_t) raw_entry[26]) | |
((uint16_t) raw_entry[27] << 8); |
dir_entry->file_size = ((uint32_t) raw_entry[28]) | |
((uint32_t) raw_entry[29] << 8) | |
((uint32_t) raw_entry[30] << 16) | |
((uint32_t) raw_entry[31] << 24); |
#if FAT16_DATETIME_SUPPORT |
dir_entry->modification_time = ((uint16_t) raw_entry[22]) | |
((uint16_t) raw_entry[23] << 8); |
dir_entry->modification_date = ((uint16_t) raw_entry[24]) | |
((uint16_t) raw_entry[25] << 8); |
#endif |
return 2; |
} |
} |
/** |
* \ingroup fat16_file |
* Retrieves the directory entry of a path. |
* |
* The given path may both describe a file or a directory. |
* |
* \param[in] fs The FAT16 filesystem on which to search. |
* \param[in] path The path of which to read the directory entry. |
* \param[out] dir_entry The directory entry to fill. |
* \returns 0 on failure, 1 on success. |
* \see fat16_read_dir |
*/ |
uint8_t fat16_get_dir_entry_of_path(struct fat16_fs_struct* fs, const char* path, struct fat16_dir_entry_struct* dir_entry) |
{ |
if(!fs || !path || path[0] == '\0' || !dir_entry) |
return 0; |
if(path[0] == '/') |
++path; |
/* begin with the root directory */ |
memset(dir_entry, 0, sizeof(*dir_entry)); |
dir_entry->attributes = FAT16_ATTRIB_DIR; |
if(path[0] == '\0') |
return 1; |
while(1) |
{ |
struct fat16_dir_struct* dd = fat16_open_dir(fs, dir_entry); |
if(!dd) |
break; |
/* extract the next hierarchy we will search for */ |
const char* sep_pos = strchr(path, '/'); |
if(!sep_pos) |
sep_pos = path + strlen(path); |
uint8_t length_to_sep = sep_pos - path; |
/* read directory entries */ |
while(fat16_read_dir(dd, dir_entry)) |
{ |
/* check if we have found the next hierarchy */ |
if((strlen(dir_entry->long_name) != length_to_sep || |
strncmp(path, dir_entry->long_name, length_to_sep) != 0)) |
continue; |
fat16_close_dir(dd); |
dd = 0; |
if(path[length_to_sep] == '\0') |
/* we iterated through the whole path and have found the file */ |
return 1; |
if(dir_entry->attributes & FAT16_ATTRIB_DIR) |
{ |
/* we found a parent directory of the file we are searching for */ |
path = sep_pos + 1; |
break; |
} |
/* a parent of the file exists, but not the file itself */ |
return 0; |
} |
fat16_close_dir(dd); |
} |
return 0; |
} |
/** |
* \ingroup fat16_fs |
* Retrieves the next following cluster of a given cluster. |
* |
* Using the filesystem file allocation table, this function returns |
* the number of the cluster containing the data directly following |
* the data within the cluster with the given number. |
* |
* \param[in] fs The filesystem for which to determine the next cluster. |
* \param[in] cluster_num The number of the cluster for which to determine its successor. |
* \returns The wanted cluster number, or 0 on error. |
*/ |
uint16_t fat16_get_next_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num) |
{ |
if(!fs || cluster_num < 2) |
return 0; |
/* read appropriate fat entry */ |
uint8_t fat_entry[2]; |
if(!fs->partition->device_read(fs->header.fat_offset + 2 * cluster_num, fat_entry, 2)) |
return 0; |
/* determine next cluster from fat */ |
cluster_num = ((uint16_t) fat_entry[0]) | |
((uint16_t) fat_entry[1] << 8); |
if(cluster_num == FAT16_CLUSTER_FREE || |
cluster_num == FAT16_CLUSTER_BAD || |
(cluster_num >= FAT16_CLUSTER_RESERVED_MIN && cluster_num <= FAT16_CLUSTER_RESERVED_MAX) || |
(cluster_num >= FAT16_CLUSTER_LAST_MIN && cluster_num <= FAT16_CLUSTER_LAST_MAX)) |
return 0; |
return cluster_num; |
} |
/** |
* \ingroup fat16_fs |
* Appends a new cluster chain to an existing one. |
* |
* Set cluster_num to zero to create a completely new one. |
* |
* \param[in] fs The file system on which to operate. |
* \param[in] cluster_num The cluster to which to append the new chain. |
* \param[in] count The number of clusters to allocate. |
* \returns 0 on failure, the number of the first new cluster on success. |
*/ |
uint16_t fat16_append_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num, uint16_t count) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fs) |
return 0; |
device_read_t device_read = fs->partition->device_read; |
device_write_t device_write = fs->partition->device_write; |
uint32_t fat_offset = fs->header.fat_offset; |
uint16_t cluster_max = fs->header.fat_size / 2; |
uint16_t cluster_next = 0; |
uint16_t count_left = count; |
uint8_t buffer[2]; |
for(uint16_t cluster_new = 0; cluster_new < cluster_max; ++cluster_new) |
{ |
if(!device_read(fat_offset + 2 * cluster_new, buffer, sizeof(buffer))) |
return 0; |
/* check if this is a free cluster */ |
if(buffer[0] == (FAT16_CLUSTER_FREE & 0xff) && |
buffer[1] == ((FAT16_CLUSTER_FREE >> 8) & 0xff)) |
{ |
/* allocate cluster */ |
if(count_left == count) |
{ |
buffer[0] = FAT16_CLUSTER_LAST_MAX & 0xff; |
buffer[1] = (FAT16_CLUSTER_LAST_MAX >> 8) & 0xff; |
} |
else |
{ |
buffer[0] = cluster_next & 0xff; |
buffer[1] = (cluster_next >> 8) & 0xff; |
} |
if(!device_write(fat_offset + 2 * cluster_new, buffer, sizeof(buffer))) |
break; |
cluster_next = cluster_new; |
if(--count_left == 0) |
break; |
} |
} |
do |
{ |
if(count_left > 0) |
break; |
/* We allocated a new cluster chain. Now join |
* it with the existing one. |
*/ |
if(cluster_num >= 2) |
{ |
buffer[0] = cluster_next & 0xff; |
buffer[1] = (cluster_next >> 8) & 0xff; |
if(!device_write(fat_offset + 2 * cluster_num, buffer, sizeof(buffer))) |
break; |
} |
return cluster_next; |
} while(0); |
/* No space left on device or writing error. |
* Free up all clusters already allocated. |
*/ |
fat16_free_clusters(fs, cluster_next); |
return 0; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_fs |
* Frees a cluster chain, or a part thereof. |
* |
* Marks the specified cluster and all clusters which are sequentially |
* referenced by it as free. They may then be used again for future |
* file allocations. |
* |
* \note If this function is used for freeing just a part of a cluster |
* chain, the new end of the chain is not correctly terminated |
* within the FAT. Use fat16_terminate_clusters() instead. |
* |
* \param[in] fs The filesystem on which to operate. |
* \param[in] cluster_num The starting cluster of the chain which to free. |
* \returns 0 on failure, 1 on success. |
* \see fat16_terminate_clusters |
*/ |
uint8_t fat16_free_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fs || cluster_num < 2) |
return 0; |
uint32_t fat_offset = fs->header.fat_offset; |
uint8_t buffer[2]; |
while(cluster_num) |
{ |
if(!fs->partition->device_read(fat_offset + 2 * cluster_num, buffer, 2)) |
return 0; |
/* get next cluster of current cluster before freeing current cluster */ |
uint16_t cluster_num_next = ((uint16_t) buffer[0]) | |
((uint16_t) buffer[1] << 8); |
if(cluster_num_next == FAT16_CLUSTER_FREE) |
return 1; |
if(cluster_num_next == FAT16_CLUSTER_BAD || |
(cluster_num_next >= FAT16_CLUSTER_RESERVED_MIN && |
cluster_num_next <= FAT16_CLUSTER_RESERVED_MAX |
) |
) |
return 0; |
if(cluster_num_next >= FAT16_CLUSTER_LAST_MIN && cluster_num_next <= FAT16_CLUSTER_LAST_MAX) |
cluster_num_next = 0; |
/* free cluster */ |
buffer[0] = FAT16_CLUSTER_FREE & 0xff; |
buffer[1] = (FAT16_CLUSTER_FREE >> 8) & 0xff; |
fs->partition->device_write(fat_offset + 2 * cluster_num, buffer, 2); |
/* We continue in any case here, even if freeing the cluster failed. |
* The cluster is lost, but maybe we can still free up some later ones. |
*/ |
cluster_num = cluster_num_next; |
} |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_fs |
* Frees a part of a cluster chain and correctly terminates the rest. |
* |
* Marks the specified cluster as the new end of a cluster chain and |
* frees all following clusters. |
* |
* \param[in] fs The filesystem on which to operate. |
* \param[in] cluster_num The new end of the cluster chain. |
* \returns 0 on failure, 1 on success. |
* \see fat16_free_clusters |
*/ |
uint8_t fat16_terminate_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fs || cluster_num < 2) |
return 0; |
/* fetch next cluster before overwriting the cluster entry */ |
uint16_t cluster_num_next = fat16_get_next_cluster(fs, cluster_num); |
/* mark cluster as the last one */ |
uint8_t buffer[2]; |
buffer[0] = FAT16_CLUSTER_LAST_MAX & 0xff; |
buffer[1] = (FAT16_CLUSTER_LAST_MAX >> 8) & 0xff; |
if(!fs->partition->device_write(fs->header.fat_offset + 2 * cluster_num, buffer, 2)) |
return 0; |
/* free remaining clusters */ |
if(cluster_num_next) |
return fat16_free_clusters(fs, cluster_num_next); |
else |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_fs |
* Clears a single cluster. |
* |
* The complete cluster is filled with zeros. |
* |
* \param[in] fs The filesystem on which to operate. |
* \param[in] cluster_num The cluster to clear. |
* \returns 0 on failure, 1 on success. |
*/ |
uint8_t fat16_clear_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num) |
{ |
#if FAT16_WRITE_SUPPORT |
if(cluster_num < 2) |
return 0; |
uint32_t cluster_offset = fs->header.cluster_zero_offset + |
(uint32_t) (cluster_num - 2) * fs->header.cluster_size; |
uint8_t zero[16]; |
return fs->partition->device_write_interval(cluster_offset, |
zero, |
fs->header.cluster_size, |
fat16_clear_cluster_callback, |
0 |
); |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_fs |
* Callback function for clearing a cluster. |
*/ |
uint16_t fat16_clear_cluster_callback(uint8_t* buffer, uint32_t offset, void* p) |
{ |
#if FAT16_WRITE_SUPPORT |
memset(buffer, 0, 16); |
return 16; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_file |
* Opens a file on a FAT16 filesystem. |
* |
* \param[in] fs The filesystem on which the file to open lies. |
* \param[in] dir_entry The directory entry of the file to open. |
* \returns The file handle, or 0 on failure. |
* \see fat16_close_file |
*/ |
struct fat16_file_struct* fat16_open_file(struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry) |
{ |
if(!fs || !dir_entry || (dir_entry->attributes & FAT16_ATTRIB_DIR)) |
return 0; |
#if USE_DYNAMIC_MEMORY |
struct fat16_file_struct* fd = malloc(sizeof(*fd)); |
if(!fd) |
return 0; |
#else |
struct fat16_file_struct* fd = fat16_file_handlers; |
uint8_t i; |
for(i = 0; i < FAT16_FILE_COUNT; ++i) |
{ |
if(!fd->fs) |
break; |
++fd; |
} |
if(i >= FAT16_FILE_COUNT) |
return 0; |
#endif |
memcpy(&fd->dir_entry, dir_entry, sizeof(*dir_entry)); |
fd->fs = fs; |
fd->pos = 0; |
fd->pos_cluster = dir_entry->cluster; |
return fd; |
} |
/** |
* \ingroup fat16_file |
* Closes a file. |
* |
* \param[in] fd The file handle of the file to close. |
* \see fat16_open_file |
*/ |
void fat16_close_file(struct fat16_file_struct* fd) |
{ |
if(fd) |
#if USE_DYNAMIC_MEMORY |
free(fd); |
#else |
fd->fs = 0; |
#endif |
} |
/** |
* \ingroup fat16_file |
* Reads data from a file. |
* |
* The data requested is read from the current file location. |
* |
* \param[in] fd The file handle of the file from which to read. |
* \param[out] buffer The buffer into which to write. |
* \param[in] buffer_len The amount of data to read. |
* \returns The number of bytes read, 0 on end of file, or -1 on failure. |
* \see fat16_write_file |
*/ |
int16_t fat16_read_file(struct fat16_file_struct* fd, uint8_t* buffer, uint16_t buffer_len) |
{ |
/* check arguments */ |
if(!fd || !buffer || buffer_len < 1) |
return -1; |
/* determine number of bytes to read */ |
if(fd->pos + buffer_len > fd->dir_entry.file_size) |
buffer_len = fd->dir_entry.file_size - fd->pos; |
if(buffer_len == 0) |
return 0; |
uint16_t cluster_size = fd->fs->header.cluster_size; |
uint16_t cluster_num = fd->pos_cluster; |
uint16_t buffer_left = buffer_len; |
uint16_t first_cluster_offset = fd->pos % cluster_size; |
/* find cluster in which to start reading */ |
if(!cluster_num) |
{ |
cluster_num = fd->dir_entry.cluster; |
if(!cluster_num) |
{ |
if(!fd->pos) |
return 0; |
else |
return -1; |
} |
if(fd->pos) |
{ |
uint32_t pos = fd->pos; |
while(pos >= cluster_size) |
{ |
pos -= cluster_size; |
cluster_num = fat16_get_next_cluster(fd->fs, cluster_num); |
if(!cluster_num) |
return -1; |
} |
} |
} |
/* read data */ |
do |
{ |
/* calculate data size to copy from cluster */ |
uint32_t cluster_offset = fd->fs->header.cluster_zero_offset + |
(uint32_t) (cluster_num - 2) * cluster_size + first_cluster_offset; |
uint16_t copy_length = cluster_size - first_cluster_offset; |
if(copy_length > buffer_left) |
copy_length = buffer_left; |
/* read data */ |
if(!fd->fs->partition->device_read(cluster_offset, buffer, copy_length)) |
return buffer_len - buffer_left; |
/* calculate new file position */ |
buffer += copy_length; |
buffer_left -= copy_length; |
fd->pos += copy_length; |
if(first_cluster_offset + copy_length >= cluster_size) |
{ |
/* we are on a cluster boundary, so get the next cluster */ |
if((cluster_num = fat16_get_next_cluster(fd->fs, cluster_num))) |
{ |
first_cluster_offset = 0; |
} |
else |
{ |
fd->pos_cluster = 0; |
return buffer_len - buffer_left; |
} |
} |
fd->pos_cluster = cluster_num; |
} while(buffer_left > 0); /* check if we are done */ |
return buffer_len; |
} |
/** |
* \ingroup fat16_file |
* Writes data to a file. |
* |
* The data is written to the current file location. |
* |
* \param[in] fd The file handle of the file to which to write. |
* \param[in] buffer The buffer from which to read the data to be written. |
* \param[in] buffer_len The amount of data to write. |
* \returns The number of bytes written, 0 on disk full, or -1 on failure. |
* \see fat16_read_file |
*/ |
int16_t fat16_write_file(struct fat16_file_struct* fd, const uint8_t* buffer, uint16_t buffer_len) |
{ |
#if FAT16_WRITE_SUPPORT |
/* check arguments */ |
if(!fd || !buffer || buffer_len < 1) |
return -1; |
if(fd->pos > fd->dir_entry.file_size) |
return -1; |
uint16_t cluster_size = fd->fs->header.cluster_size; |
uint16_t cluster_num = fd->pos_cluster; |
uint16_t buffer_left = buffer_len; |
uint16_t first_cluster_offset = fd->pos % cluster_size; |
/* find cluster in which to start writing */ |
if(!cluster_num) |
{ |
cluster_num = fd->dir_entry.cluster; |
if(!cluster_num) |
{ |
if(!fd->pos) |
{ |
/* empty file */ |
fd->dir_entry.cluster = cluster_num = fat16_append_clusters(fd->fs, 0, 1); |
if(!cluster_num) |
return -1; |
} |
else |
{ |
return -1; |
} |
} |
if(fd->pos) |
{ |
uint32_t pos = fd->pos; |
uint16_t cluster_num_next; |
while(pos >= cluster_size) |
{ |
pos -= cluster_size; |
cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num); |
if(!cluster_num_next && pos == 0) |
/* the file exactly ends on a cluster boundary, and we append to it */ |
cluster_num_next = fat16_append_clusters(fd->fs, cluster_num, 1); |
if(!cluster_num_next) |
return -1; |
cluster_num = cluster_num_next; |
} |
} |
} |
/* write data */ |
do |
{ |
/* calculate data size to write to cluster */ |
uint32_t cluster_offset = fd->fs->header.cluster_zero_offset + |
(uint32_t) (cluster_num - 2) * cluster_size + first_cluster_offset; |
uint16_t write_length = cluster_size - first_cluster_offset; |
if(write_length > buffer_left) |
write_length = buffer_left; |
/* write data which fits into the current cluster */ |
if(!fd->fs->partition->device_write(cluster_offset, buffer, write_length)) |
break; |
/* calculate new file position */ |
buffer += write_length; |
buffer_left -= write_length; |
fd->pos += write_length; |
if(first_cluster_offset + write_length >= cluster_size) |
{ |
/* we are on a cluster boundary, so get the next cluster */ |
uint16_t cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num); |
if(!cluster_num_next && buffer_left > 0) |
/* we reached the last cluster, append a new one */ |
cluster_num_next = fat16_append_clusters(fd->fs, cluster_num, 1); |
if(!cluster_num_next) |
{ |
fd->pos_cluster = 0; |
break; |
} |
cluster_num = cluster_num_next; |
first_cluster_offset = 0; |
} |
fd->pos_cluster = cluster_num; |
} while(buffer_left > 0); /* check if we are done */ |
/* update directory entry */ |
if(fd->pos > fd->dir_entry.file_size) |
{ |
uint32_t size_old = fd->dir_entry.file_size; |
/* update file size */ |
fd->dir_entry.file_size = fd->pos; |
/* write directory entry */ |
if(!fat16_write_dir_entry(fd->fs, &fd->dir_entry)) |
{ |
/* We do not return an error here since we actually wrote |
* some data to disk. So we calculate the amount of data |
* we wrote to disk and which lies within the old file size. |
*/ |
buffer_left = fd->pos - size_old; |
fd->pos = size_old; |
} |
} |
return buffer_len - buffer_left; |
#else |
return -1; |
#endif |
} |
/** |
* \ingroup fat16_file |
* Repositions the read/write file offset. |
* |
* Changes the file offset where the next call to fat16_read_file() |
* or fat16_write_file() starts reading/writing. |
* |
* If the new offset is beyond the end of the file, fat16_resize_file() |
* is implicitly called, i.e. the file is expanded. |
* |
* The new offset can be given in different ways determined by |
* the \c whence parameter: |
* - \b FAT16_SEEK_SET: \c *offset is relative to the beginning of the file. |
* - \b FAT16_SEEK_CUR: \c *offset is relative to the current file position. |
* - \b FAT16_SEEK_END: \c *offset is relative to the end of the file. |
* |
* The resulting absolute offset is written to the location the \c offset |
* parameter points to. |
* |
* \param[in] fd The file decriptor of the file on which to seek. |
* \param[in,out] offset A pointer to the new offset, as affected by the \c whence |
* parameter. The function writes the new absolute offset |
* to this location before it returns. |
* \param[in] whence Affects the way \c offset is interpreted, see above. |
* \returns 0 on failure, 1 on success. |
*/ |
uint8_t fat16_seek_file(struct fat16_file_struct* fd, int32_t* offset, uint8_t whence) |
{ |
if(!fd || !offset) |
return 0; |
uint32_t new_pos = fd->pos; |
switch(whence) |
{ |
case FAT16_SEEK_SET: |
new_pos = *offset; |
break; |
case FAT16_SEEK_CUR: |
new_pos += *offset; |
break; |
case FAT16_SEEK_END: |
new_pos = fd->dir_entry.file_size + *offset; |
break; |
default: |
return 0; |
} |
if(new_pos > fd->dir_entry.file_size && !fat16_resize_file(fd, new_pos)) |
return 0; |
fd->pos = new_pos; |
fd->pos_cluster = 0; |
*offset = new_pos; |
return 1; |
} |
/** |
* \ingroup fat16_file |
* Resizes a file to have a specific size. |
* |
* Enlarges or shrinks the file pointed to by the file descriptor to have |
* exactly the specified size. |
* |
* If the file is truncated, all bytes having an equal or larger offset |
* than the given size are lost. If the file is expanded, the additional |
* bytes are allocated. |
* |
* \note Please be aware that this function just allocates or deallocates disk |
* space, it does not explicitely clear it. To avoid data leakage, this |
* must be done manually. |
* |
* \param[in] fd The file decriptor of the file which to resize. |
* \param[in] size The new size of the file. |
* \returns 0 on failure, 1 on success. |
*/ |
uint8_t fat16_resize_file(struct fat16_file_struct* fd, uint32_t size) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fd) |
return 0; |
uint16_t cluster_num = fd->dir_entry.cluster; |
uint16_t cluster_size = fd->fs->header.cluster_size; |
uint32_t size_new = size; |
do |
{ |
if(cluster_num == 0 && size_new == 0) |
/* the file stays empty */ |
break; |
/* seek to the next cluster as long as we need the space */ |
while(size_new > cluster_size) |
{ |
/* get next cluster of file */ |
uint16_t cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num); |
if(cluster_num_next) |
{ |
cluster_num = cluster_num_next; |
size_new -= cluster_size; |
} |
else |
{ |
break; |
} |
} |
if(size_new > cluster_size || cluster_num == 0) |
{ |
/* Allocate new cluster chain and append |
* it to the existing one, if available. |
*/ |
uint16_t cluster_count = size_new / cluster_size; |
if((uint32_t) cluster_count * cluster_size < size_new) |
++cluster_count; |
uint16_t cluster_new_chain = fat16_append_clusters(fd->fs, cluster_num, cluster_count); |
if(!cluster_new_chain) |
return 0; |
if(!cluster_num) |
{ |
cluster_num = cluster_new_chain; |
fd->dir_entry.cluster = cluster_num; |
} |
} |
/* write new directory entry */ |
fd->dir_entry.file_size = size; |
if(size == 0) |
fd->dir_entry.cluster = 0; |
if(!fat16_write_dir_entry(fd->fs, &fd->dir_entry)) |
return 0; |
if(size == 0) |
{ |
/* free all clusters of file */ |
fat16_free_clusters(fd->fs, cluster_num); |
} |
else if(size_new <= cluster_size) |
{ |
/* free all clusters no longer needed */ |
fat16_terminate_clusters(fd->fs, cluster_num); |
} |
} while(0); |
/* correct file position */ |
if(size < fd->pos) |
{ |
fd->pos = size; |
fd->pos_cluster = 0; |
} |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_dir |
* Opens a directory. |
* |
* \param[in] fs The filesystem on which the directory to open resides. |
* \param[in] dir_entry The directory entry which stands for the directory to open. |
* \returns An opaque directory descriptor on success, 0 on failure. |
* \see fat16_close_dir |
*/ |
struct fat16_dir_struct* fat16_open_dir(struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry) |
{ |
if(!fs || !dir_entry || !(dir_entry->attributes & FAT16_ATTRIB_DIR)) |
return 0; |
#if USE_DYNAMIC_MEMORY |
struct fat16_dir_struct* dd = malloc(sizeof(*dd)); |
if(!dd) |
return 0; |
#else |
struct fat16_dir_struct* dd = fat16_dir_handlers; |
uint8_t i; |
for(i = 0; i < FAT16_DIR_COUNT; ++i) |
{ |
if(!dd->fs) |
break; |
++dd; |
} |
if(i >= FAT16_DIR_COUNT) |
return 0; |
#endif |
memcpy(&dd->dir_entry, dir_entry, sizeof(*dir_entry)); |
dd->fs = fs; |
dd->entry_next = 0; |
return dd; |
} |
/** |
* \ingroup fat16_dir |
* Closes a directory descriptor. |
* |
* This function destroys a directory descriptor which was |
* previously obtained by calling fat16_open_dir(). When this |
* function returns, the given descriptor will be invalid. |
* |
* \param[in] dd The directory descriptor to close. |
* \see fat16_open_dir |
*/ |
void fat16_close_dir(struct fat16_dir_struct* dd) |
{ |
if(dd) |
#if USE_DYNAMIC_MEMORY |
free(dd); |
#else |
dd->fs = 0; |
#endif |
} |
/** |
* \ingroup fat16_dir |
* Reads the next directory entry contained within a parent directory. |
* |
* \param[in] dd The descriptor of the parent directory from which to read the entry. |
* \param[out] dir_entry Pointer to a buffer into which to write the directory entry information. |
* \returns 0 on failure, 1 on success. |
* \see fat16_reset_dir |
*/ |
uint8_t fat16_read_dir(struct fat16_dir_struct* dd, struct fat16_dir_entry_struct* dir_entry) |
{ |
if(!dd || !dir_entry) |
return 0; |
if(dd->dir_entry.cluster == 0) |
{ |
/* read entry from root directory */ |
if(fat16_read_root_dir_entry(dd->fs, dd->entry_next, dir_entry)) |
{ |
++dd->entry_next; |
return 1; |
} |
} |
else |
{ |
/* read entry from a subdirectory */ |
if(fat16_read_sub_dir_entry(dd->fs, dd->entry_next, &dd->dir_entry, dir_entry)) |
{ |
++dd->entry_next; |
return 1; |
} |
} |
/* restart reading */ |
dd->entry_next = 0; |
return 0; |
} |
/** |
* \ingroup fat16_dir |
* Resets a directory handle. |
* |
* Resets the directory handle such that reading restarts |
* with the first directory entry. |
* |
* \param[in] dd The directory handle to reset. |
* \returns 0 on failure, 1 on success. |
* \see fat16_read_dir |
*/ |
uint8_t fat16_reset_dir(struct fat16_dir_struct* dd) |
{ |
if(!dd) |
return 0; |
dd->entry_next = 0; |
return 1; |
} |
/** |
* \ingroup fat16_fs |
* Searches for space where to store a directory entry. |
* |
* \param[in] fs The filesystem on which to operate. |
* \param[in] dir_entry The directory entry for which to search space. |
* \returns 0 on failure, a device offset on success. |
*/ |
uint32_t fat16_find_offset_for_dir_entry(const struct fat16_fs_struct* fs, const struct fat16_dir_struct* parent, const struct fat16_dir_entry_struct* dir_entry) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fs || !dir_entry) |
return 0; |
/* search for a place where to write the directory entry to disk */ |
uint8_t free_dir_entries_needed = (strlen(dir_entry->long_name) + 12) / 13 + 1; |
uint8_t free_dir_entries_found = 0; |
uint16_t cluster_num = parent->dir_entry.cluster; |
uint32_t dir_entry_offset = 0; |
uint32_t offset = 0; |
uint32_t offset_to = 0; |
if(cluster_num == 0) |
{ |
/* we read/write from the root directory entry */ |
offset = fs->header.root_dir_offset; |
offset_to = fs->header.cluster_zero_offset; |
dir_entry_offset = offset; |
} |
while(1) |
{ |
if(offset == offset_to) |
{ |
if(cluster_num == 0) |
/* We iterated through the whole root directory entry |
* and could not find enough space for the directory entry. |
*/ |
return 0; |
if(offset) |
{ |
/* We reached a cluster boundary and have to |
* switch to the next cluster. |
*/ |
uint16_t cluster_next = fat16_get_next_cluster(fs, cluster_num); |
if(!cluster_next) |
{ |
cluster_next = fat16_append_clusters(fs, cluster_num, 1); |
if(!cluster_next) |
return 0; |
/* we appended a new cluster and know it is free */ |
dir_entry_offset = fs->header.cluster_zero_offset + |
(uint32_t) (cluster_next - 2) * fs->header.cluster_size; |
/* clear cluster to avoid garbage directory entries */ |
fat16_clear_cluster(fs, cluster_next); |
break; |
} |
cluster_num = cluster_next; |
} |
offset = fs->header.cluster_zero_offset + |
(uint32_t) (cluster_num - 2) * fs->header.cluster_size; |
offset_to = offset + fs->header.cluster_size; |
dir_entry_offset = offset; |
free_dir_entries_found = 0; |
} |
/* read next lfn or 8.3 entry */ |
uint8_t first_char; |
if(!fs->partition->device_read(offset, &first_char, sizeof(first_char))) |
return 0; |
/* check if we found a free directory entry */ |
if(first_char == FAT16_DIRENTRY_DELETED || !first_char) |
{ |
/* check if we have the needed number of available entries */ |
++free_dir_entries_found; |
if(free_dir_entries_found >= free_dir_entries_needed) |
break; |
offset += 32; |
} |
else |
{ |
offset += 32; |
dir_entry_offset = offset; |
free_dir_entries_found = 0; |
} |
} |
return dir_entry_offset; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_fs |
* Writes a directory entry to disk. |
* |
* \note The file name is not checked for invalid characters. |
* |
* \note The generation of the short 8.3 file name is quite |
* simple. The first eight characters are used for the filename. |
* The extension, if any, is made up of the first three characters |
* following the last dot within the long filename. If the |
* filename (without the extension) is longer than eight characters, |
* the lower byte of the cluster number replaces the last two |
* characters to avoid name clashes. In any other case, it is your |
* responsibility to avoid name clashes. |
* |
* \param[in] fs The filesystem on which to operate. |
* \param[in] dir_entry The directory entry to write. |
* \returns 0 on failure, 1 on success. |
*/ |
uint8_t fat16_write_dir_entry(const struct fat16_fs_struct* fs, struct fat16_dir_entry_struct* dir_entry) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fs || !dir_entry) |
return 0; |
#if FAT16_DATETIME_SUPPORT |
{ |
uint16_t year; |
uint8_t month; |
uint8_t day; |
uint8_t hour; |
uint8_t min; |
uint8_t sec; |
fat16_get_datetime(&year, &month, &day, &hour, &min, &sec); |
fat16_set_file_modification_date(dir_entry, year, month, day); |
fat16_set_file_modification_time(dir_entry, hour, min, sec); |
} |
#endif |
device_write_t device_write = fs->partition->device_write; |
uint32_t offset = dir_entry->entry_offset; |
const char* name = dir_entry->long_name; |
uint8_t name_len = strlen(name); |
uint8_t lfn_entry_count = (name_len + 12) / 13; |
uint8_t buffer[32]; |
/* write 8.3 entry */ |
/* generate 8.3 file name */ |
memset(&buffer[0], ' ', 11); |
char* name_ext = strrchr(name, '.'); |
if(name_ext && *++name_ext) |
{ |
uint8_t name_ext_len = strlen(name_ext); |
name_len -= name_ext_len + 1; |
if(name_ext_len > 3) |
name_ext_len = 3; |
memcpy(&buffer[8], name_ext, name_ext_len); |
} |
if(name_len <= 8) |
{ |
memcpy(buffer, name, name_len); |
/* For now, we create lfn entries for all files, |
* except the "." and ".." directory references. |
* This is to avoid difficulties with capitalization, |
* as 8.3 filenames allow uppercase letters only. |
* |
* Theoretically it would be possible to leave |
* the 8.3 entry alone if the basename and the |
* extension have no mixed capitalization. |
*/ |
if(name[0] == '.' && |
((name[1] == '.' && name[2] == '\0') || |
name[1] == '\0') |
) |
lfn_entry_count = 0; |
} |
else |
{ |
memcpy(buffer, name, 8); |
/* Minimize 8.3 name clashes by appending |
* the lower byte of the cluster number. |
*/ |
uint8_t num = dir_entry->cluster & 0xff; |
buffer[6] = (num < 0xa0) ? ('0' + (num >> 4)) : ('a' + (num >> 4)); |
num &= 0x0f; |
buffer[7] = (num < 0x0a) ? ('0' + num) : ('a' + num); |
} |
if(buffer[0] == FAT16_DIRENTRY_DELETED) |
buffer[0] = 0x05; |
/* fill directory entry buffer */ |
memset(&buffer[11], 0, sizeof(buffer) - 11); |
buffer[0x0b] = dir_entry->attributes; |
#if FAT16_DATETIME_SUPPORT |
buffer[0x16] = (dir_entry->modification_time >> 0) & 0xff; |
buffer[0x17] = (dir_entry->modification_time >> 8) & 0xff; |
buffer[0x18] = (dir_entry->modification_date >> 0) & 0xff; |
buffer[0x19] = (dir_entry->modification_date >> 8) & 0xff; |
#endif |
buffer[0x1a] = (dir_entry->cluster >> 0) & 0xff; |
buffer[0x1b] = (dir_entry->cluster >> 8) & 0xff; |
buffer[0x1c] = (dir_entry->file_size >> 0) & 0xff; |
buffer[0x1d] = (dir_entry->file_size >> 8) & 0xff; |
buffer[0x1e] = (dir_entry->file_size >> 16) & 0xff; |
buffer[0x1f] = (dir_entry->file_size >> 24) & 0xff; |
/* write to disk */ |
if(!device_write(offset + (uint32_t) lfn_entry_count * 32, buffer, sizeof(buffer))) |
return 0; |
/* calculate checksum of 8.3 name */ |
uint8_t checksum = buffer[0]; |
for(uint8_t i = 1; i < 11; ++i) |
checksum = ((checksum >> 1) | (checksum << 7)) + buffer[i]; |
/* write lfn entries */ |
for(uint8_t lfn_entry = lfn_entry_count; lfn_entry > 0; --lfn_entry) |
{ |
memset(buffer, 0xff, sizeof(buffer)); |
/* set file name */ |
const char* long_name_curr = name + (lfn_entry - 1) * 13; |
uint8_t i = 1; |
while(i < 0x1f) |
{ |
buffer[i++] = *long_name_curr; |
buffer[i++] = 0; |
switch(i) |
{ |
case 0x0b: |
i = 0x0e; |
break; |
case 0x1a: |
i = 0x1c; |
break; |
} |
if(!*long_name_curr++) |
break; |
} |
/* set index of lfn entry */ |
buffer[0x00] = lfn_entry; |
if(lfn_entry == lfn_entry_count) |
buffer[0x00] |= FAT16_DIRENTRY_LFNLAST; |
/* mark as lfn entry */ |
buffer[0x0b] = 0x0f; |
/* set 8.3 checksum */ |
buffer[0x0d] = checksum; |
/* clear reserved bytes */ |
buffer[0x0c] = 0; |
buffer[0x1a] = 0; |
buffer[0x1b] = 0; |
/* write entry */ |
device_write(offset, buffer, sizeof(buffer)); |
offset += sizeof(buffer); |
} |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_file |
* Creates a file. |
* |
* Creates a file and obtains the directory entry of the |
* new file. If the file to create already exists, the |
* directory entry of the existing file will be returned |
* within the dir_entry parameter. |
* |
* \note The file name is not checked for invalid characters. |
* |
* \note The generation of the short 8.3 file name is quite |
* simple. The first eight characters are used for the filename. |
* The extension, if any, is made up of the first three characters |
* following the last dot within the long filename. If the |
* filename (without the extension) is longer than eight characters, |
* the lower byte of the cluster number replaces the last two |
* characters to avoid name clashes. In any other case, it is your |
* responsibility to avoid name clashes. |
* |
* \param[in] parent The handle of the directory in which to create the file. |
* \param[in] file The name of the file to create. |
* \param[out] dir_entry The directory entry to fill for the new file. |
* \returns 0 on failure, 1 on success. |
* \see fat16_delete_file |
*/ |
uint8_t fat16_create_file(struct fat16_dir_struct* parent, const char* file, struct fat16_dir_entry_struct* dir_entry) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!parent || !file || !file[0] || !dir_entry) |
return 0; |
/* check if the file already exists */ |
while(1) |
{ |
if(!fat16_read_dir(parent, dir_entry)) |
break; |
if(strcmp(file, dir_entry->long_name) == 0) |
{ |
fat16_reset_dir(parent); |
return 0; |
} |
} |
struct fat16_fs_struct* fs = parent->fs; |
/* prepare directory entry with values already known */ |
memset(dir_entry, 0, sizeof(*dir_entry)); |
strncpy(dir_entry->long_name, file, sizeof(dir_entry->long_name) - 1); |
/* find place where to store directory entry */ |
if(!(dir_entry->entry_offset = fat16_find_offset_for_dir_entry(fs, parent, dir_entry))) |
return 0; |
/* write directory entry to disk */ |
if(!fat16_write_dir_entry(fs, dir_entry)) |
return 0; |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_file |
* Deletes a file or directory. |
* |
* If a directory is deleted without first deleting its |
* subdirectories and files, disk space occupied by these |
* files will get wasted as there is no chance to release |
* it and mark it as free. |
* |
* \param[in] fs The filesystem on which to operate. |
* \param[in] dir_entry The directory entry of the file to delete. |
* \returns 0 on failure, 1 on success. |
* \see fat16_create_file |
*/ |
uint8_t fat16_delete_file(struct fat16_fs_struct* fs, struct fat16_dir_entry_struct* dir_entry) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!fs || !dir_entry) |
return 0; |
/* get offset of the file's directory entry */ |
uint32_t dir_entry_offset = dir_entry->entry_offset; |
if(!dir_entry_offset) |
return 0; |
uint8_t buffer[12]; |
while(1) |
{ |
/* read directory entry */ |
if(!fs->partition->device_read(dir_entry_offset, buffer, sizeof(buffer))) |
return 0; |
/* mark the directory entry as deleted */ |
buffer[0] = FAT16_DIRENTRY_DELETED; |
/* write back entry */ |
if(!fs->partition->device_write(dir_entry_offset, buffer, sizeof(buffer))) |
return 0; |
/* check if we deleted the whole entry */ |
if(buffer[11] != 0x0f) |
break; |
dir_entry_offset += 32; |
} |
/* We deleted the directory entry. The next thing to do is |
* marking all occupied clusters as free. |
*/ |
return (dir_entry->cluster == 0 || fat16_free_clusters(fs, dir_entry->cluster)); |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_dir |
* Creates a directory. |
* |
* Creates a directory and obtains its directory entry. |
* If the directory to create already exists, its |
* directory entry will be returned within the dir_entry |
* parameter. |
* |
* \note The notes which apply to fat16_create_file also |
* apply to this function. |
* |
* \param[in] parent The handle of the parent directory of the new directory. |
* \param[in] dir The name of the directory to create. |
* \param[out] dir_entry The directory entry to fill for the new directory. |
* \returns 0 on failure, 1 on success. |
* \see fat16_delete_dir |
*/ |
uint8_t fat16_create_dir(struct fat16_dir_struct* parent, const char* dir, struct fat16_dir_entry_struct* dir_entry) |
{ |
#if FAT16_WRITE_SUPPORT |
if(!parent || !dir || !dir[0] || !dir_entry) |
return 0; |
/* check if the file or directory already exists */ |
while(1) |
{ |
if(!fat16_read_dir(parent, dir_entry)) |
break; |
if(strcmp(dir, dir_entry->long_name) == 0) |
{ |
fat16_reset_dir(parent); |
return 0; |
} |
} |
struct fat16_fs_struct* fs = parent->fs; |
/* allocate cluster which will hold directory entries */ |
uint16_t dir_cluster = fat16_append_clusters(fs, 0, 1); |
if(!dir_cluster) |
return 0; |
/* clear cluster to prevent bogus directory entries */ |
fat16_clear_cluster(fs, dir_cluster); |
memset(dir_entry, 0, sizeof(*dir_entry)); |
dir_entry->attributes = FAT16_ATTRIB_DIR; |
/* create "." directory self reference */ |
dir_entry->entry_offset = fs->header.cluster_zero_offset + |
(uint32_t) (dir_cluster - 2) * fs->header.cluster_size; |
dir_entry->long_name[0] = '.'; |
dir_entry->cluster = dir_cluster; |
if(!fat16_write_dir_entry(fs, dir_entry)) |
{ |
fat16_free_clusters(fs, dir_cluster); |
return 0; |
} |
/* create ".." parent directory reference */ |
dir_entry->entry_offset += 32; |
dir_entry->long_name[1] = '.'; |
dir_entry->cluster = parent->dir_entry.cluster; |
if(!fat16_write_dir_entry(fs, dir_entry)) |
{ |
fat16_free_clusters(fs, dir_cluster); |
return 0; |
} |
/* fill directory entry */ |
strncpy(dir_entry->long_name, dir, sizeof(dir_entry->long_name) - 1); |
dir_entry->cluster = dir_cluster; |
/* find place where to store directory entry */ |
if(!(dir_entry->entry_offset = fat16_find_offset_for_dir_entry(fs, parent, dir_entry))) |
{ |
fat16_free_clusters(fs, dir_cluster); |
return 0; |
} |
/* write directory to disk */ |
if(!fat16_write_dir_entry(fs, dir_entry)) |
{ |
fat16_free_clusters(fs, dir_cluster); |
return 0; |
} |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup fat16_dir |
* Deletes a directory. |
* |
* This is just a synonym for fat16_delete_file(). |
* If a directory is deleted without first deleting its |
* subdirectories and files, disk space occupied by these |
* files will get wasted as there is no chance to release |
* it and mark it as free. |
* |
* \param[in] fs The filesystem on which to operate. |
* \param[in] dir_entry The directory entry of the directory to delete. |
* \returns 0 on failure, 1 on success. |
* \see fat16_create_dir |
*/ |
#ifdef DOXYGEN |
uint8_t fat16_delete_dir(struct fat16_fs_struct* fs, struct fat16_dir_entry_struct* dir_entry); |
#endif |
/** |
* \ingroup fat16_file |
* Returns the modification date of a file. |
* |
* \param[in] dir_entry The directory entry of which to return the modification date. |
* \param[out] year The year the file was last modified. |
* \param[out] month The month the file was last modified. |
* \param[out] day The day the file was last modified. |
*/ |
void fat16_get_file_modification_date(const struct fat16_dir_entry_struct* dir_entry, uint16_t* year, uint8_t* month, uint8_t* day) |
{ |
#if FAT16_DATETIME_SUPPORT |
if(!dir_entry) |
return; |
*year = 1980 + ((dir_entry->modification_date >> 9) & 0x7f); |
*month = (dir_entry->modification_date >> 5) & 0x0f; |
*day = (dir_entry->modification_date >> 0) & 0x1f; |
#endif |
} |
/** |
* \ingroup fat16_file |
* Returns the modification time of a file. |
* |
* \param[in] dir_entry The directory entry of which to return the modification time. |
* \param[out] hour The hour the file was last modified. |
* \param[out] min The min the file was last modified. |
* \param[out] sec The sec the file was last modified. |
*/ |
void fat16_get_file_modification_time(const struct fat16_dir_entry_struct* dir_entry, uint8_t* hour, uint8_t* min, uint8_t* sec) |
{ |
#if FAT16_DATETIME_SUPPORT |
if(!dir_entry) |
return; |
*hour = (dir_entry->modification_time >> 11) & 0x1f; |
*min = (dir_entry->modification_time >> 5) & 0x3f; |
*sec = ((dir_entry->modification_time >> 0) & 0x1f) * 2; |
#endif |
} |
/** |
* \ingroup fat16_file |
* Sets the modification time of a date. |
* |
* \param[in] dir_entry The directory entry for which to set the modification date. |
* \param[in] year The year the file was last modified. |
* \param[in] month The month the file was last modified. |
* \param[in] day The day the file was last modified. |
*/ |
void fat16_set_file_modification_date(struct fat16_dir_entry_struct* dir_entry, uint16_t year, uint8_t month, uint8_t day) |
{ |
#if FAT16_WRITE_SUPPORT |
#if FAT16_DATETIME_SUPPORT |
if(!dir_entry) |
return; |
dir_entry->modification_date = |
((year - 1980) << 9) | |
((uint16_t) month << 5) | |
((uint16_t) day << 0); |
#endif |
#endif |
} |
/** |
* \ingroup fat16_file |
* Sets the modification time of a file. |
* |
* \param[in] dir_entry The directory entry for which to set the modification time. |
* \param[in] hour The year the file was last modified. |
* \param[in] min The month the file was last modified. |
* \param[in] sec The day the file was last modified. |
*/ |
void fat16_set_file_modification_time(struct fat16_dir_entry_struct* dir_entry, uint8_t hour, uint8_t min, uint8_t sec) |
{ |
#if FAT16_WRITE_SUPPORT |
#if FAT16_DATETIME_SUPPORT |
if(!dir_entry) |
return; |
dir_entry->modification_time = |
((uint16_t) hour << 11) | |
((uint16_t) min << 5) | |
((uint16_t) sec >> 1) ; |
#endif |
#endif |
} |
/** |
* \ingroup fat16_fs |
* Returns the amount of total storage capacity of the filesystem in bytes. |
* |
* \param[in] fs The filesystem on which to operate. |
* \returns 0 on failure, the filesystem size in bytes otherwise. |
*/ |
uint32_t fat16_get_fs_size(const struct fat16_fs_struct* fs) |
{ |
if(!fs) |
return 0; |
return (fs->header.fat_size / 2 - 2) * fs->header.cluster_size; |
} |
/** |
* \ingroup fat16_fs |
* Returns the amount of free storage capacity on the filesystem in bytes. |
* |
* \note As the FAT16 filesystem is cluster based, this function does not |
* return continuous values but multiples of the cluster size. |
* |
* \param[in] fs The filesystem on which to operate. |
* \returns 0 on failure, the free filesystem space in bytes otherwise. |
*/ |
uint32_t fat16_get_fs_free(const struct fat16_fs_struct* fs) |
{ |
if(!fs) |
return 0; |
uint8_t fat[32]; |
struct fat16_usage_count_callback_arg count_arg; |
count_arg.cluster_count = 0; |
count_arg.buffer_size = sizeof(fat); |
uint32_t fat_offset = fs->header.fat_offset; |
uint32_t fat_size = fs->header.fat_size; |
while(fat_size > 0) |
{ |
uint16_t length = UINT16_MAX - 1; |
if(fat_size < length) |
length = fat_size; |
if(!fs->partition->device_read_interval(fat_offset, |
fat, |
sizeof(fat), |
length, |
fat16_get_fs_free_callback, |
&count_arg |
) |
) |
return 0; |
fat_offset += length; |
fat_size -= length; |
} |
return (uint32_t) count_arg.cluster_count * fs->header.cluster_size; |
} |
/** |
* \ingroup fat16_fs |
* Callback function used for counting free clusters. |
*/ |
uint8_t fat16_get_fs_free_callback(uint8_t* buffer, uint32_t offset, void* p) |
{ |
struct fat16_usage_count_callback_arg* count_arg = (struct fat16_usage_count_callback_arg*) p; |
uint8_t buffer_size = count_arg->buffer_size; |
for(uint8_t i = 0; i < buffer_size; i += 2) |
{ |
if((((uint16_t) buffer[1] << 8) | ((uint16_t) buffer[0] << 0)) == FAT16_CLUSTER_FREE) |
++(count_arg->cluster_count); |
buffer += 2; |
} |
return 1; |
} |
/Designs/Data_loggers/GPSRL02A/SW/logger/fat16.h |
---|
0,0 → 1,121 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* This file is free software; you can redistribute it and/or modify |
* it under the terms of either the GNU General Public License version 2 |
* or the GNU Lesser General Public License version 2.1, both as |
* published by the Free Software Foundation. |
*/ |
#ifndef FAT16_H |
#define FAT16_H |
#include "fat16_config.h" |
#include <stdint.h> |
/** |
* \addtogroup fat16 |
* |
* @{ |
*/ |
/** |
* \file |
* FAT16 header (license: GPLv2 or LGPLv2.1) |
* |
* \author Roland Riegel |
*/ |
/** |
* \addtogroup fat16_file |
* @{ |
*/ |
/** The file is read-only. */ |
#define FAT16_ATTRIB_READONLY (1 << 0) |
/** The file is hidden. */ |
#define FAT16_ATTRIB_HIDDEN (1 << 1) |
/** The file is a system file. */ |
#define FAT16_ATTRIB_SYSTEM (1 << 2) |
/** The file is empty and has the volume label as its name. */ |
#define FAT16_ATTRIB_VOLUME (1 << 3) |
/** The file is a directory. */ |
#define FAT16_ATTRIB_DIR (1 << 4) |
/** The file has to be archived. */ |
#define FAT16_ATTRIB_ARCHIVE (1 << 5) |
/** The given offset is relative to the beginning of the file. */ |
#define FAT16_SEEK_SET 0 |
/** The given offset is relative to the current read/write position. */ |
#define FAT16_SEEK_CUR 1 |
/** The given offset is relative to the end of the file. */ |
#define FAT16_SEEK_END 2 |
/** |
* @} |
*/ |
struct partition_struct; |
struct fat16_fs_struct; |
struct fat16_file_struct; |
struct fat16_dir_struct; |
/** |
* \ingroup fat16_file |
* Describes a directory entry. |
*/ |
struct fat16_dir_entry_struct |
{ |
/** The file's name, truncated to 31 characters. */ |
char long_name[32]; |
/** The file's attributes. Mask of the FAT16_ATTRIB_* constants. */ |
uint8_t attributes; |
#if FAT16_DATETIME_SUPPORT |
/** Compressed representation of modification time. */ |
uint16_t modification_time; |
/** Compressed representation of modification date. */ |
uint16_t modification_date; |
#endif |
/** The cluster in which the file's first byte resides. */ |
uint16_t cluster; |
/** The file's size. */ |
uint32_t file_size; |
/** The total disk offset of this directory entry. */ |
uint32_t entry_offset; |
}; |
struct fat16_fs_struct* fat16_open(struct partition_struct* partition); |
void fat16_close(struct fat16_fs_struct* fs); |
struct fat16_file_struct* fat16_open_file(struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry); |
void fat16_close_file(struct fat16_file_struct* fd); |
int16_t fat16_read_file(struct fat16_file_struct* fd, uint8_t* buffer, uint16_t buffer_len); |
int16_t fat16_write_file(struct fat16_file_struct* fd, const uint8_t* buffer, uint16_t buffer_len); |
uint8_t fat16_seek_file(struct fat16_file_struct* fd, int32_t* offset, uint8_t whence); |
uint8_t fat16_resize_file(struct fat16_file_struct* fd, uint32_t size); |
struct fat16_dir_struct* fat16_open_dir(struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry); |
void fat16_close_dir(struct fat16_dir_struct* dd); |
uint8_t fat16_read_dir(struct fat16_dir_struct* dd, struct fat16_dir_entry_struct* dir_entry); |
uint8_t fat16_reset_dir(struct fat16_dir_struct* dd); |
uint8_t fat16_create_file(struct fat16_dir_struct* parent, const char* file, struct fat16_dir_entry_struct* dir_entry); |
uint8_t fat16_delete_file(struct fat16_fs_struct* fs, struct fat16_dir_entry_struct* dir_entry); |
uint8_t fat16_create_dir(struct fat16_dir_struct* parent, const char* dir, struct fat16_dir_entry_struct* dir_entry); |
#define fat16_delete_dir fat16_delete_file |
void fat16_get_file_modification_date(const struct fat16_dir_entry_struct* dir_entry, uint16_t* year, uint8_t* month, uint8_t* day); |
void fat16_get_file_modification_time(const struct fat16_dir_entry_struct* dir_entry, uint8_t* hour, uint8_t* min, uint8_t* sec); |
uint8_t fat16_get_dir_entry_of_path(struct fat16_fs_struct* fs, const char* path, struct fat16_dir_entry_struct* dir_entry); |
uint32_t fat16_get_fs_size(const struct fat16_fs_struct* fs); |
uint32_t fat16_get_fs_free(const struct fat16_fs_struct* fs); |
/** |
* @} |
*/ |
#endif |
/Designs/Data_loggers/GPSRL02A/SW/logger/fat16_config.h |
---|
0,0 → 1,84 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* This file is free software; you can redistribute it and/or modify |
* it under the terms of either the GNU General Public License version 2 |
* or the GNU Lesser General Public License version 2.1, both as |
* published by the Free Software Foundation. |
*/ |
#ifndef FAT16_CONFIG_H |
#define FAT16_CONFIG_G |
/** |
* \addtogroup fat16 |
* |
* @{ |
*/ |
/** |
* \file |
* FAT16 configuration (license: GPLv2 or LGPLv2.1) |
*/ |
/** |
* \ingroup fat16_config |
* Controls FAT16 write support. |
* |
* Set to 1 to enable FAT16 write support, set to 0 to disable it. |
*/ |
#define FAT16_WRITE_SUPPORT 1 |
/** |
* \ingroup fat16_config |
* Controls FAT16 date and time support. |
* |
* Set to 1 to enable FAT16 date and time stamping support. |
*/ |
#define FAT16_DATETIME_SUPPORT 0 |
/** |
* \ingroup fat16_config |
* Determines the function used for retrieving current date and time. |
* |
* Define this to the function call which shall be used to retrieve |
* current date and time. |
* |
* \note Used only when FAT16_DATETIME_SUPPORT is 1. |
* |
* \param[out] year Pointer to a \c uint16_t which receives the current year. |
* \param[out] month Pointer to a \c uint8_t which receives the current month. |
* \param[out] day Pointer to a \c uint8_t which receives the current day. |
* \param[out] hour Pointer to a \c uint8_t which receives the current hour. |
* \param[out] min Pointer to a \c uint8_t which receives the current minute. |
* \param[out] sec Pointer to a \c uint8_t which receives the current sec. |
*/ |
#define fat16_get_datetime(year, month, day, hour, min, sec) \ |
get_datetime(year, month, day, hour, min, sec) |
/* forward declaration for the above */ |
void get_datetime(uint16_t* year, uint8_t* month, uint8_t* day, uint8_t* hour, uint8_t* min, uint8_t* sec); |
/** |
* \ingroup fat16_config |
* Maximum number of filesystem handles. |
*/ |
#define FAT16_FS_COUNT 1 |
/** |
* \ingroup fat16_config |
* Maximum number of file handles. |
*/ |
#define FAT16_FILE_COUNT 1 |
/** |
* \ingroup fat16_config |
* Maximum number of directory handles. |
*/ |
#define FAT16_DIR_COUNT 2 |
/** |
* @} |
*/ |
#endif |
/Designs/Data_loggers/GPSRL02A/SW/logger/main.c |
---|
0,0 → 1,475 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* This file is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License version 2 as |
* published by the Free Software Foundation. |
*/ |
#include <string.h> |
#include <avr/pgmspace.h> |
#include <avr/sleep.h> |
#include "fat16.h" |
#include "fat16_config.h" |
#include "partition.h" |
#include "sd_raw.h" |
#include "sd_raw_config.h" |
#include "uart.h" |
#define DEBUG 1 |
static uint8_t read_line(char* buffer, uint8_t buffer_length); |
static uint32_t strtolong(const char* str); |
static uint8_t find_file_in_dir(struct fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name, struct fat16_dir_entry_struct* dir_entry); |
static struct fat16_file_struct* open_file_in_dir(struct fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name); |
static uint8_t print_disk_info(const struct fat16_fs_struct* fs); |
int main() |
{ |
/* we will just use ordinary idle mode */ |
set_sleep_mode(SLEEP_MODE_IDLE); |
/* setup uart */ |
uart_init(); |
/* setup sd card slot */ |
if(!sd_raw_init()) |
{ |
#if DEBUG |
uart_puts_p(PSTR("MMC/SD initialization failed\n")); |
#endif |
return 1; |
} |
/* open first partition */ |
struct partition_struct* partition = partition_open(sd_raw_read, |
sd_raw_read_interval, |
sd_raw_write, |
sd_raw_write_interval, |
0 |
); |
if(!partition) |
{ |
/* If the partition did not open, assume the storage device |
* is a "superfloppy", i.e. has no MBR. |
*/ |
partition = partition_open(sd_raw_read, |
sd_raw_read_interval, |
sd_raw_write, |
sd_raw_write_interval, |
-1 |
); |
if(!partition) |
{ |
#if DEBUG |
uart_puts_p(PSTR("opening partition failed\n")); |
#endif |
return 1; |
} |
} |
/* open file system */ |
struct fat16_fs_struct* fs = fat16_open(partition); |
if(!fs) |
{ |
#if DEBUG |
uart_puts_p(PSTR("opening filesystem failed\n")); |
#endif |
return 1; |
} |
/* open root directory */ |
struct fat16_dir_entry_struct directory; |
fat16_get_dir_entry_of_path(fs, "/", &directory); |
struct fat16_dir_struct* dd = fat16_open_dir(fs, &directory); |
if(!dd) |
{ |
#if DEBUG |
uart_puts_p(PSTR("opening root directory failed\n")); |
#endif |
return 1; |
} |
/* print some card information as a boot message */ |
print_disk_info(fs); |
/* provide a simple shell */ |
char buffer[20]; |
char* command = buffer; |
//!!!KAKL |
{ |
uint8_t n; |
while(uart_getc()!='$'); |
while(uart_getc()!=','); |
for(n=0; n<6; n++) |
{ |
buffer[n]=uart_getc(); |
}; |
buffer[6]='\0'; |
} |
{ |
struct fat16_dir_entry_struct file_entry; |
fat16_create_file(dd, command, &file_entry); |
} |
{ |
int32_t offset; |
offset = 0; |
while(1) |
{ |
uint8_t znak; |
struct fat16_file_struct* fd = open_file_in_dir(fs, dd, command); |
fat16_seek_file(fd, &offset, FAT16_SEEK_SET); |
do |
{ |
znak=uart_getc(); |
fat16_write_file(fd, (uint8_t*) &znak, 1); |
uart_putc(znak); |
offset++; |
} while ((znak!='\n')&&(znak!='@')); |
fat16_close_file(fd); |
if(znak=='@') break; |
} |
} |
while(1) |
{ |
/* print prompt */ |
uart_putc('>'); |
uart_putc(' '); |
/* read command */ |
if(read_line(command, sizeof(buffer)) < 1) |
continue; |
/* execute command */ |
if(strncmp_P(command, PSTR("cd "), 3) == 0) |
{ |
command += 3; |
if(command[0] == '\0') |
continue; |
/* change directory */ |
struct fat16_dir_entry_struct subdir_entry; |
if(find_file_in_dir(fs, dd, command, &subdir_entry)) |
{ |
struct fat16_dir_struct* dd_new = fat16_open_dir(fs, &subdir_entry); |
if(dd_new) |
{ |
fat16_close_dir(dd); |
dd = dd_new; |
continue; |
} |
} |
uart_puts_p(PSTR("directory not found: ")); |
uart_puts(command); |
uart_putc('\n'); |
} |
else if(strcmp_P(command, PSTR("ls")) == 0) |
{ |
/* print directory listing */ |
struct fat16_dir_entry_struct dir_entry; |
while(fat16_read_dir(dd, &dir_entry)) |
{ |
uint8_t spaces = sizeof(dir_entry.long_name) - strlen(dir_entry.long_name) + 4; |
uart_puts(dir_entry.long_name); |
uart_putc(dir_entry.attributes & FAT16_ATTRIB_DIR ? '/' : ' '); |
while(spaces--) |
uart_putc(' '); |
uart_putdw_dec(dir_entry.file_size); |
uart_putc('\n'); |
} |
} |
else if(strncmp_P(command, PSTR("cat "), 4) == 0) |
{ |
command += 4; |
if(command[0] == '\0') |
continue; |
/* search file in current directory and open it */ |
struct fat16_file_struct* fd = open_file_in_dir(fs, dd, command); |
if(!fd) |
{ |
uart_puts_p(PSTR("error opening ")); |
uart_puts(command); |
uart_putc('\n'); |
continue; |
} |
/* print file contents */ |
uint8_t buffer[8]; |
uint32_t offset = 0; |
while(fat16_read_file(fd, buffer, sizeof(buffer)) > 0) |
{ |
uart_putdw_hex(offset); |
uart_putc(':'); |
for(uint8_t i = 0; i < 8; ++i) |
{ |
uart_putc(' '); |
uart_putc_hex(buffer[i]); |
} |
uart_putc('\n'); |
offset += 8; |
} |
fat16_close_file(fd); |
} |
else if(strcmp_P(command, PSTR("disk")) == 0) |
{ |
if(!print_disk_info(fs)) |
uart_puts_p(PSTR("error reading disk info\n")); |
} |
#if FAT16_WRITE_SUPPORT |
else if(strncmp_P(command, PSTR("rm "), 3) == 0) |
{ |
command += 3; |
if(command[0] == '\0') |
continue; |
struct fat16_dir_entry_struct file_entry; |
if(find_file_in_dir(fs, dd, command, &file_entry)) |
{ |
if(fat16_delete_file(fs, &file_entry)) |
continue; |
} |
uart_puts_p(PSTR("error deleting file: ")); |
uart_puts(command); |
uart_putc('\n'); |
} |
else if(strncmp_P(command, PSTR("touch "), 6) == 0) |
{ |
command += 6; |
if(command[0] == '\0') |
continue; |
struct fat16_dir_entry_struct file_entry; |
if(!fat16_create_file(dd, command, &file_entry)) |
{ |
uart_puts_p(PSTR("error creating file: ")); |
uart_puts(command); |
uart_putc('\n'); |
} |
} |
else if(strncmp_P(command, PSTR("write "), 6) == 0) |
{ |
command += 6; |
if(command[0] == '\0') |
continue; |
char* offset_value = command; |
while(*offset_value != ' ' && *offset_value != '\0') |
++offset_value; |
if(*offset_value == ' ') |
*offset_value++ = '\0'; |
else |
continue; |
/* search file in current directory and open it */ |
struct fat16_file_struct* fd = open_file_in_dir(fs, dd, command); |
if(!fd) |
{ |
uart_puts_p(PSTR("error opening ")); |
uart_puts(command); |
uart_putc('\n'); |
continue; |
} |
int32_t offset = strtolong(offset_value); |
if(!fat16_seek_file(fd, &offset, FAT16_SEEK_SET)) |
{ |
uart_puts_p(PSTR("error seeking on ")); |
uart_puts(command); |
uart_putc('\n'); |
fat16_close_file(fd); |
continue; |
} |
/* read text from the shell and write it to the file */ |
uint8_t data_len; |
while(1) |
{ |
/* give a different prompt */ |
uart_putc('<'); |
uart_putc(' '); |
/* read one line of text */ |
data_len = read_line(buffer, sizeof(buffer)); |
if(!data_len) |
break; |
/* write text to file */ |
if(fat16_write_file(fd, (uint8_t*) buffer, data_len) != data_len) |
{ |
uart_puts_p(PSTR("error writing to file\n")); |
break; |
} |
} |
fat16_close_file(fd); |
} |
else if(strncmp_P(command, PSTR("mkdir "), 6) == 0) |
{ |
command += 6; |
if(command[0] == '\0') |
continue; |
struct fat16_dir_entry_struct dir_entry; |
if(!fat16_create_dir(dd, command, &dir_entry)) |
{ |
uart_puts_p(PSTR("error creating directory: ")); |
uart_puts(command); |
uart_putc('\n'); |
} |
} |
#endif |
#if SD_RAW_WRITE_BUFFERING |
else if(strcmp_P(command, PSTR("sync")) == 0) |
{ |
if(!sd_raw_sync()) |
uart_puts_p(PSTR("error syncing disk\n")); |
} |
#endif |
else |
{ |
uart_puts_p(PSTR("unknown command: ")); |
uart_puts(command); |
uart_putc('\n'); |
} |
} |
/* close file system */ |
fat16_close(fs); |
/* close partition */ |
partition_close(partition); |
return 0; |
} |
uint8_t read_line(char* buffer, uint8_t buffer_length) |
{ |
memset(buffer, 0, buffer_length); |
uint8_t read_length = 0; |
while(read_length < buffer_length - 1) |
{ |
uint8_t c = uart_getc(); |
if(c == 0x08 || c == 0x7f) |
{ |
if(read_length < 1) |
continue; |
--read_length; |
buffer[read_length] = '\0'; |
uart_putc(0x08); |
uart_putc(' '); |
uart_putc(0x08); |
continue; |
} |
uart_putc(c); |
if(c == '\n') |
{ |
buffer[read_length] = '\0'; |
break; |
} |
else |
{ |
buffer[read_length] = c; |
++read_length; |
} |
} |
return read_length; |
} |
uint32_t strtolong(const char* str) |
{ |
uint32_t l = 0; |
while(*str >= '0' && *str <= '9') |
l = l * 10 + (*str++ - '0'); |
return l; |
} |
uint8_t find_file_in_dir(struct fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name, struct fat16_dir_entry_struct* dir_entry) |
{ |
while(fat16_read_dir(dd, dir_entry)) |
{ |
if(strcmp(dir_entry->long_name, name) == 0) |
{ |
fat16_reset_dir(dd); |
return 1; |
} |
} |
return 0; |
} |
struct fat16_file_struct* open_file_in_dir(struct fat16_fs_struct* fs, struct fat16_dir_struct* dd, const char* name) |
{ |
struct fat16_dir_entry_struct file_entry; |
if(!find_file_in_dir(fs, dd, name, &file_entry)) |
return 0; |
return fat16_open_file(fs, &file_entry); |
} |
uint8_t print_disk_info(const struct fat16_fs_struct* fs) |
{ |
if(!fs) |
return 0; |
struct sd_raw_info disk_info; |
if(!sd_raw_get_info(&disk_info)) |
return 0; |
uart_puts_p(PSTR("manuf: 0x")); uart_putc_hex(disk_info.manufacturer); uart_putc('\n'); |
uart_puts_p(PSTR("oem: ")); uart_puts((char*) disk_info.oem); uart_putc('\n'); |
uart_puts_p(PSTR("prod: ")); uart_puts((char*) disk_info.product); uart_putc('\n'); |
uart_puts_p(PSTR("rev: ")); uart_putc_hex(disk_info.revision); uart_putc('\n'); |
uart_puts_p(PSTR("serial: 0x")); uart_putdw_hex(disk_info.serial); uart_putc('\n'); |
uart_puts_p(PSTR("date: ")); uart_putw_dec(disk_info.manufacturing_month); uart_putc('/'); |
uart_putw_dec(disk_info.manufacturing_year); uart_putc('\n'); |
uart_puts_p(PSTR("size: ")); uart_putdw_dec(disk_info.capacity); uart_putc('\n'); |
uart_puts_p(PSTR("copy: ")); uart_putw_dec(disk_info.flag_copy); uart_putc('\n'); |
uart_puts_p(PSTR("wr.pr.: ")); uart_putw_dec(disk_info.flag_write_protect_temp); uart_putc('/'); |
uart_putw_dec(disk_info.flag_write_protect); uart_putc('\n'); |
uart_puts_p(PSTR("format: ")); uart_putw_dec(disk_info.format); uart_putc('\n'); |
uart_puts_p(PSTR("free: ")); uart_putdw_dec(fat16_get_fs_free(fs)); uart_putc('/'); |
uart_putdw_dec(fat16_get_fs_size(fs)); uart_putc('\n'); |
return 1; |
} |
void get_datetime(uint16_t* year, uint8_t* month, uint8_t* day, uint8_t* hour, uint8_t* min, uint8_t* sec) |
{ |
*year = 2007; |
*month = 1; |
*day = 1; |
*hour = 0; |
*min = 0; |
*sec = 0; |
} |
/Designs/Data_loggers/GPSRL02A/SW/logger/partition.c |
---|
0,0 → 1,159 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* This file is free software; you can redistribute it and/or modify |
* it under the terms of either the GNU General Public License version 2 |
* or the GNU Lesser General Public License version 2.1, both as |
* published by the Free Software Foundation. |
*/ |
#include "partition.h" |
#include "partition_config.h" |
#include "sd-reader_config.h" |
#include <string.h> |
#if USE_DYNAMIC_MEMORY |
#include <stdlib.h> |
#endif |
/** |
* \addtogroup partition Partition table support |
* |
* Support for reading partition tables and access to partitions. |
* |
* @{ |
*/ |
/** |
* \file |
* Partition table implementation (license: GPLv2 or LGPLv2.1) |
* |
* \author Roland Riegel |
*/ |
/** |
* \addtogroup partition_config Configuration of partition table support |
* Preprocessor defines to configure the partition support. |
*/ |
#if !USE_DYNAMIC_MEMORY |
static struct partition_struct partition_handles[PARTITION_COUNT]; |
#endif |
/** |
* Opens a partition. |
* |
* Opens a partition by its index number and returns a partition |
* handle which describes the opened partition. |
* |
* \note This function does not support extended partitions. |
* |
* \param[in] device_read A function pointer which is used to read from the disk. |
* \param[in] device_read_interval A function pointer which is used to read in constant intervals from the disk. |
* \param[in] device_write A function pointer which is used to write to the disk. |
* \param[in] device_write_interval A function pointer which is used to write a data stream to disk. |
* \param[in] index The index of the partition which should be opened, range 0 to 3. |
* A negative value is allowed as well. In this case, the partition opened is |
* not checked for existance, begins at offset zero, has a length of zero |
* and is of an unknown type. |
* \returns 0 on failure, a partition descriptor on success. |
* \see partition_close |
*/ |
struct partition_struct* partition_open(device_read_t device_read, device_read_interval_t device_read_interval, device_write_t device_write, device_write_interval_t device_write_interval, int8_t index) |
{ |
struct partition_struct* new_partition = 0; |
uint8_t buffer[0x10]; |
if(!device_read || !device_read_interval || index >= 4) |
return 0; |
if(index >= 0) |
{ |
/* read specified partition table index */ |
if(!device_read(0x01be + index * 0x10, buffer, sizeof(buffer))) |
return 0; |
/* abort on empty partition entry */ |
if(buffer[4] == 0x00) |
return 0; |
} |
/* allocate partition descriptor */ |
#if USE_DYNAMIC_MEMORY |
new_partition = malloc(sizeof(*new_partition)); |
if(!new_partition) |
return 0; |
#else |
new_partition = partition_handles; |
uint8_t i; |
for(i = 0; i < PARTITION_COUNT; ++i) |
{ |
if(new_partition->type == PARTITION_TYPE_FREE) |
break; |
++new_partition; |
} |
if(i >= PARTITION_COUNT) |
return 0; |
#endif |
memset(new_partition, 0, sizeof(*new_partition)); |
/* fill partition descriptor */ |
new_partition->device_read = device_read; |
new_partition->device_read_interval = device_read_interval; |
new_partition->device_write = device_write; |
new_partition->device_write_interval = device_write_interval; |
if(index >= 0) |
{ |
new_partition->type = buffer[4]; |
new_partition->offset = ((uint32_t) buffer[8]) | |
((uint32_t) buffer[9] << 8) | |
((uint32_t) buffer[10] << 16) | |
((uint32_t) buffer[11] << 24); |
new_partition->length = ((uint32_t) buffer[12]) | |
((uint32_t) buffer[13] << 8) | |
((uint32_t) buffer[14] << 16) | |
((uint32_t) buffer[15] << 24); |
} |
else |
{ |
new_partition->type = 0xff; |
} |
return new_partition; |
} |
/** |
* Closes a partition. |
* |
* This function destroys a partition descriptor which was |
* previously obtained from a call to partition_open(). |
* When this function returns, the given descriptor will be |
* invalid. |
* |
* \param[in] partition The partition descriptor to destroy. |
* \returns 0 on failure, 1 on success. |
* \see partition_open |
*/ |
uint8_t partition_close(struct partition_struct* partition) |
{ |
if(!partition) |
return 0; |
/* destroy partition descriptor */ |
#if USE_DYNAMIC_MEMORY |
free(partition); |
#else |
partition->type = PARTITION_TYPE_FREE; |
#endif |
return 1; |
} |
/** |
* @} |
*/ |
/Designs/Data_loggers/GPSRL02A/SW/logger/partition.h |
---|
0,0 → 1,201 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* This file is free software; you can redistribute it and/or modify |
* it under the terms of either the GNU General Public License version 2 |
* or the GNU Lesser General Public License version 2.1, both as |
* published by the Free Software Foundation. |
*/ |
#ifndef PARTITION_H |
#define PARTITION_H |
#include <stdint.h> |
/** |
* \addtogroup partition |
* |
* @{ |
*/ |
/** |
* \file |
* Partition table header (license: GPLv2 or LGPLv2.1) |
* |
* \author Roland Riegel |
*/ |
/** |
* The partition table entry is not used. |
*/ |
#define PARTITION_TYPE_FREE 0x00 |
/** |
* The partition contains a FAT12 filesystem. |
*/ |
#define PARTITION_TYPE_FAT12 0x01 |
/** |
* The partition contains a FAT16 filesystem with 32MB maximum. |
*/ |
#define PARTITION_TYPE_FAT16_32MB 0x04 |
/** |
* The partition is an extended partition with its own partition table. |
*/ |
#define PARTITION_TYPE_EXTENDED 0x05 |
/** |
* The partition contains a FAT16 filesystem. |
*/ |
#define PARTITION_TYPE_FAT16 0x06 |
/** |
* The partition contains a FAT32 filesystem. |
*/ |
#define PARTITION_TYPE_FAT32 0x0b |
/** |
* The partition contains a FAT32 filesystem with LBA. |
*/ |
#define PARTITION_TYPE_FAT32_LBA 0x0c |
/** |
* The partition contains a FAT16 filesystem with LBA. |
*/ |
#define PARTITION_TYPE_FAT16_LBA 0x0e |
/** |
* The partition is an extended partition with LBA. |
*/ |
#define PARTITION_TYPE_EXTENDED_LBA 0x0f |
/** |
* The partition has an unknown type. |
*/ |
#define PARTITION_TYPE_UNKNOWN 0xff |
/** |
* A function pointer used to read from the partition. |
* |
* \param[in] offset The offset on the device where to start reading. |
* \param[out] buffer The buffer into which to place the data. |
* \param[in] length The count of bytes to read. |
*/ |
typedef uint8_t (*device_read_t)(uint32_t offset, uint8_t* buffer, uint16_t length); |
/** |
* A function pointer passed to a \c device_read_interval_t. |
* |
* \param[in] buffer The buffer which contains the data just read. |
* \param[in] offset The offset from which the data in \c buffer was read. |
* \param[in] p An opaque pointer. |
* \see device_read_interval_t |
*/ |
typedef uint8_t (*device_read_callback_t)(uint8_t* buffer, uint32_t offset, void* p); |
/** |
* A function pointer used to continuously read units of \c interval bytes |
* and call a callback function. |
* |
* This function starts reading at the specified offset. Every \c interval bytes, |
* it calls the callback function with the associated data buffer. |
* |
* By returning zero, the callback may stop reading. |
* |
* \param[in] offset Offset from which to start reading. |
* \param[in] buffer Pointer to a buffer which is at least interval bytes in size. |
* \param[in] interval Number of bytes to read before calling the callback function. |
* \param[in] length Number of bytes to read altogether. |
* \param[in] callback The function to call every interval bytes. |
* \param[in] p An opaque pointer directly passed to the callback function. |
* \returns 0 on failure, 1 on success |
* \see device_read_t |
*/ |
typedef uint8_t (*device_read_interval_t)(uint32_t offset, uint8_t* buffer, uint16_t interval, uint16_t length, device_read_callback_t callback, void* p); |
/** |
* A function pointer used to write to the partition. |
* |
* \param[in] offset The offset on the device where to start writing. |
* \param[in] buffer The buffer which to write. |
* \param[in] length The count of bytes to write. |
*/ |
typedef uint8_t (*device_write_t)(uint32_t offset, const uint8_t* buffer, uint16_t length); |
/** |
* A function pointer passed to a \c device_write_interval_t. |
* |
* \param[in] buffer The buffer which receives the data to write. |
* \param[in] offset The offset to which the data in \c buffer will be written. |
* \param[in] p An opaque pointer. |
* \returns The number of bytes put into \c buffer |
* \see device_write_interval_t |
*/ |
typedef uint16_t (*device_write_callback_t)(uint8_t* buffer, uint32_t offset, void* p); |
/** |
* A function pointer used to continuously write a data stream obtained from |
* a callback function. |
* |
* This function starts writing at the specified offset. To obtain the |
* next bytes to write, it calls the callback function. The callback fills the |
* provided data buffer and returns the number of bytes it has put into the buffer. |
* |
* By returning zero, the callback may stop writing. |
* |
* \param[in] offset Offset where to start writing. |
* \param[in] buffer Pointer to a buffer which is used for the callback function. |
* \param[in] length Number of bytes to write in total. May be zero for endless writes. |
* \param[in] callback The function used to obtain the bytes to write. |
* \param[in] p An opaque pointer directly passed to the callback function. |
* \returns 0 on failure, 1 on success |
* \see device_write_t |
*/ |
typedef uint8_t (*device_write_interval_t)(uint32_t offset, uint8_t* buffer, uint16_t length, device_write_callback_t callback, void* p); |
/** |
* Describes a partition. |
*/ |
struct partition_struct |
{ |
/** |
* The function which reads data from the partition. |
* |
* \note The offset given to this function is relative to the whole disk, |
* not to the start of the partition. |
*/ |
device_read_t device_read; |
/** |
* The function which repeatedly reads a constant amount of data from the partition. |
* |
* \note The offset given to this function is relative to the whole disk, |
* not to the start of the partition. |
*/ |
device_read_interval_t device_read_interval; |
/** |
* The function which writes data to the partition. |
* |
* \note The offset given to this function is relative to the whole disk, |
* not to the start of the partition. |
*/ |
device_write_t device_write; |
/** |
* The function which repeatedly writes data to the partition. |
* |
* \note The offset given to this function is relative to the whole disk, |
* not to the start of the partition. |
*/ |
device_write_interval_t device_write_interval; |
/** |
* The type of the partition. |
* |
* Compare this value to the PARTITION_TYPE_* constants. |
*/ |
uint8_t type; |
/** |
* The offset in bytes on the disk where this partition starts. |
*/ |
uint32_t offset; |
/** |
* The length in bytes of this partition. |
*/ |
uint32_t length; |
}; |
struct partition_struct* partition_open(device_read_t device_read, device_read_interval_t device_read_interval, device_write_t device_write, device_write_interval_t device_write_interval, int8_t index); |
uint8_t partition_close(struct partition_struct* partition); |
/** |
* @} |
*/ |
#endif |
/Designs/Data_loggers/GPSRL02A/SW/logger/partition_config.h |
---|
0,0 → 1,35 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* This file is free software; you can redistribute it and/or modify |
* it under the terms of either the GNU General Public License version 2 |
* or the GNU Lesser General Public License version 2.1, both as |
* published by the Free Software Foundation. |
*/ |
#ifndef PARTITION_CONFIG_H |
#define PARTITION_CONFIG_G |
/** |
* \addtogroup partition |
* |
* @{ |
*/ |
/** |
* \file |
* Partition configuration (license: GPLv2 or LGPLv2.1) |
*/ |
/** |
* \ingroup partition_config |
* Maximum number of partition handles. |
*/ |
#define PARTITION_COUNT 1 |
/** |
* @} |
*/ |
#endif |
/Designs/Data_loggers/GPSRL02A/SW/logger/sd-reader.hex |
---|
0,0 → 1,899 |
:100000000C941D010C943A010C943A010C943A01A1 |
:100010000C943A010C943A010C943A010C943A0174 |
:100020000C943A010C943A010C943A010C943A0164 |
:100030000C943A010C943A010C943A010C943A0154 |
:100040000C943A010C943A010C94341B0C943A0130 |
:100050000C943A010C943A010C943A010C943A0134 |
:100060000C943A010C943A01756E6B6E6F776E20AA |
:10007000636F6D6D616E643A20006572726F7220FD |
:100080006372656174696E67206469726563746F19 |
:1000900072793A20006D6B64697220006572726F2C |
:1000A000722077726974696E6720746F2066696C5C |
:1000B000650A006572726F72207365656B696E67A1 |
:1000C000206F6E20006572726F72206F70656E69AE |
:1000D0006E672000777269746520006572726F72B6 |
:1000E000206372656174696E672066696C653A2089 |
:1000F00000746F75636820006572726F72206465AA |
:100100006C6574696E672066696C653A2000726D73 |
:1001100020006572726F722072656164696E67207B |
:100120006469736B20696E666F0A006469736B00A3 |
:100130006572726F72206F70656E696E6720006302 |
:10014000617420006C73006469726563746F727906 |
:10015000206E6F7420666F756E643A2000636420B1 |
:10016000006F70656E696E6720726F6F74206469CE |
:10017000726563746F7279206661696C65640A00E8 |
:100180006F70656E696E672066696C6573797374EC |
:10019000656D206661696C65640A006F70656E69E3 |
:1001A0006E6720706172746974696F6E2066616930 |
:1001B0006C65640A004D4D432F534420696E697489 |
:1001C00069616C697A6174696F6E206661696C65DA |
:1001D000640A00667265653A20202000666F726DC1 |
:1001E00061743A200077722E70722E3A2000636F8D |
:1001F00070793A2020200073697A653A2020200027 |
:10020000646174653A2020200073657269616C3AFC |
:10021000203078007265763A202020200070726FBE |
:10022000643A202020006F656D3A20202020006D68 |
:10023000616E75663A202030780011241FBECFEF22 |
:10024000D4E0DEBFCDBF11E0A0E0B1E0E2E0F8E332 |
:1002500002C005900D92A230B107D9F713E0A2E0D9 |
:10026000B1E001C01D92A23CB107E1F70E94B512B6 |
:100270000C94001C0C940000FC01892B11F01182DD |
:1002800010820895CF93DF93FC01D9018081853ED0 |
:1002900029F1882319F12D913C911197ED018A8163 |
:1002A0009B812817390799F44C835D836E837F8384 |
:1002B00083858F3011F080E205C080818295880FA0 |
:1002C000807E805EFD01808780E090E009C08385AC |
:1002D0008F3021F02F5F3F4F2D933C9381E090E0D2 |
:1002E000DF91CF910895EF92FF920F931F93CF93D9 |
:1002F000DF93EC017A018B01B9018881853E09F415 |
:10030000CCC0882309F4C9C0F90187A190A5A1A593 |
:10031000B2A50097A105B10521F4E7A2F0A601A7B7 |
:1003200012A76115710509F4B8C0209709F4B5C08A |
:100330009881992309F4B1C0AE01455F5F4F8B8569 |
:100340008F3099F5892F99278F7390702DE030E0C9 |
:10035000AC01429FC001439F900D529F900D11240C |
:100360009C012D5030400197809708F093C0FB010D |
:10037000E20FF31F898180838B8181838D8182834A |
:100380008F818383898584838E858583888986830D |
:100390008A8987838C8980878E898187888D8287E7 |
:1003A0008C8D83878E8D848775C0FB018081882327 |
:1003B000B9F580E090E0382FFE01E80FF91F2081A9 |
:1003C000203249F0FB01E80FF91F20833F5F0196BF |
:1003D0008830910581F7FB018081853011F485EE2D |
:1003E00080838885803211F4832F16C0FB01E30FD0 |
:1003F000F11D8EE28083832F8F5FDE01232F2C5F20 |
:10040000FD019085903241F0FB01E80FF11D9083D2 |
:100410008F5F11968217A1F7FB01E80FF11D108283 |
:10042000FA018081FB0180A38B8D9927982F882763 |
:100430002A8D3327822B932B92A381A32D8D3327D3 |
:1004400044275527542F432F322F22278E8D99274B |
:10045000AA27BB27DC0199278827282B392B4A2B71 |
:100460005B2B8C8D9927AA27BB27282B392B4A2B4E |
:100470005B2B8F8D9927AA27BB27B82FAA279927EF |
:100480008827282B392B4A2B5B2B23A334A345A386 |
:1004900056A303C081E090E002C080E090E0DF91CD |
:1004A000CF911F910F91FF90EF9008950F931F939D |
:1004B000CF93DF93CDB7DEB722970FB6F894DEBFA8 |
:1004C0000FBECDBFDC01892BA9F16230710590F11F |
:1004D0000D911C911197660F771F88279927FD01B1 |
:1004E0002681378140855185620F731F841F951FB8 |
:1004F000D801ED91FC9122E030E0AE014F5F5F4FFB |
:1005000009958823B9F08A819927382F2227898174 |
:100510009927282B392B2115310571F0BFEF273F83 |
:100520003B0741F0C9014096079720F0EFEF283FC5 |
:100530003E0710F020E030E0C90122960FB6F89493 |
:10054000DEBF0FBECDBFDF91CF911F910F910895F8 |
:100550004F925F926F927F928F929F92AF92BF92D3 |
:10056000CF92DF92EF92FF920F931F93CF93DF937F |
:10057000CDB7DEB722970FB6F894DEBF0FBECDBF62 |
:100580005C01009709F44BC06230710508F447C064 |
:10059000FC0166807780808491842E010894411C40 |
:1005A000511C660F771F6B01EE24FF24C60CD71C6D |
:1005B000E81CF91CD501ED91FC910190F081E02D32 |
:1005C00022E030E0A201C701B6010995882339F184 |
:1005D0008A819927182F002789819927082B192BA1 |
:1005E00001151105F9F0C80140960897C0F0BFEF5A |
:1005F000083F1B0710F000E010E019821A82D501B5 |
:10060000ED91FC910480F581E02D22E030E0A20123 |
:10061000C701B6010995B801012B21F0C2CF80E0D6 |
:1006200090E002C081E090E022960FB6F894DEBF21 |
:100630000FBECDBFDF91CF911F910F91FF90EF9033 |
:10064000DF90CF90BF90AF909F908F907F906F90F2 |
:100650005F904F9008952F923F924F925F926F92CA |
:100660007F928F929F92AF92BF92CF92DF92EF9242 |
:10067000FF920F931F93CF93DF93CDB7DEB72C97E5 |
:100680000FB6F894DEBF0FBECDBF3C012B011A019F |
:10069000009709F495C0DC01ED91FC912081318136 |
:1006A0003C872B870480F581E02DFA87E987FC01E0 |
:1006B00086819781A085B1858D839E83AF83B8871E |
:1006C00082859385A485B585B695A79597958795D9 |
:1006D0009C838B836A01AA24BB248824992444C068 |
:1006E000C401880F991F7C01002711272D813E81AD |
:1006F0004F815885E20EF31E041F151F22E030E0E3 |
:10070000AE014F5F5F4FC801B701AB85BC85FD01EE |
:100710000995882309F454C08981882311F58A81B9 |
:100720008823F9F4C214D30419F48FEF898303C02A |
:10073000A9828B2D99278A8322E030E0AE014F5F9A |
:100740005F4FC801B701E985FA850995882391F0C3 |
:100750000894C108D108C114D10411F454010CC08B |
:1007600054010894811C911C2B813C8182169306B4 |
:1007700009F0B6CFCD2801F532E04316510410F14F |
:10078000A9828B2D99278A83440C551CB201882796 |
:1007900099272D813E814F815885620F731F841FD9 |
:1007A000951F22E030E0AE014F5F5F4FA985BA850B |
:1007B000FD010995882331F4B501C3010E94A80207 |
:1007C000AA24BB24C5012C960FB6F894DEBF0FBE39 |
:1007D000CDBFDF91CF911F910F91FF90EF90DF90F0 |
:1007E000CF90BF90AF909F908F907F906F905F90D1 |
:1007F0004F903F902F900895CF92DF92EF92FF920B |
:100800000F931F93CF93DF93CDB7DEB760970FB6EB |
:10081000F894DEBF0FBECDBF7C016230710518F4C5 |
:1008200080E090E027C0FC01C088D1880081118160 |
:1008300062507040882799279601442755270E94C7 |
:10084000981B9B01AC01F70166897789808D918D9A |
:10085000620F731F841F951FF801A681B781EE24D4 |
:10086000FF240AEE16E09601AE014F5F5F4FFD01D7 |
:100870000995992760960FB6F894DEBF0FBECDBFDD |
:10088000DF91CF911F910F91FF90EF90DF90CF906C |
:100890000895FC01892B11F01182108208952F9286 |
:1008A0003F924F925F926F927F928F929F92AF9200 |
:1008B000BF92CF92DF92EF92FF920F931F93CF934D |
:1008C000DF93CDB7DEB72C970FB6F894DEBF0FBE1F |
:1008D000CDBF3C0178876F835A874987009709F419 |
:1008E000FCC0672B09F4F9C0452B09F4F6C0FC01E4 |
:1008F000A5A4B6A4C7A4D0A825A136A147A150A5F8 |
:1009000069857A85CB01AA27BB278A0D9B1DAC1D63 |
:10091000BD1D281739074A075B0738F42A193B0918 |
:100920003A872987232B09F4DBC0D3018D919C9151 |
:10093000FC01808991899A838983F30101A8F2A936 |
:10094000E02DFC87EB87BC01882799276B837C838C |
:100950008D839E83EF2BE1F5F30103A0F4A1E02D3D |
:10096000FC87EB87EF2B39F4A114B104C104D10447 |
:1009700009F4B6C0B2C0A114B104C104D10441F15C |
:10098000860175012B803C804D805E8050944094A0 |
:1009900030942094211C311C411C511C10C06B85CB |
:1009A0007C85D3018D919C910E9456029C878B87F8 |
:1009B000892B09F492C0E20CF31C041D151D6B81F8 |
:1009C0007C818D819E81E616F7060807190738F7A6 |
:1009D000C601B5012B813C814D815E810E94DE1BE9 |
:1009E0002B0189849A84D3018D919C91A980BA802E |
:1009F000A418B5088A149B0408F45401FC01C080B3 |
:100A0000D18072010027112786899789A08DB18D29 |
:100A1000E80EF91E0A1F1B1F2B853C852250304013 |
:100A2000B901882799272E5F3F4F3C872B872B8161 |
:100A30003C814D815E810E94981BE60EF71E081FC7 |
:100A4000191FD601CD90DC9095014F815885C801C2 |
:100A5000B701F6010995882339F18A189B08C50169 |
:100A6000AA27BB27F30125A536A547A550A9280F1E |
:100A7000391F4A1F5B1F25A736A747A750ABC501E3 |
:100A8000840D951D29813A8182179307A0F06B850B |
:100A90007C85808191810E9456029C878B87892B5F |
:100AA00041F4F30112AA11AA49855A854819590936 |
:100AB00019C0442455242B853C85F30132AB21AB6E |
:100AC0008114910439F06F8178856A0D7B1D7887D8 |
:100AD0006F8389CF49855A8505C04FEF5FEF02C00C |
:100AE00040E050E0CA012C960FB6F894DEBF0FBE6E |
:100AF000CDBFDF91CF911F910F91FF90EF90DF90CD |
:100B0000CF90BF90AF909F908F907F906F905F90AD |
:100B10004F903F902F900895FC01892B11F0118286 |
:100B200010820895FC01892B19F480E090E008956B |
:100B300016A615A681E090E008958F929F92AF923D |
:100B4000BF92CF92DF92EF92FF920F931F93CF93BA |
:100B5000DF93CDB7DEB72C970FB6F894DEBF0FBE8C |
:100B6000CDBF6C015B01892B09F452C06115710581 |
:100B700009F44EC0FB01E7A0F0A401A512A5E11401 |
:100B8000F1040105110509F443C04E010894811CCC |
:100B9000911CD601ED91FC910190F081E02D2CE0AB |
:100BA00030E0A401C801B7010995882389F185EED9 |
:100BB0008983D601ED91FC910480F581E02D2CE034 |
:100BC00030E0A401C801B7010995882309F18C859B |
:100BD0008F3049F480E290E0A0E0B0E0E80EF91E2A |
:100BE0000A1F1B1FD6CFF50161A172A16115710506 |
:100BF00019F481E090E00AC0C6010E94A80220E03A |
:100C000030E0882311F021E030E0C901992702C0CB |
:100C100080E090E02C960FB6F894DEBF0FBECDBFFB |
:100C2000DF91CF911F910F91FF90EF90DF90CF90C8 |
:100C3000BF90AF909F908F90089508950895FC0104 |
:100C4000892B29F460E070E080E090E008956285EF |
:100C50007385848595859695879577956795625078 |
:100C600070408040904020893189442755270E9458 |
:100C7000981B08952F923F924F925F926F927F92AE |
:100C80008F929F92AF92BF92CF92DF92EF92FF929C |
:100C90000F931F93CF93DF93CDB7DEB7A5970FB612 |
:100CA000F894DEBF0FBECDBF1C01892B09F456C0DE |
:100CB0001A82198280E28B83F1014680578060841A |
:100CC000718482849384A484B58437C0FEEF8F1628 |
:100CD000FFEF9F06F0E0AF06F0E0BF0628F02EEF32 |
:100CE0003FEF3DA32CA302C09DA28CA2D101ED91A8 |
:100CF000FC910280F381E02D6E010894C11CD11C8F |
:100D0000BBECEB2EB6E0FB2E0CA11DA120E230E0E7 |
:100D1000AE014C5F5F4FC301B20109958823F1F02A |
:100D20000CA11DA1C801AA27BB27480E591E6A1E87 |
:100D30007B1E881A990AAA0ABB0A81149104A1048D |
:100D4000B10421F6F10160897189882799272981E9 |
:100D50003A81442755270E94981B04C060E070E048 |
:100D600080E090E0A5960FB6F894DEBF0FBECDBF31 |
:100D7000DF91CF911F910F91FF90EF90DF90CF9077 |
:100D8000BF90AF909F908F907F906F905F904F90AB |
:100D90003F902F900895AC01D901F9016281FC01C7 |
:100DA00012C081819927982F882720813327822B91 |
:100DB000932B892B39F48D919C9111970196119663 |
:100DC0009C938E9332968E2F841B861750F381E06E |
:100DD00090E0089520E1FC0111922A95E9F780E165 |
:100DE00090E008952F923F924F925F926F927F9280 |
:100DF0008F929F92AF92BF92CF92DF92EF92FF922B |
:100E00000F931F93CF93DF93CDB7DEB7E5970FB660 |
:100E1000F894DEBF0FBECDBF1C017DA76CA7009765 |
:100E200009F4F7C0672B09F4F4C0FC0163A074A0B7 |
:100E300025A536A53FA72EA74080518061147104D7 |
:100E400009F050C04114510409F4E0C0D201ED9101 |
:100E5000FC91A280B3809E012F5F3F4F89E0F90192 |
:100E600011928A95E9F78EA59FA59C838B83F20149 |
:100E7000628973898489958906891789061B170BEE |
:100E8000FAE08F2E912C8C0E9D1E6901E2E4EE2E6D |
:100E9000E1E0FE2E20E230E0A401F501099588236F |
:100EA00009F4B4C04D805E806F8078844114510491 |
:100EB0006104710409F4AAC08BE2ACA5BDA51D9222 |
:100EC0008A95E9F709851127CCA4DDA473E7E72EFD |
:100ED00071E0F72E20E230E0A401C301B201F50178 |
:100EE000099584C04114510409F490C0FC0182A109 |
:100EF00084FF8CC0F2010088F189E02DFBA7EAA7EE |
:100F0000CF01AA27BB2788AB99ABAAABBBABDE014D |
:100F10001196BDABACABEEEFFFEF6E0E7F1EB301D3 |
:100F20008827992722E030E0620E731E28A939A98C |
:100F30004AA95BA90E94981BF20186889788A08C19 |
:100F4000B18C860E971EA81EB91E89E0ACA9BDA95A |
:100F50001D928A95E9F7EEA5FFA5FC83EB83D201EC |
:100F6000ED91FC91AE01465F5F4F0280F381E02D71 |
:100F70006E010894C11CD11C62E4E62E61E0F62EDD |
:100F80000AA51BA520E230E0C501B401099588231C |
:100F9000E9F18D809E80AF80B88481149104A10412 |
:100FA000B10441F4B301C2010E9456023C01892BF5 |
:100FB00069F1B1CF8BE2ECA5FDA511928A95E9F715 |
:100FC000D201ED91FC91098511270280F381E02D7A |
:100FD000CCA4DDA433E7E32E31E0F32E20E230E0B1 |
:100FE000AE01465F5F4FC501B4010995882371F0DA |
:100FF000ECA5FDA58081882349F0F10185A596A582 |
:10100000019696A785A781E090E005C0F10116A69C |
:1010100015A680E090E0E5960FB6F894DEBF0FBE0F |
:10102000CDBFDF91CF911F910F91FF90EF90DF9097 |
:10103000CF90BF90AF909F908F907F906F905F9078 |
:101040004F903F902F9008952F923F924F925F9232 |
:101050006F927F928F929F92AF92BF92CF92DF92C8 |
:10106000EF92FF920F931F93CF93DF93CDB7DEB72D |
:10107000AC970FB6F894DEBF0FBECDBF6C010097E2 |
:1010800009F4A2C1FC0184819581892B09F49CC1DA |
:1010900086819781892B09F497C102E011E01CA792 |
:1010A0000BA78091020190910301892B09F08CC15B |
:1010B0008AE1D8011D928A95E9F7D0920301C09286 |
:1010C0000201018512852385348589E0000F111FF7 |
:1010D000221F331F8A95D1F70AA31BA32CA33DA37C |
:1010E000C901B801655F7F4F8F4F9F4F0190F0811D |
:1010F000E02D29E130E0AE014F5F5F4F0995882375 |
:1011000009F45EC129813A80FB81F8A74C813D81B9 |
:101110005E812F8048845984AA848D859927F82F71 |
:10112000EE278C859927E82BF92BEE888F89688D1F |
:10113000798D309709F444C19927AA27BB276624E3 |
:10114000782E892E9A2E862F9927AA27BB27DC0175 |
:1011500099278827682A792A8A2A9B2A8E2D9927F7 |
:10116000AA27BB27682A792A8A2A9B2A872F9927A8 |
:10117000AA27BB27B82FAA2799278827682A792A60 |
:101180008A2A9B2A611471048104910479F48A2DBE |
:101190009927782F6627852D9927682B792B61153C |
:1011A000710509F40DC13B0188249924832D9927E9 |
:1011B000982F88279FA38EA3822F99270EA11FA166 |
:1011C000082B192B1FA30EA3842D9927982F88274E |
:1011D0009AA789A7822D992769A57AA5682B792BCB |
:1011E0007AA769A7832F9927982F8827242F332739 |
:1011F000822B932B8C01222733270A8F1B8F2C8F56 |
:101200003D8FBF0188279927252F3327442755274E |
:101210000E94981B6E8F7F8F88A399A3840173010E |
:101220002A8D3B8D4C8D5D8DE21AF30A040B150B54 |
:10123000E61AF70A080B190B8EA19FA1019729A5A1 |
:101240003AA545E0220F331F4A95E1F7820F931F1D |
:101250006EA17FA10E94B71B88279927E61AF70A7B |
:10126000080B190B68A5262F332744275527C801DB |
:10127000B7010E94DE1B19012A01DA01C901855F4D |
:101280009F40A040B0408050904FA040B04008F038 |
:1012900097C086E0F60180870BA51CA50E5F1F4F47 |
:1012A00088E1D8011D928A95E9F7025010401CA7E9 |
:1012B0000BA7EEA1FFA15F01CC24DD24C401B30183 |
:1012C000A60195010E94981B60930401709305018B |
:1012D0008093060190930701C601B5012A8D3B8DCD |
:1012E0004C8D5D8D0E94981B7B018C012AA13BA136 |
:1012F0004CA15DA1E20EF31E041F151FE092080130 |
:10130000F092090100930A0110930B01220C331C87 |
:10131000441C551C44E050E060E070E0240E351E93 |
:10132000461E571E20920C0130920D0140920E0174 |
:1013300050920F016EA17FA1709311016093100173 |
:1013400078A5872F9927AEA1BFA1FC01AE9FC00150 |
:10135000AF9F900DBE9F900D112490931301809329 |
:1013600012016E8D7F8D88A199A1A60195010E9421 |
:10137000981B6E0D7F1D801F911F60931401709349 |
:101380001501809316019093170109A51AA59801DC |
:1013900044275527A5E0220F331F441F551FAA9548 |
:1013A000D1F7620F731F841F951F6093180170930C |
:1013B000190180931A0190931B018BA59CA506C06F |
:1013C000109203011092020180E090E0AC960FB6FB |
:1013D000F894DEBF0FBECDBFDF91CF911F910F916B |
:1013E000FF90EF90DF90CF90BF90AF909F908F9045 |
:1013F0007F906F905F904F903F902F9008952F9225 |
:101400003F924F925F926F927F928F929F92AF9294 |
:10141000BF92CF92DF92EF92FF920F931F93CF93E1 |
:10142000DF93CDB7DEB723970FB6F894DEBF0FBEBC |
:10143000CDBF1C019B01892B09F4C2C04115510588 |
:1014400009F4BEC0FA0101900020E9F7E41BF50B96 |
:10145000CF010B966DE070E00E94B71B6F5F6B834E |
:10146000F90143A054A04114510451F0662477249B |
:101470004301AA24BB246501EE24FF2487010BC08D |
:10148000F101A288B388C488D588E688F788008DE2 |
:10149000118D350146011A82AE14BF04C006D10673 |
:1014A00009F05EC04114510409F48AC0A114B104CA |
:1014B000C104D10479F1B201C1010E945602009722 |
:1014C00041F541E050E0B201C1010E942B038C01C3 |
:1014D000892B09F475C002501040B801882799275C |
:1014E0000E5F1F4FF10120893189442755270E9443 |
:1014F000981B3B014C01F10186899789A08DB18D24 |
:10150000680E791E8A1E9B1EB801C1010E94FC0351 |
:101510005AC02C01F101E088F188002711272EEF35 |
:101520003FEF420E531EB20188279927A2E0B0E098 |
:101530004A0E5B1EA80197010E94981B5B016C017B |
:10154000F10186899789A08DB18DA80EB91ECA1E9A |
:10155000DB1EEA0CFB1C0C1D1D1D350146011A8209 |
:10156000D101ED91FC910190F081E02D21E030E07E |
:10157000AE014F5F5F4FC601B5010995882301F1A8 |
:101580008981853E11F0882379F4BA81BF5FBA83DF |
:10159000EB81BE17C0F480E290E0A0E0B0E0A80EBE |
:1015A000B91ECA1EDB1E78CF90E2692E712C812CE9 |
:1015B000912C6A0C7B1C8C1C9D1C640153016BCF0D |
:1015C000662477244301C401B30123960FB6F8942F |
:1015D000DEBF0FBECDBFDF91CF911F910F91FF9066 |
:1015E000EF90DF90CF90BF90AF909F908F907F90C3 |
:1015F0006F905F904F903F902F9008954F925F9221 |
:101600007F928F929F92AF92BF92CF92DF92EF9292 |
:10161000FF920F931F93CF93DF93CDB7DEB7A097C1 |
:101620000FB6F894DEBF0FBECDBFFC018B01892B36 |
:1016300009F41AC16115710509F416C10190F08110 |
:10164000E02D44805580FB01A7A0B0A4C1A4D2A482 |
:1016500001900020E9F73197FE2EF61A8F2D992779 |
:101660000C966DE070E00E94CB1B762E4BE050E0B4 |
:1016700060E270E0CE0101960E94551B6EE270E0C0 |
:10168000C8010E948D1BFC010097C1F0DC0111967E |
:101690008181882399F0FD0101900020E9F73197BD |
:1016A000EA1BFB0BFE1AFA944E2FE43008F043E0DD |
:1016B0005527BD01CE0109960E944C1BCE01019613 |
:1016C000F8E0FF1588F04F2D5527B8010E944C1BFC |
:1016D000D8018C918E3219F5F80181818E3209F48E |
:1016E00082818823D9F01BC0DC01F80188E00190D9 |
:1016F0000D928150E1F7F80181A1982F92959F708A |
:10170000803A10F4905D01C09F598F708A3010F4B8 |
:10171000805D01C08F599F83888701C077248981AC |
:10172000853E11F485E089837CE0872E912C8C0E18 |
:101730009D1E85E1D4011D928A95E9F7F80180A1EB |
:101740008C8781A192A18B8F892F99278C8F83A160 |
:1017500094A1A5A1B6A18D8F292F3A2F4B2F5527E4 |
:101760002E8F9D01442755272F8F8B2F9927AA272E |
:10177000BB2788A3672D77278827992725E0660F41 |
:10178000771F881F991F2A95D1F76A0D7B1D8C1D25 |
:101790009D1D20E230E0AE014F5F5F4FF2010995E1 |
:1017A000882309F461C0E980FE01329694018E2DF0 |
:1017B0008695E794EE24E794E82A8191E80EE217F3 |
:1017C000F307A9F7F72C4E010894811C911C0D50CA |
:1017D000104044C040E250E06FEF70E0C4010E944E |
:1017E000551B8DE0F89ED0011124A00FB11F91E090 |
:1017F000F401E90FF11D8C918083892F8F5FF40133 |
:10180000E80FF11D10829E5F9B3021F09A3119F490 |
:101810009CE101C09EE08C91882321F09F3110F45F |
:101820001196E6CFF982F71419F48F2D806489831D |
:101830008FE08C87EE861D861B8E1C8E20E230E0AA |
:10184000A401C601B501F201099580E290E0A0E093 |
:10185000B0E0A80EB91ECA1EDB1EFA94FF2009F0E4 |
:10186000B9CF81E090E002C080E090E0A0960FB692 |
:10187000F894DEBF0FBECDBFDF91CF911F910F91C6 |
:10188000FF90EF90DF90CF90BF90AF909F908F90A0 |
:101890007F905F904F9008952F923F924F925F926A |
:1018A0006F927F928F929F92AF92BF92CF92DF9270 |
:1018B000EF92FF920F931F93CF93DF93CDB7DEB7D5 |
:1018C0002E970FB6F894DEBF0FBECDBF6C011A0184 |
:1018D0002B01009709F4E2C0FC01E3A0F4A0019001 |
:1018E000F081E02D80899189E114F10431F44115F2 |
:1018F00051056105710509F4BDC0420131019C012A |
:10190000442755272F83388749875A875095409514 |
:10191000309521953F4F4F4F5F4F2B873C874D8729 |
:101920005E8711C0B701D6018D919C910E9456022D |
:101930000097B9F02B853C854D855E85620E731E40 |
:10194000841E951E7C018F819885A985BA858B831D |
:101950009C83AD83BE8386159705A805B90510F352 |
:10196000A0C05701C401B3012B813C814D815E8130 |
:101970000E94DE1B8901B901882799272B813C81B0 |
:101980004D815E810E94981B661577058805990533 |
:1019900010F40F5F1F4FA801B701D6018D919C91E4 |
:1019A0000E942B03009709F479C0EF2821F4F60177 |
:1019B00094A383A35C01F60125A236A247A250A6F8 |
:1019C000211431044104510411F414A213A2B601EC |
:1019D0006E5F7F4FD6018D919C910E94FE0A8823F5 |
:1019E00009F45CC0211431044104510429F4B50107 |
:1019F000F601808191813CC02B813C814D815E81CB |
:101A00002615370548055905A8F1D6010D911C91F9 |
:101A10000115110579F1B2E0AB16B10458F1B50129 |
:101A2000C8010E9456027C018FEF89838A83F801E6 |
:101A300080809180AA0CBB1CB5018827992726813C |
:101A4000378140855185620F731F841F951FF401F4 |
:101A5000A481B58122E030E0AE014F5F5F4FFD0110 |
:101A60000995882339F0E114F10421F0B701C80188 |
:101A70000E94A802F60185A596A5A7A5B0A92816DB |
:101A800039064A065B0638F4F60125A636A647A6AF |
:101A900050AA12AA11AA81E090E009C080E090E06B |
:101AA00006C05701E114F10409F45CCF84CF2E96EF |
:101AB0000FB6F894DEBF0FBECDBFDF91CF911F915F |
:101AC0000F91FF90EF90DF90CF90BF90AF909F90DD |
:101AD0008F907F906F905F904F903F902F900895E0 |
:101AE000CF92DF92EF92FF920F931F93CF93DF93EA |
:101AF000EC016B01892B09F446C06115710509F4ED |
:101B000042C08DA59EA5AFA5B8A9413059F041307E |
:101B100018F04230C1F50CC0FB01E080F180028179 |
:101B2000138113C0FB01E080F1800281138109C0A1 |
:101B3000FB01E080F180028113818DA19EA1AFA104 |
:101B4000B8A5E80EF91E0A1F1B1F8DA19EA1AFA10B |
:101B5000B8A58E159F05A007B10738F4B801A701F5 |
:101B6000CE010E944C0C882371F0EDA6FEA60FA7B3 |
:101B700018AB1AAA19AAF601E082F1820283138334 |
:101B800081E090E002C080E090E0DF91CF911F9172 |
:101B90000F91FF90EF90DF90CF9008952F923F929A |
:101BA0004F925F926F927F928F929F92AF92BF926D |
:101BB000CF92DF92EF92FF920F931F93CF93DF9319 |
:101BC000CDB7DEB72A970FB6F894DEBF0FBECDBFF4 |
:101BD0005C011B0158874F83009709F43BC1672BB9 |
:101BE00009F438C1452B09F435C1FC0165A476A47C |
:101BF00087A490A885A196A1A7A1B0A58615970551 |
:101C0000A805B90508F426C120813181F9010088B1 |
:101C1000F189E02DFA83E983F50101A8F2A9E02D0D |
:101C2000FA87E98789819A81AA27BB278B839C83BE |
:101C3000AD83BE83EF2B09F059C0F50103A0F4A1D9 |
:101C4000E02DFA87E987EF2BA9F461147104810470 |
:101C5000910409F0FFC041E050E060E070E0C9018C |
:101C60000E942B039A878987F50194A383A3892B6C |
:101C700009F4F0C0F501E5A4F6A407A510A9E11444 |
:101C8000F1040105110549F531C08B819C81AD81BD |
:101C9000BE81E81AF90A0A0B1B0B69857A85D50102 |
:101CA0008D919C910E945602009719F09A8789871E |
:101CB00014C0E114F1040105110509F0CBC041E0A5 |
:101CC00050E069857A85F501808191810E942B031E |
:101CD000009709F4BFC09A8789878B819C81AD8169 |
:101CE000BE81E816F9060A071B0778F6C401B3019E |
:101CF0002B813C814D815E810E94DE1B2B016F8018 |
:101D00007884D5018D919C9189809A80841895085A |
:101D10006814790408F44301FC01C080D180720189 |
:101D20000027112786899789A08DB18DE80EF91EAD |
:101D30000A1F1B1F29853A8522503040B901882788 |
:101D400099272E5F3F4F3A8729872B813C814D8110 |
:101D50005E810E94981BE60EF71E081F191FF601F0 |
:101D6000A481B5819401A101C801B701FD010995C4 |
:101D7000882309F446C068187908C401AA27BB273C |
:101D8000F50125A536A547A550A9280F391F4A1FDB |
:101D90005B1F25A736A747A750ABC401840D951D2F |
:101DA00029813A818217930708F169857A858081B4 |
:101DB00091810E945602009719F09A87898714C072 |
:101DC0006114710459F041E050E069857A85D501CC |
:101DD0008D919C910E942B03009721F4F50112AA8A |
:101DE00011AA0FC09A8789874424552429853A85EA |
:101DF000F50132AB21AB6114710419F0280C391CC8 |
:101E000080CFF50185A596A5A7A5B0A9E5A0F6A068 |
:101E100007A110A5E816F9060A071B07B0F485A369 |
:101E200096A3A7A3B0A7B5016E5F7F4F8081918174 |
:101E30000E94FE0A882349F4F50165A476A46E1871 |
:101E40007F08E5A6F6A607A710AB8F8198858619AF |
:101E5000970902C08FEF9FEF2A960FB6F894DEBF66 |
:101E60000FBECDBFDF91CF911F910F91FF90EF90EB |
:101E7000DF90CF90BF90AF909F908F907F906F90AA |
:101E80005F904F903F902F900895CF93DF939C01E8 |
:101E9000FB01892B21F1672B11F180A184FF1FC069 |
:101EA00080914F0190915001892B19F4AFE4B1E07A |
:101EB00008C080917E0190917F01892B81F4AEE76B |
:101EC000B1E0ED0122968BE2019009928150E1F799 |
:101ED00011963C932E93FD0116A615A602C0A0E014 |
:101EE000B0E0CD01DF91CF910895CF93DF939C01B6 |
:101EF000FB01892B49F16115710531F180A184FD48 |
:101F000023C080911C0190911D01892BE9F4CEE141 |
:101F1000D1E0DB018BE20D9009928150E1F7309323 |
:101F20001D0120931C011092490110924A01109248 |
:101F30004B0110924C0181A192A190934E0180938C |
:101F40004D018CE191E002C080E090E0DF91CF9103 |
:101F50000895CF92DF92EF92FF920F931F93CF934A |
:101F6000DF937C018B01EA01892B09F443C06115E1 |
:101F7000710509F43FC0FB0180818823D9F1452B0D |
:101F8000C9F1BE01C7010E94F206882351F0BE01CB |
:101F9000C8010E94671B892BA1F7F70116A615A699 |
:101FA00029C0F701C080D1808BE2FE0111928A9591 |
:101FB000E9F74FE150E0B801CE010E947E1BAE016F |
:101FC000B701C6010E94FF096FA378A789A79AA746 |
:101FD000611571058105910569F0BE01C6010E9478 |
:101FE000FE0A90E0882309F491E081E09827892F88 |
:101FF000992702C080E090E0DF91CF911F910F916F |
:10200000FF90EF90DF90CF9008956F927F928F9224 |
:102010009F92AF92BF92CF92DF92EF92FF920F9377 |
:102020001F93CF93DF933C018B017A01892B09F435 |
:1020300061C06115710509F45DC0FB0180818823D1 |
:1020400009F458C0452B09F455C08F3211F40F5FC5 |
:102050001F4F8BE2F70111928A95E9F780E1F701B2 |
:1020600080A3F8018081882309F447C0B701C30128 |
:102070000E94450F5C01892BE9F16FE270E0C80115 |
:102080000E945C1B6C01892B41F4F8010190002037 |
:10209000E9F76F010894C108D1088C2D801B882EA8 |
:1020A000992421C0E70109900020E9F72197CE1972 |
:1020B000DF09C815D905B9F4AE01B701C8010E94FE |
:1020C000701B892B81F4F50111821082C00FD11F82 |
:1020D0008881882391F0F70180A184FF0BC08601DD |
:1020E0000F5F1F4FC3CFB701C5010E94F2068823BF |
:1020F000C9F606C080E090E007C081E090E004C02F |
:10210000F50111821082B2CFDF91CF911F910F9113 |
:10211000FF90EF90DF90CF90BF90AF909F908F9007 |
:102120007F906F9008959F92AF92BF92CF92DF926F |
:10213000EF92FF920F931F93CF93DF936C015B019C |
:10214000EA01892B09F495C06115710509F491C064 |
:10215000FB018081882309F48CC0452B09F489C0D8 |
:10216000BE01C6010E94F206882351F0BE01C501DE |
:102170000E94671B892BA1F7F60116A615A679C048 |
:10218000F601E080F18041E050E060E070E0C701DE |
:102190000E942B038C01009709F46BC0BC01C7019E |
:1021A0000E94FC038BE2FE0111928A95E9F780E11F |
:1021B00088A302501040B801882799270E5F1F4F4F |
:1021C000F70120893189442755270E94981BF70180 |
:1021D00026893789408D518D260F371F481F591F7B |
:1021E0002FA338A749A75AA7BEE29B2E98821AA30D |
:1021F00009A3BE01C7010E94FE0A8823B1F18FA185 |
:1022000098A5A9A5BAA58096A11DB11D8FA398A7D1 |
:10221000A9A7BAA79982F60183A194A19AA389A339 |
:10222000BE01C7010E94FE0A8823F9F04FE150E089 |
:10223000B501CE010E947E1B1AA309A3AE01B6010F |
:10224000C7010E94FF096FA378A789A79AA7611504 |
:1022500071058105910549F0BE01C7010E94FE0A82 |
:10226000882319F081E090E006C0B801C7010E9400 |
:10227000A80280E090E0DF91CF911F910F91FF9035 |
:10228000EF90DF90CF90BF90AF909F900895EF9226 |
:10229000FF920F931F93FC01DB01B80187ED97E0DC |
:1022A0009183808381E08C93FA018083F90110820D |
:1022B000FB011082F70110821F910F91FF90EF90A8 |
:1022C00008950F931F93CF93DF93CDB7DEB7699730 |
:1022D0000FB6F894DEBF0FBECDBF8C01892B09F479 |
:1022E0009CC0CE0101960E940319882309F495C071 |
:1022F0008FE292E00E94101B89810E94261A8AE0D8 |
:102300000E94171A86E292E00E94101BCE010296EC |
:102310000E94031B8AE00E94171A8DE192E00E943E |
:10232000101BCE0105960E94031B8AE00E94171A1B |
:1023300084E192E00E94101B8B850E94261A8AE09D |
:102340000E94171A89E092E00E94101B6C857D851F |
:102350008E859F850E944F1A8AE00E94171A80E09E |
:1023600092E00E94101B898999270E94621A8FE2CD |
:102370000E94171A888999270E94621A8AE00E948F |
:10238000171A87EF91E00E94101B6A897B898C895C |
:102390009D890E94A21A8AE00E94171A8EEE91E08F |
:1023A0000E94101B8E8999270E94621A8AE00E945F |
:1023B000171A85EE91E00E94101B888D99270E94C4 |
:1023C000621A8FE20E94171A8F8999270E94621A57 |
:1023D0008AE00E94171A8CED91E00E94101B898DF3 |
:1023E00099270E94621A8AE00E94171A83ED91E0F1 |
:1023F0000E94101BC8010E943A060E94A21A8FE296 |
:102400000E94171AC8010E941F060E94A21A8AE0A1 |
:102410000E94171A81E090E002C080E090E0699687 |
:102420000FB6F894DEBF0FBECDBFDF91CF911F91E5 |
:102430000F910895EF92FF920F931F93CF93DF9325 |
:102440008B017A01E9010CC0B701CE010E94671B24 |
:10245000892B31F4C8010E94920581E090E008C008 |
:10246000BE01C8010E94F206882371F780E090E067 |
:10247000DF91CF911F910F91FF90EF900895EF9210 |
:10248000FF920F931F93CF93DF93CDB7DEB7AB9738 |
:102490000FB6F894DEBF0FBECDBF8C017E0108944D |
:1024A000E11CF11C97010E941A12882319F480E0A4 |
:1024B00090E004C0B701C8010E94750FAB960FB63B |
:1024C000F894DEBF0FBECDBFDF91CF911F910F916A |
:1024D000FF90EF900895AF92BF92DF92EF92FF923C |
:1024E0000F931F93CF93DF937C01062F1127A80131 |
:1024F00060E070E00E94551BDD2458010894A1089B |
:10250000B10823C00E941E1B182F883011F08F378E |
:1025100089F4DD20D1F0DA94F701ED0DF11D108280 |
:1025200088E00E94171A80E20E94171A88E00E9431 |
:10253000171A0BC00E94171AF701EC0FFD1F1A3073 |
:1025400011F4108207C01083D394CD2DDD27CA1556 |
:10255000DB05C4F2CE01DF91CF911F910F91FF9067 |
:10256000EF90DF90BF90AF900895C6E8D4E0DEBF53 |
:10257000CDBF83B7817F83BF0E940B1A0E94901842 |
:10258000882319F485EB91E068C200E020EC37E184 |
:102590004DE057E16AE178E186E796E10E943D155A |
:1025A000009781F40FEF20EC37E14DE057E16AE14D |
:1025B00078E186E796E10E943D15009719F48BE9D2 |
:1025C00091E04BC20E9424082C01009719F480E886 |
:1025D00091E043C28E010E5D1F4FA80160E071E0E3 |
:1025E0000E940510B801C2010E94450F3C01892BD1 |
:1025F00019F481E691E031C2C2010E9461110E948A |
:102600001E1B8432E1F70E941E1B8C32E1F78E0103 |
:10261000025F1F4F680164E1E62EF12CEC0EFD1EF7 |
:102620000E941E1BD8018D938D01AE15BF05C1F709 |
:102630001C8AAE01435B5F4FB601C3010E94A90F24 |
:102640001A821B821C821D825EE0A52EB12CAC0E6C |
:10265000BD1E42E0C42ED12CCC0EDD1E7E0108949E |
:10266000E11CF11CA501B301C2010E943F128C01C3 |
:1026700040E0B6010E94700D0E941E1B898341E05C |
:1026800050E0B701C8010E94CE0D89810E94171A3F |
:102690008A819B81AC81BD810196A11DB11D8A8378 |
:1026A0009B83AC83BD8389818A3011F0803421F70C |
:1026B000C8010E94490489818034A1F63EE0A32E1E |
:1026C000B12CAC0EBD1E2DE4222E312C2C0E3D1E45 |
:1026D000EA96BFAEAEAEEA978EE30E94171A80E28A |
:1026E0000E94171A64E1C5010E946B128823A1F3AE |
:1026F00043E050E06DE571E0C5010E943E1B892B6F |
:10270000F9F4E3E0F0E0AE0EBF1ED5018C91882312 |
:1027100019F39101A501B301C2010E941A12882385 |
:1027200061F0B101C2010E94450F8C01892B29F093 |
:10273000C3010E948C053801CFCF87E491E084C1AA |
:1027400064E471E0C5010E94351B892B81F528C026 |
:10275000F10101900020E9F78F01015010400219AA |
:102760001309C1010E94031BF10180A184FF02C073 |
:102770008FE201C080E294E2F92EF01A01C080E2FB |
:102780000E94171AFA94FFEFFF16C9F7F10163A12F |
:1027900074A185A196A10E94A21A8AE00E94171A2C |
:1027A000B101C3010E94F206882391F695CF44E05F |
:1027B00050E06FE371E0C5010E943E1B892B09F0D8 |
:1027C00049C084E090E0A80EB91ED5018C91882301 |
:1027D00009F482CFA501B301C2010E943F124C014E |
:1027E000892B21F0CC24DD24760127C080E391E001 |
:1027F0002BC1C701B6010E944F1A8AE30E94171A23 |
:102800008E010A5F1F4F80E20E94171AF801819122 |
:102810008F010E94261AEA968EAD9FADEA9708179F |
:10282000190789F78AE00E94171A88E090E0A0E073 |
:10283000B0E0C80ED91EEA1EFB1E48E050E0BE0103 |
:102840006A5F7F4FC4010E944F04181619068CF26C |
:10285000C401BAC06BE271E0C5010E94351B892B2F |
:1028600059F4C2010E946111882309F035CF82E139 |
:1028700091E00E94101B30CF43E050E06EE071E029 |
:10288000C5010E943E1B892BD9F4A3E0B0E0AA0E3B |
:10289000BB1EF5018081882309F41ECF9101A5019B |
:1028A000B301C2010E941A12882339F0B101C2019A |
:1028B0000E949D05882309F00FCF88EF90E0C4C0E7 |
:1028C00046E050E061EF70E0C5010E943E1B892B9D |
:1028D000A1F486E090E0A80EB91ED5018C91882362 |
:1028E00009F4FACEA101B501C3010E94A90F882302 |
:1028F00009F0F2CE8BED90E0A7C046E050E064ED29 |
:1029000070E0C5010E943E1B892B09F07EC0E6E005 |
:10291000F0E0AE0EBF1ED5018C91882309F4DCCE09 |
:10292000850102C00F5F1F4FF8018081803219F0CE |
:102930008823C1F7D1CED8011C92A501B301C201F1 |
:102940000E943F127C01892B19F485EC90E07CC039 |
:1029500020E030E040E050E017C0CA01B9012AE0B1 |
:1029600030E040E050E00E94981B9B01AC018D2DAF |
:10297000992787FD9095C097AA2797FDA095BA2F14 |
:10298000280F391F4A1F5B1FF801D1800F5F1F4FAF |
:102990008D2D80538A3008F32A833B834C835D83DB |
:1029A00040E0BE016E5F7F4FC7010E94700D88231B |
:1029B00071F483EB90E00E94101BC5010E94031B81 |
:1029C0008AE00E94171AC7010E94490485CE8CE351 |
:1029D0000E94171A80E20E94171A64E1CE010E9637 |
:1029E0000E946B12882379F3082F1127A801BE01DA |
:1029F000625F7F4FC7010E94CE0D8017910739F3A8 |
:102A00008CE990E00E94101BDECF46E050E065E9C3 |
:102A100070E0C5010E943E1B892BA1F486E090E086 |
:102A2000A80EB91ED5018C91882309F455CEA101B9 |
:102A3000B501C3010E949310882309F04DCE8AE7A7 |
:102A400090E002C088E690E00E94101BC5010E9441 |
:102A5000031B8AE00E94171A3FCE0E94101B81E0E0 |
:102A600090E00C94001CFC01892B19F480E090E0AC |
:102A70000895108681E090E008958F929F92AF9222 |
:102A8000BF92CF92DF92EF92FF920F93CF93DF939B |
:102A9000CDB7DEB760970FB6F894DEBF0FBECDBFDF |
:102AA0007C016B015A014901892B09F4AAC0672BEB |
:102AB00009F4A7C004300CF0A4C007FD1DC0602FAE |
:102AC000772767FD7095E4E0660F771FEA95E1F7D9 |
:102AD00062547E4F882777FD8095982F20E130E063 |
:102AE000AE014F5F5F4FF7010995882309F489C054 |
:102AF0008D81882309F485C08091B501882309F070 |
:102B000080C0EDEAF1E081E1DF011D928A95E9F7ED |
:102B1000F092AE01E092AD01D092B001C092AF014F |
:102B2000B092B201A092B1019092B4018092B3012F |
:102B300007FD62C08D818093B5012A853327442724 |
:102B40005527542F432F322F22278B859927AA27C9 |
:102B5000BB27DC0199278827282B392B4A2B5B2B95 |
:102B600089859927AA27BB27282B392B4A2B5B2B32 |
:102B70008C859927AA27BB27B82FAA2799278827AA |
:102B8000282B392B4A2B5B2B2093B6013093B701AE |
:102B90004093B8015093B9012E8533274427552718 |
:102BA000542F432F322F22278F859927AA27BB27FF |
:102BB000DC0199278827282B392B4A2B5B2B8D8505 |
:102BC0009927AA27BB27282B392B4A2B5B2B8889CF |
:102BD0009927AA27BB27B82FAA2799278827282B08 |
:102BE000392B4A2B5B2B2093BA013093BB014093C6 |
:102BF000BC015093BD0103C08FEF8093B501CF019D |
:102C000002C080E090E060960FB6F894DEBF0FBE81 |
:102C1000CDBFDF91CF910F91FF90EF90DF90CF90DC |
:102C2000BF90AF909F908F90089586B182958F70DE |
:102C300099278095909581709070089586B18295BE |
:102C400086958770992780959095817090700895EA |
:102C50008EBD0DB407FEFDCF8DB58F778DBD089568 |
:102C60008FEF8EBD0DB407FEFDCF8DB58F778DBD77 |
:102C70008EB599270895DF92EF92FF920F931F93DD |
:102C8000D82E7A018B010E9430168D2D80640E940F |
:102C90002816812F9927AA27BB270E942816C8012A |
:102CA000AA27BB270E942816BB27A12F902F8F2D64 |
:102CB0000E9428168E2D0E942816DD2011F485E929 |
:102CC00001C08FEF0E94281610E00E9430168F3F3F |
:102CD00019F41F5F1A30C9F799271F910F91FF90C0 |
:102CE000EF90DF90089581E090E008952F923F9259 |
:102CF0004F925F926F927F928F929F92AF92BF920C |
:102D0000CF92DF92EF92FF920F931F93CF93DF93B7 |
:102D10003B014C012A01190167C0C12C4EEFD42E92 |
:102D20004FEFE42E4FEFF42EC620D720E820F920F5 |
:102D300083011170A12C32E0B32EA01AB10A2A141B |
:102D40003B0408F451018091BE039091BF03A09110 |
:102D5000C003B091C103C816D906EA06FB0691F17B |
:102D60002A98B701A60181E10E943B16882321F031 |
:102D70002A9A80E090E03EC00E9430168E3FE1F734 |
:102D8000CEEBD1E00E943016899383E0CE3BD8078A |
:102D9000C9F7C092BE03D092BF03E092C003F09285 |
:102DA000C10302541E4FA501B801C2010E944C1B71 |
:102DB0004A0C5B1C0E9430160E9430162A9A0E9410 |
:102DC000301609C002541E4FA501B801C2010E946D |
:102DD0004C1B4A0C5B1C2A183B08C501AA27BB27C1 |
:102DE000680E791E8A1E9B1E2114310409F095CFAE |
:102DF00081E090E0DF91CF911F910F91FF90EF90D4 |
:102E0000DF90CF90BF90AF909F908F907F906F900A |
:102E10005F904F903F902F9008952F923F924F9246 |
:102E20005F926F927F928F929F92AF92BF92CF925A |
:102E3000DF92EF92FF920F931F93CF93DF935B018B |
:102E40006C012A01390186B182958695877080FFD1 |
:102E500077C081C0E12C7EEFF72E7FEF072F7FEF49 |
:102E6000172FEA20FB200C211D21E501D170812CB8 |
:102E700062E0962E8C1A9D0A6814790408F44301C6 |
:102E80008091BE039091BF03A091C003B091C10394 |
:102E9000E816F9060A071B07C9F0209729F480E015 |
:102EA000881682E0980650F420E032E0A101C801C3 |
:102EB000B7010E947616882309F44DC0E092BE0344 |
:102EC000F092BF030093C0031093C1038EEB48162A |
:102ED00081E0580639F0A401B201CE0182549E4F20 |
:102EE0000E944C1B2A98B801A70188E10E943B165A |
:102EF000882311F02A9A2FC08EEF0E942816E10134 |
:102F000089910E94281683E0CE3BD807C9F78FEF3E |
:102F10000E9428168FEF0E9428160E9430168F3FBD |
:102F2000E1F7480C591C0E9430162A9A6818790853 |
:102F3000C401AA27BB27A80EB91ECA1EDB1E04C0E7 |
:102F40005EEB252E51E0352E6114710409F082CF1D |
:102F500081E090E002C080E090E0DF91CF911F918E |
:102F60000F91FF90EF90DF90CF90BF90AF909F9028 |
:102F70008F907F906F905F904F903F902F9008952B |
:102F80004F925F926F927F928F929F92AF92BF9279 |
:102F9000CF92DF92EF92FF920F931F93CF93DF9325 |
:102FA0005B016C014A01E90138012701452B61F100 |
:102FB000012B51F1FF24232B11F5FF24F3941FC0A3 |
:102FC0009201B601A501C401F30109958C01009796 |
:102FD000F1F0FF2019F4C817D907B0F09801A40147 |
:102FE000C601B5010E940D17882371F0C801AA27F8 |
:102FF000BB27A80EB91ECA1EDB1EC01BD10BFF20AB |
:10300000F9F62097E9F603C080E090E002C081E085 |
:1030100090E0DF91CF911F910F91FF90EF90DF90A3 |
:10302000CF90BF90AF909F908F907F906F905F9068 |
:103030004F9008952F923F924F925F926F927F929E |
:103040008F929F92AF92BF92CF92DF92EF92FF92B8 |
:103050000F931F93CF93DF93CDB7DEB724970FB6AF |
:10306000F894DEBF0FBECDBF4B015C013A013C833B |
:103070002B832701DA82C982452BA1F12115310565 |
:1030800089F10217130770F1EF2861F119013094EB |
:10309000219431083394021B130B6901EE24FF24A1 |
:1030A0002B813C81A301C501B4010E9476168823BF |
:1030B000C9F029813A81B501A401C301F201099542 |
:1030C000882399F0020D131D8B819C81800F911F25 |
:1030D0002B813C818217930740F08C0C9D1CAE1C09 |
:1030E000BF1CDECF80E090E002C081E090E024963B |
:1030F0000FB6F894DEBF0FBECDBFDF91CF911F9109 |
:103100000F91FF90EF90DF90CF90BF90AF909F9086 |
:103110008F907F906F905F904F903F902F90089589 |
:103120001F93CF93DF933C983D98239A259A229A38 |
:1031300024982A9A83E58CBD8DB58E7F8DBD86B18E |
:1031400082958F7080FD17C010E00E9430161F5FBF |
:103150001A30D9F72A98C0E0D0E040E050E060E0B3 |
:1031600070E080E00E943B16813051F081E0CF3F5B |
:10317000D80721F42A9A80E090E041C02196EDCF53 |
:10318000C0E0D0E040E050E060E070E081E00E940C |
:103190003B1680FF06C08FE7CF3FD80759F3219633 |
:1031A000F1CF40E052E060E070E080E10E943B1629 |
:1031B000882301F72A9A8CB58C7F8CBD8DB58160F0 |
:1031C0008DBD8FEF9FEFAFEFBFEF8093BE03909366 |
:1031D000BF03A093C003B093C10320E032E04EEBE5 |
:1031E00051E060E070E080E090E00E94761690E0B0 |
:1031F000882309F491E081E09827892F9927DF91AE |
:10320000CF911F910895CF92DF92EF92FF920F938B |
:103210001F93CF93DF93EC01892B09F4F1C086B1A2 |
:1032200082958F7080FDECC089E1FE0111928A9534 |
:10323000E9F72A9840E050E060E070E08AE00E9400 |
:103240003B16882309F061C00E9430168E3FE1F7DB |
:103250008E0120E6E22EF12C0E943016282F802FBE |
:103260008C1B883028F4833090F4882359F00CC0EC |
:103270008D3018F4893080F40DC08D3029F18E30F6 |
:1032800079F526C028832CC0F801208329C0F801D5 |
:10329000218326C02A8724C03327442755270E2C94 |
:1032A00004C0220F331F441F551F0A94D2F78B8589 |
:1032B0009C85AD85BE85822B932BA42BB52B8B874C |
:1032C0009C87AD87BE870CC02295207F2F8708C0C2 |
:1032D000922F92959F708F85892B8F872F70288BC7 |
:1032E0000F5F1F4F88EF9FEFE80EF91E90EDE91674 |
:1032F0009FEFF90609F0B0CF40E050E060E070E0E9 |
:1033000089E00E943B16882311F02A9A79C00E9416 |
:1033100030168E3FE1F7CC24DD24EE24FF2400E0BC |
:1033200010E00E943016083021F1093040F40630D8 |
:1033300091F00730B0F4053009F058C008C00A30E9 |
:1033400041F10A3008F10E3009F050C03AC09FE058 |
:10335000C92EC8224BC0992783709070F82EEE2496 |
:1033600045C09927E82AF92AEE0CFF1CEE0CFF1C39 |
:103370003DC082958695869583709927E82AF92A1B |
:103380000894E11CF11C32C0F3E0DF2ED822DD0CE2 |
:103390002DC0881F8827881FD82A970144275527C2 |
:1033A0008C2D992702968D0D911D04C0220F331F7D |
:1033B000441F551F8A95D2F7298B3A8B4B8B5C8B18 |
:1033C00015C0282F332726FF02C081E08D8B25FFF3 |
:1033D00002C081E08E8B24FF02C081E08F8B2C70B5 |
:1033E00030703595279535952795288F0F5F1F4F9E |
:1033F0000231110509F095CF2A9A81E090E002C0D0 |
:1034000080E090E0DF91CF911F910F91FF90EF90BE |
:10341000DF90CF9008951092C50087E68093C40096 |
:1034200086E08093C20088E98093C10008951F93CD |
:10343000182F8A3019F48DE00E94171A8091C0006D |
:1034400085FFFCCF1093C6001F9108951F93182F7E |
:1034500082958F708A3010F4805D01C0895A0E9475 |
:10346000171A812F99278F709070212F2F700A972C |
:103470001CF4822F805D02C0822F895A0E94171A85 |
:103480001F9108950F931F938C01812F99270E94FC |
:10349000261A802F0E94261A1F910F910895EF92ED |
:1034A000FF920F931F937B018C01C801AA27BB27B2 |
:1034B0000E94421AC7010E94421A1F910F91FF9069 |
:1034C000EF900895DF92EF92FF920F931F93CF93A7 |
:1034D000DF93EC0100E117E220E0EE24FF24CE01AF |
:1034E000B8010E94B71BD62E662329F4222319F4B3 |
:1034F0000130110529F48D2D805D0E94171A21E0FD |
:10350000C8016AE070E00E94B71B0894E11CF11C3E |
:1035100045E0E416F10471F08D2D9927AC01409F30 |
:10352000C001419F900D509F900D1124C81BD90BD5 |
:103530008B01D5CFDF91CF911F910F91FF90EF902D |
:10354000DF9008954F925F926F927F928F929F9239 |
:10355000AF92BF92CF92DF92EF92FF920F931F93A1 |
:10356000CF93DF937B018C01A12C2AECB22E2AE9A8 |
:10357000C22E2BE3D22E4424C0E0D0E0C801B70114 |
:10358000A60195010E94DE1B522E222341F4442005 |
:1035900031F481E0A816B104C104D10431F4852DC1 |
:1035A000805D0E94171A44244394C601B5012AE0A5 |
:1035B00030E040E050E00E94DE1B39014A012196D4 |
:1035C000CA30D10579F0652D772788279927A6017C |
:1035D00095010E94981BE61AF70A080B190B640163 |
:1035E0005301CCCFDF91CF911F910F91FF90EF90BE |
:1035F000DF90CF90BF90AF909F908F907F906F9013 |
:103600005F904F900895CF93DF93EC0103C0219614 |
:103610000E94171A88818823D1F7DF91CF910895EE |
:10362000CF93DF93EC01FE0121968491882319F05A |
:103630000E94171AF8CFDF91CF9108959FB7789421 |
:1036400007C083B7816083BF889583B78E7F83BFB0 |
:103650008091C00087FFF5CF9FBF8091C6008D305D |
:1036600009F48AE0992708951895FB01DC018D91F2 |
:10367000059080190110D9F3990B0895FB01DC0125 |
:103680004150504030F08D910590801919F4002080 |
:10369000B9F7881B990B0895FB01DC0102C001906A |
:1036A0000D9241505040D8F70895DC0101C06D9350 |
:1036B00041505040E0F70895FC018191861721F0B8 |
:1036C0008823D9F7992708953197CF010895FB01F1 |
:1036D000DC018D91019080190110D9F3990B0895A7 |
:1036E000FB01DC014150504030F08D910190801978 |
:1036F00019F40020B9F7881B990B0895FB01DC0130 |
:103700004150504048F001900D920020C9F701C08F |
:103710001D9241505040E0F70895FC0181E090E097 |
:103720000190061609F4CF010020D1F70197089502 |
:10373000629FD001739FF001829FE00DF11D649F95 |
:10374000E00DF11D929FF00D839FF00D749FF00D21 |
:10375000659FF00D9927729FB00DE11DF91F639FC2 |
:10376000B00DE11DF91FBD01CF0111240895AA1B61 |
:10377000BB1B51E107C0AA1FBB1FA617B70710F05C |
:10378000A61BB70B881F991F5A95A9F7809590958E |
:10379000BC01CD01089597FB092E07260AD077FDBD |
:1037A00004D0E5DF06D000201AF4709561957F4FB4 |
:1037B0000895F6F7909581959F4F0895A1E21A2EEE |
:1037C000AA1BBB1BFD010DC0AA1FBB1FEE1FFF1FC5 |
:1037D000A217B307E407F50720F0A21BB30BE40B15 |
:1037E000F50B661F771F881F991F1A9469F760955C |
:1037F0007095809590959B01AC01BD01CF01089516 |
:02380000FFCFF8 |
:023802002F0095 |
:00000001FF |
/Designs/Data_loggers/GPSRL02A/SW/logger/sd-reader.map |
---|
0,0 → 1,525 |
Archive member included because of file (symbol) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_mulsi3.o) |
fat16.o (__mulsi3) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodhi4.o) |
fat16.o (__udivmodhi4) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_divmodhi4.o) |
fat16.o (__divmodhi4) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodsi4.o) |
fat16.o (__udivmodsi4) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o (exit) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_copy_data.o) |
fat16.o (__do_copy_data) |
/usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_clear_bss.o) |
fat16.o (__do_clear_bss) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp_P.o) |
main.o (strcmp_P) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp_P.o) |
main.o (strncmp_P) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memcpy.o) |
fat16.o (memcpy) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memset.o) |
fat16.o (memset) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strchr.o) |
fat16.o (strchr) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp.o) |
fat16.o (strcmp) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp.o) |
fat16.o (strncmp) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncpy.o) |
fat16.o (strncpy) |
/usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strrchr.o) |
fat16.o (strrchr) |
Memory Configuration |
Name Origin Length Attributes |
text 0x00000000 0x00020000 xr |
data 0x00800060 0x0000ffa0 rw !x |
eeprom 0x00810000 0x00010000 rw !x |
fuse 0x00820000 0x00000400 rw !x |
lock 0x00830000 0x00000400 rw !x |
signature 0x00840000 0x00000400 rw !x |
*default* 0x00000000 0xffffffff |
Linker script and memory map |
Address of section .data set to 0x800100 |
LOAD /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
LOAD fat16.o |
LOAD main.o |
LOAD partition.o |
LOAD sd_raw.o |
LOAD uart.o |
LOAD /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a |
LOAD /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a |
LOAD /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a |
.hash |
*(.hash) |
.dynsym |
*(.dynsym) |
.dynstr |
*(.dynstr) |
.gnu.version |
*(.gnu.version) |
.gnu.version_d |
*(.gnu.version_d) |
.gnu.version_r |
*(.gnu.version_r) |
.rel.init |
*(.rel.init) |
.rela.init |
*(.rela.init) |
.rel.text |
*(.rel.text) |
*(.rel.text.*) |
*(.rel.gnu.linkonce.t*) |
.rela.text |
*(.rela.text) |
*(.rela.text.*) |
*(.rela.gnu.linkonce.t*) |
.rel.fini |
*(.rel.fini) |
.rela.fini |
*(.rela.fini) |
.rel.rodata |
*(.rel.rodata) |
*(.rel.rodata.*) |
*(.rel.gnu.linkonce.r*) |
.rela.rodata |
*(.rela.rodata) |
*(.rela.rodata.*) |
*(.rela.gnu.linkonce.r*) |
.rel.data |
*(.rel.data) |
*(.rel.data.*) |
*(.rel.gnu.linkonce.d*) |
.rela.data |
*(.rela.data) |
*(.rela.data.*) |
*(.rela.gnu.linkonce.d*) |
.rel.ctors |
*(.rel.ctors) |
.rela.ctors |
*(.rela.ctors) |
.rel.dtors |
*(.rel.dtors) |
.rela.dtors |
*(.rela.dtors) |
.rel.got |
*(.rel.got) |
.rela.got |
*(.rela.got) |
.rel.bss |
*(.rel.bss) |
.rela.bss |
*(.rela.bss) |
.rel.plt |
*(.rel.plt) |
.rela.plt |
*(.rela.plt) |
.text 0x00000000 0x3802 |
*(.vectors) |
.vectors 0x00000000 0x68 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
0x00000000 __vectors |
0x00000000 __vector_default |
*(.vectors) |
*(.progmem.gcc*) |
*(.progmem*) |
.progmem.data 0x00000068 0x1d2 main.o |
0x0000023a . = ALIGN (0x2) |
0x0000023a __trampolines_start = . |
*(.trampolines) |
.trampolines 0x0000023a 0x0 linker stubs |
*(.trampolines*) |
0x0000023a __trampolines_end = . |
*(.jumptables) |
*(.jumptables*) |
*(.lowtext) |
*(.lowtext*) |
0x0000023a __ctors_start = . |
*(.ctors) |
0x0000023a __ctors_end = . |
0x0000023a __dtors_start = . |
*(.dtors) |
0x0000023a __dtors_end = . |
SORT(*)(.ctors) |
SORT(*)(.dtors) |
*(.init0) |
.init0 0x0000023a 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
0x0000023a __init |
*(.init0) |
*(.init1) |
*(.init1) |
*(.init2) |
.init2 0x0000023a 0xc /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
*(.init2) |
*(.init3) |
*(.init3) |
*(.init4) |
.init4 0x00000246 0x16 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_copy_data.o) |
0x00000246 __do_copy_data |
.init4 0x0000025c 0x10 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_clear_bss.o) |
0x0000025c __do_clear_bss |
*(.init4) |
*(.init5) |
*(.init5) |
*(.init6) |
*(.init6) |
*(.init7) |
*(.init7) |
*(.init8) |
*(.init8) |
*(.init9) |
.init9 0x0000026c 0x8 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
*(.init9) |
*(.text) |
.text 0x00000274 0x4 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
0x00000274 __vector_22 |
0x00000274 __vector_1 |
0x00000274 __vector_24 |
0x00000274 __vector_12 |
0x00000274 __bad_interrupt |
0x00000274 __vector_6 |
0x00000274 __vector_3 |
0x00000274 __vector_23 |
0x00000274 __vector_25 |
0x00000274 __vector_11 |
0x00000274 __vector_13 |
0x00000274 __vector_17 |
0x00000274 __vector_19 |
0x00000274 __vector_7 |
0x00000274 __vector_5 |
0x00000274 __vector_4 |
0x00000274 __vector_9 |
0x00000274 __vector_2 |
0x00000274 __vector_21 |
0x00000274 __vector_15 |
0x00000274 __vector_8 |
0x00000274 __vector_14 |
0x00000274 __vector_10 |
0x00000274 __vector_16 |
0x00000274 __vector_20 |
.text 0x00000278 0x2016 fat16.o |
0x00001898 fat16_resize_file |
0x00000278 fat16_close |
0x00000b24 fat16_reset_dir |
0x00000b3a fat16_delete_file |
0x00000c74 fat16_get_fs_free |
0x00000c3a fat16_get_file_modification_date |
0x00000de4 fat16_read_dir |
0x00000c3c fat16_get_file_modification_time |
0x00001ae0 fat16_seek_file |
0x00000c3e fat16_get_fs_size |
0x00000892 fat16_close_file |
0x00001eea fat16_open_file |
0x0000089e fat16_read_file |
0x00001048 fat16_open |
0x00001f52 fat16_create_file |
0x00002126 fat16_create_dir |
0x0000200a fat16_get_dir_entry_of_path |
0x00001b9c fat16_write_file |
0x00001e8a fat16_open_dir |
0x00000b18 fat16_close_dir |
.text 0x0000228e 0x7d8 main.o |
0x0000228e get_datetime |
0x0000256a main |
.text 0x00002a66 0x1c4 partition.o |
0x00002a66 partition_close |
0x00002a7a partition_open |
.text 0x00002c2a 0x7ec sd_raw.o |
0x00002c2a sd_raw_available |
0x00002f80 sd_raw_write_interval |
0x00002cec sd_raw_read |
0x00003120 sd_raw_init |
0x00003034 sd_raw_read_interval |
0x00003206 sd_raw_get_info |
0x00002ce6 sd_raw_sync |
0x00002c3c sd_raw_locked |
0x00002e1a sd_raw_write |
.text 0x00003416 0x254 uart.o |
0x00003544 uart_putdw_dec |
0x0000344c uart_putc_hex |
0x00003606 uart_puts |
0x00003620 uart_puts_p |
0x00003416 uart_init |
0x000034c4 uart_putw_dec |
0x0000363c uart_getc |
0x0000349e uart_putdw_hex |
0x0000342e uart_putc |
0x00003668 __vector_18 |
0x00003484 uart_putw_hex |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_mulsi3.o) |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodhi4.o) |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_divmodhi4.o) |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodsi4.o) |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_copy_data.o) |
.text 0x0000366a 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_clear_bss.o) |
.text 0x0000366a 0x12 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp_P.o) |
0x0000366a strcmp_P |
.text 0x0000367c 0x1c /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp_P.o) |
0x0000367c strncmp_P |
.text 0x00003698 0x12 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memcpy.o) |
0x00003698 memcpy |
.text 0x000036aa 0xe /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memset.o) |
0x000036aa memset |
.text 0x000036b8 0x16 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strchr.o) |
0x000036b8 strchr |
.text 0x000036ce 0x12 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp.o) |
0x000036ce strcmp |
.text 0x000036e0 0x1c /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp.o) |
0x000036e0 strncmp |
.text 0x000036fc 0x1e /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncpy.o) |
0x000036fc strncpy |
.text 0x0000371a 0x16 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strrchr.o) |
0x0000371a strrchr |
0x00003730 . = ALIGN (0x2) |
*(.text.*) |
.text.libgcc 0x00003730 0x3e /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_mulsi3.o) |
0x00003730 __mulsi3 |
.text.libgcc 0x0000376e 0x28 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodhi4.o) |
0x0000376e __udivmodhi4 |
.text.libgcc 0x00003796 0x26 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_divmodhi4.o) |
0x00003796 __divmodhi4 |
0x00003796 _div |
.text.libgcc 0x000037bc 0x44 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodsi4.o) |
0x000037bc __udivmodsi4 |
.text.libgcc 0x00003800 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
.text.libgcc 0x00003800 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_copy_data.o) |
.text.libgcc 0x00003800 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_clear_bss.o) |
0x00003800 . = ALIGN (0x2) |
*(.fini9) |
.fini9 0x00003800 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
0x00003800 exit |
0x00003800 _exit |
*(.fini9) |
*(.fini8) |
*(.fini8) |
*(.fini7) |
*(.fini7) |
*(.fini6) |
*(.fini6) |
*(.fini5) |
*(.fini5) |
*(.fini4) |
*(.fini4) |
*(.fini3) |
*(.fini3) |
*(.fini2) |
*(.fini2) |
*(.fini1) |
*(.fini1) |
*(.fini0) |
.fini0 0x00003800 0x2 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
*(.fini0) |
0x00003802 _etext = . |
.data 0x00800100 0x2 load address 0x00003802 |
0x00800100 PROVIDE (__data_start, .) |
*(.data) |
.data 0x00800100 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
.data 0x00800100 0x0 fat16.o |
.data 0x00800100 0x2 main.o |
.data 0x00800102 0x0 partition.o |
.data 0x00800102 0x0 sd_raw.o |
.data 0x00800102 0x0 uart.o |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_mulsi3.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodhi4.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_divmodhi4.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodsi4.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_copy_data.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_clear_bss.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp_P.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp_P.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memcpy.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memset.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strchr.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncpy.o) |
.data 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strrchr.o) |
*(.data*) |
*(.rodata) |
*(.rodata*) |
*(.gnu.linkonce.d*) |
0x00800102 . = ALIGN (0x2) |
0x00800102 _edata = . |
0x00800102 PROVIDE (__data_end, .) |
.bss 0x00800102 0x2c0 load address 0x00003804 |
0x00800102 PROVIDE (__bss_start, .) |
*(.bss) |
.bss 0x00800102 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
.bss 0x00800102 0xab fat16.o |
.bss 0x008001ad 0x0 main.o |
.bss 0x008001ad 0x11 partition.o |
.bss 0x008001be 0x204 sd_raw.o |
.bss 0x008003c2 0x0 uart.o |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_mulsi3.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodhi4.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_divmodhi4.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_udivmodsi4.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_exit.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_copy_data.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/avr5/libgcc.a(_clear_bss.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp_P.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp_P.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memcpy.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memset.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strchr.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncpy.o) |
.bss 0x008003c2 0x0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strrchr.o) |
*(.bss*) |
*(COMMON) |
0x008003c2 PROVIDE (__bss_end, .) |
0x00003802 __data_load_start = LOADADDR (.data) |
0x00003804 __data_load_end = (__data_load_start + SIZEOF (.data)) |
.noinit 0x008003c2 0x0 |
0x008003c2 PROVIDE (__noinit_start, .) |
*(.noinit*) |
0x008003c2 PROVIDE (__noinit_end, .) |
0x008003c2 _end = . |
0x008003c2 PROVIDE (__heap_start, .) |
.eeprom 0x00810000 0x0 |
*(.eeprom*) |
0x00810000 __eeprom_end = . |
.fuse |
*(.fuse) |
*(.lfuse) |
*(.hfuse) |
*(.efuse) |
.lock |
*(.lock*) |
.signature |
*(.signature*) |
.stab 0x00000000 0x6228 |
*(.stab) |
.stab 0x00000000 0x378 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
.stab 0x00000378 0x2e14 fat16.o |
0x2e20 (size before relaxing) |
.stab 0x0000318c 0x1158 main.o |
0x135c (size before relaxing) |
.stab 0x000042e4 0x300 partition.o |
0x4ec (size before relaxing) |
.stab 0x000045e4 0xf24 sd_raw.o |
0x10d4 (size before relaxing) |
.stab 0x00005508 0x7a4 uart.o |
0x9d8 (size before relaxing) |
.stab 0x00005cac 0x84 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp_P.o) |
0x90 (size before relaxing) |
.stab 0x00005d30 0xc0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp_P.o) |
0xcc (size before relaxing) |
.stab 0x00005df0 0x84 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memcpy.o) |
0x90 (size before relaxing) |
.stab 0x00005e74 0x6c /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(memset.o) |
0x78 (size before relaxing) |
.stab 0x00005ee0 0x9c /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strchr.o) |
0xa8 (size before relaxing) |
.stab 0x00005f7c 0x84 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strcmp.o) |
0x90 (size before relaxing) |
.stab 0x00006000 0xc0 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncmp.o) |
0xcc (size before relaxing) |
.stab 0x000060c0 0xcc /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strncpy.o) |
0xd8 (size before relaxing) |
.stab 0x0000618c 0x9c /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/libc.a(strrchr.o) |
0xa8 (size before relaxing) |
.stabstr 0x00000000 0x2db7 |
*(.stabstr) |
.stabstr 0x00000000 0x2db7 /usr/lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o |
.stab.excl |
*(.stab.excl) |
.stab.exclstr |
*(.stab.exclstr) |
.stab.index |
*(.stab.index) |
.stab.indexstr |
*(.stab.indexstr) |
.comment |
*(.comment) |
.debug |
*(.debug) |
.line |
*(.line) |
.debug_srcinfo |
*(.debug_srcinfo) |
.debug_sfnames |
*(.debug_sfnames) |
.debug_aranges |
*(.debug_aranges) |
.debug_pubnames |
*(.debug_pubnames) |
.debug_info |
*(.debug_info) |
*(.gnu.linkonce.wi.*) |
.debug_abbrev |
*(.debug_abbrev) |
.debug_line |
*(.debug_line) |
.debug_frame |
*(.debug_frame) |
.debug_str |
*(.debug_str) |
.debug_loc |
*(.debug_loc) |
.debug_macinfo |
*(.debug_macinfo) |
OUTPUT(sd-reader.out elf32-avr) |
LOAD linker stubs |
/Designs/Data_loggers/GPSRL02A/SW/logger/sd-reader.out |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:executable |
+* |
\ No newline at end of property |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/Designs/Data_loggers/GPSRL02A/SW/logger/sd-reader_config.h |
---|
0,0 → 1,44 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* This file is free software; you can redistribute it and/or modify |
* it under the terms of either the GNU General Public License version 2 |
* or the GNU Lesser General Public License version 2.1, both as |
* published by the Free Software Foundation. |
*/ |
#ifndef SD_READER_CONFIG_H |
#define SD_READER_CONFIG_H |
/** |
* \addtogroup config Sd-reader configuration |
* |
* @{ |
*/ |
/** |
* \file |
* Common sd-reader configuration used by all modules (license: GPLv2 or LGPLv2.1) |
* |
* \note This file contains only configuration items relevant to |
* all sd-reader implementation files. For module specific configuration |
* options, please see the files fat16_config.h, partition_config.h |
* and sd_raw_config.h. |
*/ |
/** |
* Controls allocation of memory. |
* |
* Set to 1 to use malloc()/free() for allocation of structures |
* like file and directory handles, set to 0 to use pre-allocated |
* fixed-size handle arrays. |
*/ |
#define USE_DYNAMIC_MEMORY 0 |
/** |
* @} |
*/ |
#endif |
/Designs/Data_loggers/GPSRL02A/SW/logger/sd_raw.c |
---|
0,0 → 1,912 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* This file is free software; you can redistribute it and/or modify |
* it under the terms of either the GNU General Public License version 2 |
* or the GNU Lesser General Public License version 2.1, both as |
* published by the Free Software Foundation. |
*/ |
#include <string.h> |
#include <avr/io.h> |
#include "sd_raw.h" |
/** |
* \addtogroup sd_raw MMC/SD card raw access |
* |
* This module implements read and write access to MMC and |
* SD cards. It serves as a low-level driver for the higher |
* level modules such as partition and file system access. |
* |
* @{ |
*/ |
/** |
* \file |
* MMC/SD raw access implementation (license: GPLv2 or LGPLv2.1) |
* |
* \author Roland Riegel |
*/ |
/** |
* \addtogroup sd_raw_config MMC/SD configuration |
* Preprocessor defines to configure the MMC/SD support. |
*/ |
/** |
* @} |
*/ |
/* commands available in SPI mode */ |
/* CMD0: response R1 */ |
#define CMD_GO_IDLE_STATE 0x00 |
/* CMD1: response R1 */ |
#define CMD_SEND_OP_COND 0x01 |
/* CMD9: response R1 */ |
#define CMD_SEND_CSD 0x09 |
/* CMD10: response R1 */ |
#define CMD_SEND_CID 0x0a |
/* CMD12: response R1 */ |
#define CMD_STOP_TRANSMISSION 0x0c |
/* CMD13: response R2 */ |
#define CMD_SEND_STATUS 0x0d |
/* CMD16: arg0[31:0]: block length, response R1 */ |
#define CMD_SET_BLOCKLEN 0x10 |
/* CMD17: arg0[31:0]: data address, response R1 */ |
#define CMD_READ_SINGLE_BLOCK 0x11 |
/* CMD18: arg0[31:0]: data address, response R1 */ |
#define CMD_READ_MULTIPLE_BLOCK 0x12 |
/* CMD24: arg0[31:0]: data address, response R1 */ |
#define CMD_WRITE_SINGLE_BLOCK 0x18 |
/* CMD25: arg0[31:0]: data address, response R1 */ |
#define CMD_WRITE_MULTIPLE_BLOCK 0x19 |
/* CMD27: response R1 */ |
#define CMD_PROGRAM_CSD 0x1b |
/* CMD28: arg0[31:0]: data address, response R1b */ |
#define CMD_SET_WRITE_PROT 0x1c |
/* CMD29: arg0[31:0]: data address, response R1b */ |
#define CMD_CLR_WRITE_PROT 0x1d |
/* CMD30: arg0[31:0]: write protect data address, response R1 */ |
#define CMD_SEND_WRITE_PROT 0x1e |
/* CMD32: arg0[31:0]: data address, response R1 */ |
#define CMD_TAG_SECTOR_START 0x20 |
/* CMD33: arg0[31:0]: data address, response R1 */ |
#define CMD_TAG_SECTOR_END 0x21 |
/* CMD34: arg0[31:0]: data address, response R1 */ |
#define CMD_UNTAG_SECTOR 0x22 |
/* CMD35: arg0[31:0]: data address, response R1 */ |
#define CMD_TAG_ERASE_GROUP_START 0x23 |
/* CMD36: arg0[31:0]: data address, response R1 */ |
#define CMD_TAG_ERASE_GROUP_END 0x24 |
/* CMD37: arg0[31:0]: data address, response R1 */ |
#define CMD_UNTAG_ERASE_GROUP 0x25 |
/* CMD38: arg0[31:0]: stuff bits, response R1b */ |
#define CMD_ERASE 0x26 |
/* CMD42: arg0[31:0]: stuff bits, response R1b */ |
#define CMD_LOCK_UNLOCK 0x2a |
/* CMD58: response R3 */ |
#define CMD_READ_OCR 0x3a |
/* CMD59: arg0[31:1]: stuff bits, arg0[0:0]: crc option, response R1 */ |
#define CMD_CRC_ON_OFF 0x3b |
/* command responses */ |
/* R1: size 1 byte */ |
#define R1_IDLE_STATE 0 |
#define R1_ERASE_RESET 1 |
#define R1_ILL_COMMAND 2 |
#define R1_COM_CRC_ERR 3 |
#define R1_ERASE_SEQ_ERR 4 |
#define R1_ADDR_ERR 5 |
#define R1_PARAM_ERR 6 |
/* R1b: equals R1, additional busy bytes */ |
/* R2: size 2 bytes */ |
#define R2_CARD_LOCKED 0 |
#define R2_WP_ERASE_SKIP 1 |
#define R2_ERR 2 |
#define R2_CARD_ERR 3 |
#define R2_CARD_ECC_FAIL 4 |
#define R2_WP_VIOLATION 5 |
#define R2_INVAL_ERASE 6 |
#define R2_OUT_OF_RANGE 7 |
#define R2_CSD_OVERWRITE 7 |
#define R2_IDLE_STATE (R1_IDLE_STATE + 8) |
#define R2_ERASE_RESET (R1_ERASE_RESET + 8) |
#define R2_ILL_COMMAND (R1_ILL_COMMAND + 8) |
#define R2_COM_CRC_ERR (R1_COM_CRC_ERR + 8) |
#define R2_ERASE_SEQ_ERR (R1_ERASE_SEQ_ERR + 8) |
#define R2_ADDR_ERR (R1_ADDR_ERR + 8) |
#define R2_PARAM_ERR (R1_PARAM_ERR + 8) |
/* R3: size 5 bytes */ |
#define R3_OCR_MASK (0xffffffffUL) |
#define R3_IDLE_STATE (R1_IDLE_STATE + 32) |
#define R3_ERASE_RESET (R1_ERASE_RESET + 32) |
#define R3_ILL_COMMAND (R1_ILL_COMMAND + 32) |
#define R3_COM_CRC_ERR (R1_COM_CRC_ERR + 32) |
#define R3_ERASE_SEQ_ERR (R1_ERASE_SEQ_ERR + 32) |
#define R3_ADDR_ERR (R1_ADDR_ERR + 32) |
#define R3_PARAM_ERR (R1_PARAM_ERR + 32) |
/* Data Response: size 1 byte */ |
#define DR_STATUS_MASK 0x0e |
#define DR_STATUS_ACCEPTED 0x05 |
#define DR_STATUS_CRC_ERR 0x0a |
#define DR_STATUS_WRITE_ERR 0x0c |
#if !SD_RAW_SAVE_RAM |
/* static data buffer for acceleration */ |
static uint8_t raw_block[512]; |
/* offset where the data within raw_block lies on the card */ |
static uint32_t raw_block_address; |
#if SD_RAW_WRITE_BUFFERING |
/* flag to remember if raw_block was written to the card */ |
static uint8_t raw_block_written; |
#endif |
#endif |
/* private helper functions */ |
static void sd_raw_send_byte(uint8_t b); |
static uint8_t sd_raw_rec_byte(); |
static uint8_t sd_raw_send_command_r1(uint8_t command, uint32_t arg); |
static uint16_t sd_raw_send_command_r2(uint8_t command, uint32_t arg); |
/** |
* \ingroup sd_raw |
* Initializes memory card communication. |
* |
* \returns 0 on failure, 1 on success. |
*/ |
uint8_t sd_raw_init() |
{ |
/* enable inputs for reading card status */ |
configure_pin_available(); |
configure_pin_locked(); |
/* enable outputs for MOSI, SCK, SS, input for MISO */ |
configure_pin_mosi(); |
configure_pin_sck(); |
configure_pin_ss(); |
configure_pin_miso(); |
unselect_card(); |
/* initialize SPI with lowest frequency; max. 400kHz during identification mode of card */ |
SPCR = (0 << SPIE) | /* SPI Interrupt Enable */ |
(1 << SPE) | /* SPI Enable */ |
(0 << DORD) | /* Data Order: MSB first */ |
(1 << MSTR) | /* Master mode */ |
(0 << CPOL) | /* Clock Polarity: SCK low when idle */ |
(0 << CPHA) | /* Clock Phase: sample on rising SCK edge */ |
(1 << SPR1) | /* Clock Frequency: f_OSC / 128 */ |
(1 << SPR0); |
SPSR &= ~(1 << SPI2X); /* No doubled clock frequency */ |
/* initialization procedure */ |
if(!sd_raw_available()) |
return 0; |
/* card needs 74 cycles minimum to start up */ |
for(uint8_t i = 0; i < 10; ++i) |
{ |
/* wait 8 clock cycles */ |
sd_raw_rec_byte(); |
} |
/* address card */ |
select_card(); |
/* reset card */ |
uint8_t response; |
for(uint16_t i = 0; ; ++i) |
{ |
response = sd_raw_send_command_r1(CMD_GO_IDLE_STATE, 0); |
if(response == (1 << R1_IDLE_STATE)) |
break; |
if(i == 0x1ff) |
{ |
unselect_card(); |
return 0; |
} |
} |
/* wait for card to get ready */ |
for(uint16_t i = 0; ; ++i) |
{ |
response = sd_raw_send_command_r1(CMD_SEND_OP_COND, 0); |
if(!(response & (1 << R1_IDLE_STATE))) |
break; |
if(i == 0x7fff) |
{ |
unselect_card(); |
return 0; |
} |
} |
/* set block size to 512 bytes */ |
if(sd_raw_send_command_r1(CMD_SET_BLOCKLEN, 512)) |
{ |
unselect_card(); |
return 0; |
} |
/* deaddress card */ |
unselect_card(); |
/* switch to highest SPI frequency possible */ |
SPCR &= ~((1 << SPR1) | (1 << SPR0)); /* Clock Frequency: f_OSC / 4 */ |
SPSR |= (1 << SPI2X); /* Doubled Clock Frequency: f_OSC / 2 */ |
#if !SD_RAW_SAVE_RAM |
/* the first block is likely to be accessed first, so precache it here */ |
raw_block_address = 0xffffffff; |
#if SD_RAW_WRITE_BUFFERING |
raw_block_written = 1; |
#endif |
if(!sd_raw_read(0, raw_block, sizeof(raw_block))) |
return 0; |
#endif |
return 1; |
} |
/** |
* \ingroup sd_raw |
* Checks wether a memory card is located in the slot. |
* |
* \returns 1 if the card is available, 0 if it is not. |
*/ |
uint8_t sd_raw_available() |
{ |
return get_pin_available() == 0x00; |
} |
/** |
* \ingroup sd_raw |
* Checks wether the memory card is locked for write access. |
* |
* \returns 1 if the card is locked, 0 if it is not. |
*/ |
uint8_t sd_raw_locked() |
{ |
return get_pin_locked() == 0x00; |
} |
/** |
* \ingroup sd_raw |
* Sends a raw byte to the memory card. |
* |
* \param[in] b The byte to sent. |
* \see sd_raw_rec_byte |
*/ |
void sd_raw_send_byte(uint8_t b) |
{ |
SPDR = b; |
/* wait for byte to be shifted out */ |
while(!(SPSR & (1 << SPIF))); |
SPSR &= ~(1 << SPIF); |
} |
/** |
* \ingroup sd_raw |
* Receives a raw byte from the memory card. |
* |
* \returns The byte which should be read. |
* \see sd_raw_send_byte |
*/ |
uint8_t sd_raw_rec_byte() |
{ |
/* send dummy data for receiving some */ |
SPDR = 0xff; |
while(!(SPSR & (1 << SPIF))); |
SPSR &= ~(1 << SPIF); |
return SPDR; |
} |
/** |
* \ingroup sd_raw |
* Send a command to the memory card which responses with a R1 response. |
* |
* \param[in] command The command to send. |
* \param[in] arg The argument for command. |
* \returns The command answer. |
*/ |
uint8_t sd_raw_send_command_r1(uint8_t command, uint32_t arg) |
{ |
uint8_t response; |
/* wait some clock cycles */ |
sd_raw_rec_byte(); |
/* send command via SPI */ |
sd_raw_send_byte(0x40 | command); |
sd_raw_send_byte((arg >> 24) & 0xff); |
sd_raw_send_byte((arg >> 16) & 0xff); |
sd_raw_send_byte((arg >> 8) & 0xff); |
sd_raw_send_byte((arg >> 0) & 0xff); |
sd_raw_send_byte(command == CMD_GO_IDLE_STATE ? 0x95 : 0xff); |
/* receive response */ |
for(uint8_t i = 0; i < 10; ++i) |
{ |
response = sd_raw_rec_byte(); |
if(response != 0xff) |
break; |
} |
return response; |
} |
/** |
* \ingroup sd_raw |
* Send a command to the memory card which responses with a R2 response. |
* |
* \param[in] command The command to send. |
* \param[in] arg The argument for command. |
* \returns The command answer. |
*/ |
uint16_t sd_raw_send_command_r2(uint8_t command, uint32_t arg) |
{ |
uint16_t response; |
/* wait some clock cycles */ |
sd_raw_rec_byte(); |
/* send command via SPI */ |
sd_raw_send_byte(0x40 | command); |
sd_raw_send_byte((arg >> 24) & 0xff); |
sd_raw_send_byte((arg >> 16) & 0xff); |
sd_raw_send_byte((arg >> 8) & 0xff); |
sd_raw_send_byte((arg >> 0) & 0xff); |
sd_raw_send_byte(command == CMD_GO_IDLE_STATE ? 0x95 : 0xff); |
/* receive response */ |
for(uint8_t i = 0; i < 10; ++i) |
{ |
response = sd_raw_rec_byte(); |
if(response != 0xff) |
break; |
} |
response <<= 8; |
response |= sd_raw_rec_byte(); |
return response; |
} |
/** |
* \ingroup sd_raw |
* Reads raw data from the card. |
* |
* \param[in] offset The offset from which to read. |
* \param[out] buffer The buffer into which to write the data. |
* \param[in] length The number of bytes to read. |
* \returns 0 on failure, 1 on success. |
* \see sd_raw_read_interval, sd_raw_write, sd_raw_write_interval |
*/ |
uint8_t sd_raw_read(uint32_t offset, uint8_t* buffer, uint16_t length) |
{ |
uint32_t block_address; |
uint16_t block_offset; |
uint16_t read_length; |
while(length > 0) |
{ |
/* determine byte count to read at once */ |
block_address = offset & 0xfffffe00; |
block_offset = offset & 0x01ff; |
read_length = 512 - block_offset; /* read up to block border */ |
if(read_length > length) |
read_length = length; |
#if !SD_RAW_SAVE_RAM |
/* check if the requested data is cached */ |
if(block_address != raw_block_address) |
#endif |
{ |
#if SD_RAW_WRITE_BUFFERING |
if(!raw_block_written) |
{ |
if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block))) |
return 0; |
} |
#endif |
/* address card */ |
select_card(); |
/* send single block request */ |
if(sd_raw_send_command_r1(CMD_READ_SINGLE_BLOCK, block_address)) |
{ |
unselect_card(); |
return 0; |
} |
/* wait for data block (start byte 0xfe) */ |
while(sd_raw_rec_byte() != 0xfe); |
#if SD_RAW_SAVE_RAM |
/* read byte block */ |
uint16_t read_to = block_offset + read_length; |
for(uint16_t i = 0; i < 512; ++i) |
{ |
uint8_t b = sd_raw_rec_byte(); |
if(i >= block_offset && i < read_to) |
*buffer++ = b; |
} |
#else |
/* read byte block */ |
uint8_t* cache = raw_block; |
for(uint16_t i = 0; i < 512; ++i) |
*cache++ = sd_raw_rec_byte(); |
raw_block_address = block_address; |
memcpy(buffer, raw_block + block_offset, read_length); |
buffer += read_length; |
#endif |
/* read crc16 */ |
sd_raw_rec_byte(); |
sd_raw_rec_byte(); |
/* deaddress card */ |
unselect_card(); |
/* let card some time to finish */ |
sd_raw_rec_byte(); |
} |
#if !SD_RAW_SAVE_RAM |
else |
{ |
/* use cached data */ |
memcpy(buffer, raw_block + block_offset, read_length); |
buffer += read_length; |
} |
#endif |
length -= read_length; |
offset += read_length; |
} |
return 1; |
} |
/** |
* \ingroup sd_raw |
* Continuously reads units of \c interval bytes and calls a callback function. |
* |
* This function starts reading at the specified offset. Every \c interval bytes, |
* it calls the callback function with the associated data buffer. |
* |
* By returning zero, the callback may stop reading. |
* |
* \note Within the callback function, you can not start another read or |
* write operation. |
* \note This function only works if the following conditions are met: |
* - (offset - (offset % 512)) % interval == 0 |
* - length % interval == 0 |
* |
* \param[in] offset Offset from which to start reading. |
* \param[in] buffer Pointer to a buffer which is at least interval bytes in size. |
* \param[in] interval Number of bytes to read before calling the callback function. |
* \param[in] length Number of bytes to read altogether. |
* \param[in] callback The function to call every interval bytes. |
* \param[in] p An opaque pointer directly passed to the callback function. |
* \returns 0 on failure, 1 on success |
* \see sd_raw_write_interval, sd_raw_read, sd_raw_write |
*/ |
uint8_t sd_raw_read_interval(uint32_t offset, uint8_t* buffer, uint16_t interval, uint16_t length, sd_raw_read_interval_handler_t callback, void* p) |
{ |
if(!buffer || interval == 0 || length < interval || !callback) |
return 0; |
#if !SD_RAW_SAVE_RAM |
while(length >= interval) |
{ |
/* as reading is now buffered, we directly |
* hand over the request to sd_raw_read() |
*/ |
if(!sd_raw_read(offset, buffer, interval)) |
return 0; |
if(!callback(buffer, offset, p)) |
break; |
offset += interval; |
length -= interval; |
} |
return 1; |
#else |
/* address card */ |
select_card(); |
uint16_t block_offset; |
uint16_t read_length; |
uint8_t* buffer_cur; |
uint8_t finished = 0; |
do |
{ |
/* determine byte count to read at once */ |
block_offset = offset & 0x01ff; |
read_length = 512 - block_offset; |
/* send single block request */ |
if(sd_raw_send_command_r1(CMD_READ_SINGLE_BLOCK, offset & 0xfffffe00)) |
{ |
unselect_card(); |
return 0; |
} |
/* wait for data block (start byte 0xfe) */ |
while(sd_raw_rec_byte() != 0xfe); |
/* read up to the data of interest */ |
for(uint16_t i = 0; i < block_offset; ++i) |
sd_raw_rec_byte(); |
/* read interval bytes of data and execute the callback */ |
do |
{ |
if(read_length < interval || length < interval) |
break; |
buffer_cur = buffer; |
for(uint16_t i = 0; i < interval; ++i) |
*buffer_cur++ = sd_raw_rec_byte(); |
if(!callback(buffer, offset + (512 - read_length), p)) |
{ |
finished = 1; |
break; |
} |
read_length -= interval; |
length -= interval; |
} while(read_length > 0 && length > 0); |
/* read rest of data block */ |
while(read_length-- > 0) |
sd_raw_rec_byte(); |
/* read crc16 */ |
sd_raw_rec_byte(); |
sd_raw_rec_byte(); |
if(length < interval) |
break; |
offset = (offset & 0xfffffe00) + 512; |
} while(!finished); |
/* deaddress card */ |
unselect_card(); |
/* let card some time to finish */ |
sd_raw_rec_byte(); |
return 1; |
#endif |
} |
/** |
* \ingroup sd_raw |
* Writes raw data to the card. |
* |
* \note If write buffering is enabled, you might have to |
* call sd_raw_sync() before disconnecting the card |
* to ensure all remaining data has been written. |
* |
* \param[in] offset The offset where to start writing. |
* \param[in] buffer The buffer containing the data to be written. |
* \param[in] length The number of bytes to write. |
* \returns 0 on failure, 1 on success. |
* \see sd_raw_write_interval, sd_raw_read, sd_raw_read_interval |
*/ |
uint8_t sd_raw_write(uint32_t offset, const uint8_t* buffer, uint16_t length) |
{ |
#if SD_RAW_WRITE_SUPPORT |
if(get_pin_locked()) |
return 0; |
uint32_t block_address; |
uint16_t block_offset; |
uint16_t write_length; |
while(length > 0) |
{ |
/* determine byte count to write at once */ |
block_address = offset & 0xfffffe00; |
block_offset = offset & 0x01ff; |
write_length = 512 - block_offset; /* write up to block border */ |
if(write_length > length) |
write_length = length; |
/* Merge the data to write with the content of the block. |
* Use the cached block if available. |
*/ |
if(block_address != raw_block_address) |
{ |
#if SD_RAW_WRITE_BUFFERING |
if(!raw_block_written) |
{ |
if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block))) |
return 0; |
} |
#endif |
if(block_offset || write_length < 512) |
{ |
if(!sd_raw_read(block_address, raw_block, sizeof(raw_block))) |
return 0; |
} |
raw_block_address = block_address; |
} |
if(buffer != raw_block) |
{ |
memcpy(raw_block + block_offset, buffer, write_length); |
#if SD_RAW_WRITE_BUFFERING |
raw_block_written = 0; |
if(length == write_length) |
return 1; |
#endif |
} |
buffer += write_length; |
/* address card */ |
select_card(); |
/* send single block request */ |
if(sd_raw_send_command_r1(CMD_WRITE_SINGLE_BLOCK, block_address)) |
{ |
unselect_card(); |
return 0; |
} |
/* send start byte */ |
sd_raw_send_byte(0xfe); |
/* write byte block */ |
uint8_t* cache = raw_block; |
for(uint16_t i = 0; i < 512; ++i) |
sd_raw_send_byte(*cache++); |
/* write dummy crc16 */ |
sd_raw_send_byte(0xff); |
sd_raw_send_byte(0xff); |
/* wait while card is busy */ |
while(sd_raw_rec_byte() != 0xff); |
sd_raw_rec_byte(); |
/* deaddress card */ |
unselect_card(); |
length -= write_length; |
offset += write_length; |
#if SD_RAW_WRITE_BUFFERING |
raw_block_written = 1; |
#endif |
} |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup sd_raw |
* Writes a continuous data stream obtained from a callback function. |
* |
* This function starts writing at the specified offset. To obtain the |
* next bytes to write, it calls the callback function. The callback fills the |
* provided data buffer and returns the number of bytes it has put into the buffer. |
* |
* By returning zero, the callback may stop writing. |
* |
* \param[in] offset Offset where to start writing. |
* \param[in] buffer Pointer to a buffer which is used for the callback function. |
* \param[in] length Number of bytes to write in total. May be zero for endless writes. |
* \param[in] callback The function used to obtain the bytes to write. |
* \param[in] p An opaque pointer directly passed to the callback function. |
* \returns 0 on failure, 1 on success |
* \see sd_raw_read_interval, sd_raw_write, sd_raw_read |
*/ |
uint8_t sd_raw_write_interval(uint32_t offset, uint8_t* buffer, uint16_t length, sd_raw_write_interval_handler_t callback, void* p) |
{ |
#if SD_RAW_WRITE_SUPPORT |
#if SD_RAW_SAVE_RAM |
#error "SD_RAW_WRITE_SUPPORT is not supported together with SD_RAW_SAVE_RAM" |
#endif |
if(!buffer || !callback) |
return 0; |
uint8_t endless = (length == 0); |
while(endless || length > 0) |
{ |
uint16_t bytes_to_write = callback(buffer, offset, p); |
if(!bytes_to_write) |
break; |
if(!endless && bytes_to_write > length) |
return 0; |
/* as writing is always buffered, we directly |
* hand over the request to sd_raw_write() |
*/ |
if(!sd_raw_write(offset, buffer, bytes_to_write)) |
return 0; |
offset += bytes_to_write; |
length -= bytes_to_write; |
} |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup sd_raw |
* Writes the write buffer's content to the card. |
* |
* \note When write buffering is enabled, you should |
* call this function before disconnecting the |
* card to ensure all remaining data has been |
* written. |
* |
* \returns 0 on failure, 1 on success. |
* \see sd_raw_write |
*/ |
uint8_t sd_raw_sync() |
{ |
#if SD_RAW_WRITE_SUPPORT |
#if SD_RAW_WRITE_BUFFERING |
if(raw_block_written) |
return 1; |
if(!sd_raw_write(raw_block_address, raw_block, sizeof(raw_block))) |
return 0; |
#endif |
return 1; |
#else |
return 0; |
#endif |
} |
/** |
* \ingroup sd_raw |
* Reads informational data from the card. |
* |
* This function reads and returns the card's registers |
* containing manufacturing and status information. |
* |
* \note: The information retrieved by this function is |
* not required in any way to operate on the card, |
* but it might be nice to display some of the data |
* to the user. |
* |
* \param[in] info A pointer to the structure into which to save the information. |
* \returns 0 on failure, 1 on success. |
*/ |
uint8_t sd_raw_get_info(struct sd_raw_info* info) |
{ |
if(!info || !sd_raw_available()) |
return 0; |
memset(info, 0, sizeof(*info)); |
select_card(); |
/* read cid register */ |
if(sd_raw_send_command_r1(CMD_SEND_CID, 0)) |
{ |
unselect_card(); |
return 0; |
} |
while(sd_raw_rec_byte() != 0xfe); |
for(uint8_t i = 0; i < 18; ++i) |
{ |
uint8_t b = sd_raw_rec_byte(); |
switch(i) |
{ |
case 0: |
info->manufacturer = b; |
break; |
case 1: |
case 2: |
info->oem[i - 1] = b; |
break; |
case 3: |
case 4: |
case 5: |
case 6: |
case 7: |
info->product[i - 3] = b; |
break; |
case 8: |
info->revision = b; |
break; |
case 9: |
case 10: |
case 11: |
case 12: |
info->serial |= (uint32_t) b << ((12 - i) * 8); |
break; |
case 13: |
info->manufacturing_year = b << 4; |
break; |
case 14: |
info->manufacturing_year |= b >> 4; |
info->manufacturing_month = b & 0x0f; |
break; |
} |
} |
/* read csd register */ |
uint8_t csd_read_bl_len = 0; |
uint8_t csd_c_size_mult = 0; |
uint16_t csd_c_size = 0; |
if(sd_raw_send_command_r1(CMD_SEND_CSD, 0)) |
{ |
unselect_card(); |
return 0; |
} |
while(sd_raw_rec_byte() != 0xfe); |
for(uint8_t i = 0; i < 18; ++i) |
{ |
uint8_t b = sd_raw_rec_byte(); |
switch(i) |
{ |
case 5: |
csd_read_bl_len = b & 0x0f; |
break; |
case 6: |
csd_c_size = (uint16_t) (b & 0x03) << 8; |
break; |
case 7: |
csd_c_size |= b; |
csd_c_size <<= 2; |
break; |
case 8: |
csd_c_size |= b >> 6; |
++csd_c_size; |
break; |
case 9: |
csd_c_size_mult = (b & 0x03) << 1; |
break; |
case 10: |
csd_c_size_mult |= b >> 7; |
info->capacity = (uint32_t) csd_c_size << (csd_c_size_mult + csd_read_bl_len + 2); |
break; |
case 14: |
if(b & 0x40) |
info->flag_copy = 1; |
if(b & 0x20) |
info->flag_write_protect = 1; |
if(b & 0x10) |
info->flag_write_protect_temp = 1; |
info->format = (b & 0x0c) >> 2; |
break; |
} |
} |
unselect_card(); |
return 1; |
} |
/Designs/Data_loggers/GPSRL02A/SW/logger/sd_raw.h |
---|
0,0 → 1,139 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* This file is free software; you can redistribute it and/or modify |
* it under the terms of either the GNU General Public License version 2 |
* or the GNU Lesser General Public License version 2.1, both as |
* published by the Free Software Foundation. |
*/ |
#ifndef SD_RAW_H |
#define SD_RAW_H |
#include <stdint.h> |
#include "sd_raw_config.h" |
/** |
* \addtogroup sd_raw |
* |
* @{ |
*/ |
/** |
* \file |
* MMC/SD raw access header (license: GPLv2 or LGPLv2.1) |
* |
* \author Roland Riegel |
*/ |
/** |
* The card's layout is harddisk-like, which means it contains |
* a master boot record with a partition table. |
*/ |
#define SD_RAW_FORMAT_HARDDISK 0 |
/** |
* The card contains a single filesystem and no partition table. |
*/ |
#define SD_RAW_FORMAT_SUPERFLOPPY 1 |
/** |
* The card's layout follows the Universal File Format. |
*/ |
#define SD_RAW_FORMAT_UNIVERSAL 2 |
/** |
* The card's layout is unknown. |
*/ |
#define SD_RAW_FORMAT_UNKNOWN 3 |
/** |
* This struct is used by sd_raw_get_info() to return |
* manufacturing and status information of the card. |
*/ |
struct sd_raw_info |
{ |
/** |
* A manufacturer code globally assigned by the SD card organization. |
*/ |
uint8_t manufacturer; |
/** |
* A string describing the card's OEM or content, globally assigned by the SD card organization. |
*/ |
uint8_t oem[3]; |
/** |
* A product name. |
*/ |
uint8_t product[6]; |
/** |
* The card's revision, coded in packed BCD. |
* |
* For example, the revision value \c 0x32 means "3.2". |
*/ |
uint8_t revision; |
/** |
* A serial number assigned by the manufacturer. |
*/ |
uint32_t serial; |
/** |
* The year of manufacturing. |
* |
* A value of zero means year 2000. |
*/ |
uint8_t manufacturing_year; |
/** |
* The month of manufacturing. |
*/ |
uint8_t manufacturing_month; |
/** |
* The card's total capacity in bytes. |
*/ |
uint32_t capacity; |
/** |
* Defines wether the card's content is original or copied. |
* |
* A value of \c 0 means original, \c 1 means copied. |
*/ |
uint8_t flag_copy; |
/** |
* Defines wether the card's content is write-protected. |
* |
* \note This is an internal flag and does not represent the |
* state of the card's mechanical write-protect switch. |
*/ |
uint8_t flag_write_protect; |
/** |
* Defines wether the card's content is temporarily write-protected. |
* |
* \note This is an internal flag and does not represent the |
* state of the card's mechanical write-protect switch. |
*/ |
uint8_t flag_write_protect_temp; |
/** |
* The card's data layout. |
* |
* See the \c SD_RAW_FORMAT_* constants for details. |
* |
* \note This value is not guaranteed to match reality. |
*/ |
uint8_t format; |
}; |
typedef uint8_t (*sd_raw_read_interval_handler_t)(uint8_t* buffer, uint32_t offset, void* p); |
typedef uint16_t (*sd_raw_write_interval_handler_t)(uint8_t* buffer, uint32_t offset, void* p); |
uint8_t sd_raw_init(); |
uint8_t sd_raw_available(); |
uint8_t sd_raw_locked(); |
uint8_t sd_raw_read(uint32_t offset, uint8_t* buffer, uint16_t length); |
uint8_t sd_raw_read_interval(uint32_t offset, uint8_t* buffer, uint16_t interval, uint16_t length, sd_raw_read_interval_handler_t callback, void* p); |
uint8_t sd_raw_write(uint32_t offset, const uint8_t* buffer, uint16_t length); |
uint8_t sd_raw_write_interval(uint32_t offset, uint8_t* buffer, uint16_t length, sd_raw_write_interval_handler_t callback, void* p); |
uint8_t sd_raw_sync(); |
uint8_t sd_raw_get_info(struct sd_raw_info* info); |
/** |
* @} |
*/ |
#endif |
/Designs/Data_loggers/GPSRL02A/SW/logger/sd_raw_config.h |
---|
0,0 → 1,109 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* This file is free software; you can redistribute it and/or modify |
* it under the terms of either the GNU General Public License version 2 |
* or the GNU Lesser General Public License version 2.1, both as |
* published by the Free Software Foundation. |
*/ |
#ifndef SD_RAW_CONFIG_H |
#define SD_RAW_CONFIG_H |
/** |
* \addtogroup sd_raw |
* |
* @{ |
*/ |
/** |
* \file |
* MMC/SD support configuration (license: GPLv2 or LGPLv2.1) |
*/ |
/** |
* \ingroup sd_raw_config |
* Controls MMC/SD write support. |
* |
* Set to 1 to enable MMC/SD write support, set to 0 to disable it. |
*/ |
#define SD_RAW_WRITE_SUPPORT 1 |
/** |
* \ingroup sd_raw_config |
* Controls MMC/SD write buffering. |
* |
* Set to 1 to buffer write accesses, set to 0 to disable it. |
* |
* \note This option has no effect when SD_RAW_WRITE_SUPPORT is 0. |
*/ |
#define SD_RAW_WRITE_BUFFERING 0 |
/** |
* \ingroup sd_raw_config |
* Controls MMC/SD access buffering. |
* |
* Set to 1 to save static RAM, but be aware that you will |
* lose performance. |
* |
* \note When SD_RAW_WRITE_SUPPORT is 1, SD_RAW_SAVE_RAM will |
* be reset to 0. |
*/ |
#define SD_RAW_SAVE_RAM 1 |
/* defines for customisation of sd/mmc port access */ |
#if defined(__AVR_ATmega8__) || \ |
defined(__AVR_ATmega48__) || \ |
defined(__AVR_ATmega88__) || \ |
defined(__AVR_ATmega168__) |
#define configure_pin_mosi() DDRB |= (1 << DDB3) |
#define configure_pin_sck() DDRB |= (1 << DDB5) |
#define configure_pin_ss() DDRB |= (1 << DDB2) |
#define configure_pin_miso() DDRB &= ~(1 << DDB4) |
#define select_card() PORTB &= ~(1 << PB2) |
#define unselect_card() PORTB |= (1 << PB2) |
#elif defined(__AVR_ATmega16__) || \ |
defined(__AVR_ATmega32__) |
#define configure_pin_mosi() DDRB |= (1 << DDB5) |
#define configure_pin_sck() DDRB |= (1 << DDB7) |
#define configure_pin_ss() DDRB |= (1 << DDB4) |
#define configure_pin_miso() DDRB &= ~(1 << DDB6) |
#define select_card() PORTB &= ~(1 << PB4) |
#define unselect_card() PORTB |= (1 << PB4) |
#elif defined(__AVR_ATmega64__) || \ |
defined(__AVR_ATmega128__) || \ |
defined(__AVR_ATmega169__) |
#define configure_pin_mosi() DDRB |= (1 << DDB2) |
#define configure_pin_sck() DDRB |= (1 << DDB1) |
#define configure_pin_ss() DDRB |= (1 << DDB0) |
#define configure_pin_miso() DDRB &= ~(1 << DDB3) |
#define select_card() PORTB &= ~(1 << PB0) |
#define unselect_card() PORTB |= (1 << PB0) |
#else |
#error "no sd/mmc pin mapping available!" |
#endif |
#define configure_pin_available() DDRC &= ~(1 << DDC4) |
#define configure_pin_locked() DDRC &= ~(1 << DDC5) |
#define get_pin_available() ((PINC >> PC4) & 0x01) |
#define get_pin_locked() ((PINC >> PC5) & 0x01) |
/** |
* @} |
*/ |
/* configuration checks */ |
#if SD_RAW_WRITE_SUPPORT |
#undef SD_RAW_SAVE_RAM |
#define SD_RAW_SAVE_RAM 0 |
#else |
#undef SD_RAW_WRITE_BUFFERING |
#define SD_RAW_WRITE_BUFFERING 0 |
#endif |
#endif |
/Designs/Data_loggers/GPSRL02A/SW/logger/uart.c |
---|
0,0 → 1,198 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* This file is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License version 2 as |
* published by the Free Software Foundation. |
*/ |
#include <stdio.h> |
#include <avr/interrupt.h> |
#include <avr/io.h> |
#include <avr/pgmspace.h> |
#include <avr/sfr_defs.h> |
#include <avr/sleep.h> |
#include "uart.h" |
/* some mcus have multiple uarts */ |
#ifdef UDR0 |
#define UBRRH UBRR0H |
#define UBRRL UBRR0L |
#define UDR UDR0 |
#define UCSRA UCSR0A |
#define UDRE UDRE0 |
#define RXC RXC0 |
#define UCSRB UCSR0B |
#define RXEN RXEN0 |
#define TXEN TXEN0 |
#define RXCIE RXCIE0 |
#define UCSRC UCSR0C |
#define URSEL |
#define UCSZ0 UCSZ00 |
#define UCSZ1 UCSZ01 |
#define UCSRC_SELECT 0 |
#else |
#define UCSRC_SELECT (1 << URSEL) |
#endif |
#ifndef USART_RXC_vect |
#if defined(UART0_RX_vect) |
#define USART_RXC_vect UART0_RX_vect |
#elif defined(UART_RX_vect) |
#define USART_RXC_vect UART_RX_vect |
#elif defined(USART0_RX_vect) |
#define USART_RXC_vect USART0_RX_vect |
#elif defined(USART_RX_vect) |
#define USART_RXC_vect USART_RX_vect |
#elif defined(USART0_RXC_vect) |
#define USART_RXC_vect USART0_RXC_vect |
#elif defined(USART_RXC_vect) |
#define USART_RXC_vect USART_RXC_vect |
#else |
#error "Uart receive complete interrupt not defined!" |
#endif |
#endif |
#define BAUD 9600UL |
#define UBRRVAL (F_CPU/(BAUD*16)-1) |
#define USE_SLEEP 1 |
void uart_init() |
{ |
/* set baud rate */ |
UBRRH = UBRRVAL >> 8; |
UBRRL = UBRRVAL & 0xff; |
/* set frame format: 8 bit, no parity, 1 bit */ |
UCSRC = UCSRC_SELECT | (1 << UCSZ1) | (1 << UCSZ0); |
/* enable serial receiver and transmitter */ |
#if !USE_SLEEP |
UCSRB = (1 << RXEN) | (1 << TXEN); |
#else |
UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE); |
#endif |
} |
void uart_putc(uint8_t c) |
{ |
if(c == '\n') |
uart_putc('\r'); |
/* wait until transmit buffer is empty */ |
while(!(UCSRA & (1 << UDRE))); |
/* send next byte */ |
UDR = c; |
} |
void uart_putc_hex(uint8_t b) |
{ |
/* upper nibble */ |
if((b >> 4) < 0x0a) |
uart_putc((b >> 4) + '0'); |
else |
uart_putc((b >> 4) - 0x0a + 'a'); |
/* lower nibble */ |
if((b & 0x0f) < 0x0a) |
uart_putc((b & 0x0f) + '0'); |
else |
uart_putc((b & 0x0f) - 0x0a + 'a'); |
} |
void uart_putw_hex(uint16_t w) |
{ |
uart_putc_hex((uint8_t) (w >> 8)); |
uart_putc_hex((uint8_t) (w & 0xff)); |
} |
void uart_putdw_hex(uint32_t dw) |
{ |
uart_putw_hex((uint16_t) (dw >> 16)); |
uart_putw_hex((uint16_t) (dw & 0xffff)); |
} |
void uart_putw_dec(uint16_t w) |
{ |
uint16_t num = 10000; |
uint8_t started = 0; |
while(num > 0) |
{ |
uint8_t b = w / num; |
if(b > 0 || started || num == 1) |
{ |
uart_putc('0' + b); |
started = 1; |
} |
w -= b * num; |
num /= 10; |
} |
} |
void uart_putdw_dec(uint32_t dw) |
{ |
uint32_t num = 1000000000; |
uint8_t started = 0; |
while(num > 0) |
{ |
uint8_t b = dw / num; |
if(b > 0 || started || num == 1) |
{ |
uart_putc('0' + b); |
started = 1; |
} |
dw -= b * num; |
num /= 10; |
} |
} |
void uart_puts(const char* str) |
{ |
while(*str) |
uart_putc(*str++); |
} |
void uart_puts_p(PGM_P str) |
{ |
while(1) |
{ |
uint8_t b = pgm_read_byte_near(str++); |
if(!b) |
break; |
uart_putc(b); |
} |
} |
uint8_t uart_getc() |
{ |
/* wait until receive buffer is full */ |
#if USE_SLEEP |
uint8_t sreg = SREG; |
sei(); |
while(!(UCSRA & (1 << RXC))) |
sleep_mode(); |
SREG = sreg; |
#else |
while(!(UCSRA & (1 << RXC))); |
#endif |
uint8_t b = UDR; |
if(b == '\r') |
b = '\n'; |
return b; |
} |
EMPTY_INTERRUPT(USART_RXC_vect) |
/Designs/Data_loggers/GPSRL02A/SW/logger/uart.h |
---|
0,0 → 1,33 |
/* |
* Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> |
* |
* This file is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License version 2 as |
* published by the Free Software Foundation. |
*/ |
#ifndef UART_H |
#define UART_H |
#include <stdint.h> |
#include <avr/pgmspace.h> |
void uart_init(); |
void uart_putc(uint8_t c); |
void uart_putc_hex(uint8_t b); |
void uart_putw_hex(uint16_t w); |
void uart_putdw_hex(uint32_t dw); |
void uart_putw_dec(uint16_t w); |
void uart_putdw_dec(uint32_t dw); |
void uart_puts(const char* str); |
void uart_puts_p(PGM_P str); |
uint8_t uart_getc(); |
#endif |